[{"data":1,"prerenderedAt":331},["ShallowReactive",2],{"projects-list":3},[4,137,247],{"id":5,"title":6,"author":7,"body":8,"coverText":109,"date":110,"description":111,"excerpt":112,"extension":113,"image":114,"meta":115,"navigation":116,"path":117,"projectLink":118,"readingTime":119,"seo":120,"stack":121,"status":128,"stem":129,"tags":130,"__hash__":136},"content\u002Fprojects\u002Fboneappetite.md","Boneappetitedk — Building a Subscription eCommerce Webshop from Scratch","Sandip Choudhary",{"type":9,"value":10,"toc":100},"minimark",[11,16,20,23,39,42,46,49,52,56,65,68,72,75,78,87,91,94,97],[12,13,15],"h2",{"id":14},"how-it-started","How it started",[17,18,19],"p",{},"When I first got this project I honestly didn't know much about calculating calorie needs for dogs. That was a whole new domain for me. The client was a Copenhagen-based dog-food company that needed a webshop, but not a typical one — they wanted a subscription model where customers could get recurring deliveries based on their dog's specific dietary needs.",[17,21,22],{},"My first instinct was Shopify. I'd used it before and it's the obvious choice for eCommerce. But it quickly became clear it wasn't going to work here. The cost was too high for what the project needed, and getting the level of customisation required — especially for a calorie calculator and a proper subscription flow — meant relying on plugins that either didn't exist or didn't do quite what I needed. Every workaround felt fragile.",[17,24,25,26,33,34,38],{},"I then looked at ",[27,28,32],"a",{"href":29,"rel":30},"https:\u002F\u002Fmedusajs.com\u002F",[31],"nofollow","MedusaJS",", which is an open-source headless commerce platform. It was promising but the version available at the time was ",[35,36,37],"code",{},"1.x.x"," and the documentation for subscriptions was really lacking. I couldn't find a clear path forward with it.",[17,40,41],{},"So I decided to just build it myself from scratch.",[12,43,45],{"id":44},"the-stack","The stack",[17,47,48],{},"I went with .NET Core for the backend, Vue.js for the frontend, PostgreSQL as the database, and Stripe for payments. I had used Stripe in a previous project so I was already comfortable with how it works, which made the payment side of things much less daunting.",[17,50,51],{},"The main reason I kept the frontend and backend completely separate was to make the project easier to maintain and scale over time. If the client ever wants to redesign the storefront later, none of the business logic needs to change. It also means the backend could serve a mobile app or an admin panel down the road without any restructuring.",[12,53,55],{"id":54},"subscriptions-and-billing","Subscriptions and billing",[17,57,58,59,64],{},"This was the part I had to learn the most for. I'd built webshops before with WooCommerce and Shopify where it's basically just products and a checkout — subscriptions are a completely different beast. I spent a good amount of time reading through ",[27,60,63],{"href":61,"rel":62},"https:\u002F\u002Fwww.chargebee.com\u002Fsubscription-management\u002F",[31],"Chargebee's subscription management docs"," and Stripe's own documentation to properly understand the model before writing a single line of code.",[17,66,67],{},"Once I had a solid understanding, Stripe's subscription API turned out to be really well thought out. It handles the recurring billing cycles, plan changes, failed payments, and invoicing in a way that integrated cleanly with the .NET Core backend. I'm glad I chose it over trying to roll my own billing logic.",[12,69,71],{"id":70},"the-colour-change-problem","The colour change problem",[17,73,74],{},"At one point during the project the client was going back and forth a lot on the colour scheme. I had components built, but manually updating button colours, backgrounds, and accents across all of them was slow and honestly a bit annoying.",[17,76,77],{},"Around that time PrimeVue 4.0 Beta came out, which introduced design tokens — basically a single place where you define your colours and the entire UI picks them up. I decided to migrate the project to PrimeVue 4.0, which took less than half an hour since I already had all the components in place.",[17,79,80,81,86],{},"After that, responding to a colour change request from the client went from an hour of hunting through files to just updating a couple of token values. It was one of those decisions that felt slightly risky at the time (migrating to a beta version mid-project) but paid off immediately. I wrote a bit more about it in the ",[27,82,85],{"href":83,"rel":84},"https:\u002F\u002Fprimevue.org\u002Ftheming\u002Fstyled\u002F",[31],"PrimeVue Styled Mode docs"," if you want to dig into how the token system works.",[12,88,90],{"id":89},"what-i-took-away","What I took away",[17,92,93],{},"This project pushed me into areas I hadn't worked in before — subscription billing, domain-specific calculators, and building a full custom eCommerce solution without leaning on an existing platform. It was one of the more challenging projects I've done, but also one of the most satisfying to ship.",[17,95,96],{},"The biggest lesson for me was around making smart architectural choices early. Decoupling the frontend and backend, and later adopting design tokens, both felt like small decisions at the time but made a real difference as the project grew and the client's requirements kept evolving.",[17,98,99],{},"And that's a wrap for this one. Hope you enjoyed the read 💖",{"title":101,"searchDepth":102,"depth":102,"links":103},"",2,[104,105,106,107,108],{"id":14,"depth":102,"text":15},{"id":44,"depth":102,"text":45},{"id":54,"depth":102,"text":55},{"id":70,"depth":102,"text":71},{"id":89,"depth":102,"text":90},"My recent project Boneappetitedk 💖","2025-07-01","How I designed and built a Copenhagen dog-food subscription webshop from the ground up using .NET Core, Vue.js, PostgreSQL, and Stripe — without relying on Shopify or any off-the-shelf platform.",null,"md","\u002Fimg\u002FBoneappetiteBannerWide.png",{},true,"\u002Fprojects\u002Fboneappetite","https:\u002F\u002Fboneappetitedk.com\u002F",4,{"title":6,"description":111},[122,123,124,125,126,127],".NET Core","Vue.js","PostgreSQL","Stripe","PrimeVue","Figma","Completed","projects\u002Fboneappetite",[131,132,133,134,135],"eCommerce","Webshop","Web App","Subscription","Full-Stack","94NxNdT5G7tilkSgbnErqf924cPXf5OmQvmrcr7_hbw",{"id":138,"title":139,"author":7,"body":140,"coverText":229,"date":230,"description":231,"excerpt":112,"extension":113,"image":232,"meta":233,"navigation":116,"path":234,"projectLink":235,"readingTime":119,"seo":236,"stack":237,"status":128,"stem":241,"tags":242,"__hash__":246},"content\u002Fprojects\u002Fbattery-notifier.md","Battery Notifier — An Open-Source Windows Desktop App for Battery Management",{"type":9,"value":141,"toc":222},[142,144,147,150,153,157,160,167,171,174,183,186,189,193,196,199,203,212,215],[12,143,15],{"id":14},[17,145,146],{},"It was just a normal working day. I was deep into one of my projects when my laptop suddenly shut off — no warning, no low-battery popup, nothing. Just a black screen.",[17,148,149],{},"My laptop was from 2017 and the battery had degraded quite a bit by then. Windows usually sends a notification when you're below 20%, but because of the degradation my machine would die well before reaching that point — sometimes at 50% or more. The default system alert was basically useless for me.",[17,151,152],{},"That's when I thought — why not just build something myself? A small app that sits in the background and notifies me exactly when I want to be notified, not when Windows decides to.",[12,154,156],{"id":155},"why-winforms","Why WinForms",[17,158,159],{},"I was already familiar with C# and .NET from my day job where I'd built a POS desktop application, so going with WinForms felt natural. I know some people raise an eyebrow at WinForms being \"old\", but honestly for a lightweight system-tray utility it's more than capable. Most enterprise desktop software still runs on it, and it gave me direct access to the Windows APIs I needed without any extra overhead.",[17,161,162,163,166],{},"The goal was simple — a small ",[35,164,165],{},".exe"," that runs on startup, lives in the system tray, and doesn't get in your way.",[12,168,170],{"id":169},"building-it","Building it",[17,172,173],{},"The core of the app is straightforward. It polls your battery status on a set interval and fires a native Windows toast notification when the charge crosses a threshold you've defined. You can set a high limit (so you know when to unplug) and a low limit (so you know when to plug in before it's too late).",[17,175,176,177,182],{},"One thing I had to think about was preventing multiple instances of the app running at the same time, which would cause duplicate notifications spamming you. I solved this using a ",[27,178,181],{"href":179,"rel":180},"https:\u002F\u002Fwww.autoitconsulting.com\u002Fsite\u002Fdevelopment\u002Fsingle-instance-winform-app-csharp-mutex-named-pipes\u002F",[31],"named Mutex",". A Mutex is normally used in multithreading to control access to a shared resource — here I used it at the process level so that if the app is already running, any second launch just exits immediately.",[17,184,185],{},"After getting the core working, I wanted to distribute it properly. So I learned how to create an installer that handles the setup wizard, registers the app to run on startup, and also supports automatic updates. That last part was genuinely fun to figure out.",[17,187,188],{},"I also spent some time on the design side — created custom tray icons and kept the settings UI minimal and clean. It was a good chance to flex a bit beyond just writing code.",[12,190,192],{"id":191},"what-i-learned","What I learned",[17,194,195],{},"This was my first open-source release on GitHub, which felt like a big deal at the time. Beyond the code itself, I got a real feel for the full lifecycle of a desktop app — from the initial idea, through building and testing, all the way to packaging, distributing, and maintaining a public release.",[17,197,198],{},"The Mutex bit was also a nice detour into concurrency concepts. It's one of those things you learn in theory but it's satisfying to find a real practical use for it.",[12,200,202],{"id":201},"whats-next","What's next",[17,204,205,206,211],{},"The app works well and still solves my original problem. Down the line I'd like to rebuild it using ",[27,207,210],{"href":208,"rel":209},"https:\u002F\u002Favaloniaui.net\u002F",[31],"Avalonia UI"," — a modern cross-platform framework for .NET — so it could run on macOS and Linux too, not just Windows.",[213,214],"hr",{},[17,216,217],{},[218,219],"img",{"alt":220,"src":221},"Battery Notifier Features","https:\u002F\u002Fgithub.com\u002FSandip124\u002FBatteryNotifier\u002Fraw\u002Fmaster\u002FBatteryNotifierBanner.png",{"title":101,"searchDepth":102,"depth":102,"links":223},[224,225,226,227,228],{"id":14,"depth":102,"text":15},{"id":155,"depth":102,"text":156},{"id":169,"depth":102,"text":170},{"id":191,"depth":102,"text":192},{"id":201,"depth":102,"text":202},"my first opensource desktop app 🖥️","2024-07-01","A lightweight, open-source Windows desktop application that monitors your battery charging status and sends native notifications when your battery is full or critically low — built with C# and WinForms.","\u002Fimg\u002FBatteryNotifierBannerWide.png",{},"\u002Fprojects\u002Fbattery-notifier","https:\u002F\u002Fgithub.com\u002FSandip124\u002FBatteryNotifier\u002F",{"title":139,"description":231},[238,239,240],"C#","WinForms",".NET Framework","projects\u002Fbattery-notifier",[243,244,245,238,239],"Desktop","Windows","Open Source","26qmHiy8v89jGVSV_J_euH3Nn49EaNtMXVvyFzUkQT4",{"id":248,"title":249,"author":7,"body":250,"coverText":314,"date":315,"description":316,"excerpt":112,"extension":113,"image":317,"meta":318,"navigation":116,"path":319,"projectLink":320,"readingTime":119,"seo":321,"stack":322,"status":325,"stem":326,"tags":327,"__hash__":330},"content\u002Fprojects\u002Fexpense-tracker.md","Expense Tracker — A Multi-Workspace Finance Manager Built with .NET Core",{"type":9,"value":251,"toc":307},[252,254,257,260,263,265,268,271,275,278,281,284,288,291,294,298,301,304],[12,253,15],{"id":14},[17,255,256],{},"This one actually goes back to my college days. I built an early version of it as a project back then — nothing fancy, just a basic way to log transactions. But the idea always stuck with me and I kept thinking about what it could be if I actually built it properly.",[17,258,259],{},"The core problem I wanted to solve was pretty simple. Most finance apps treat everything as one big flat list. That's fine if you only have one thing to track, but as soon as you want to separate your personal spending from shared expenses, or keep a side project's budget completely isolated, it falls apart. I wanted something where each context had its own space — its own transactions, categories, and balance — without bleeding into each other.",[17,261,262],{},"That's where the idea of workspaces came from.",[12,264,45],{"id":44},[17,266,267],{},"I went with .NET Core for the backend since I'm most comfortable with it and it's great for building structured REST APIs. PostgreSQL handles the data — it's open-source, reliable, and well suited for the kind of relational data a finance app deals with. The frontend at the moment is plain JavaScript and CSS, just enough to get the prototype working and usable.",[17,269,270],{},"The backend is built as an API from the start, so the frontend is fully decoupled. That was a deliberate call — when I eventually rebuild the UI properly (planning to use Vue.js), none of the backend logic needs to change.",[12,272,274],{"id":273},"what-it-does","What it does",[17,276,277],{},"The main feature is workspaces. You can create as many as you want — one for personal finances, one for shared household costs, one for a side project — and each one is completely separate. Transactions, categories, and balances in one workspace have no idea the others exist.",[17,279,280],{},"Within each workspace you can log income and expense entries, assign them to categories you define yourself, and mark things as recurring for bills or subscriptions that repeat every month. The summary view gives you a quick picture of where you stand — total in, total out, and a breakdown by category so you can see where your money is actually going.",[17,282,283],{},"User accounts are scoped so your data stays private to you. Each workspace belongs to the user who created it.",[12,285,287],{"id":286},"where-its-at","Where it's at",[17,289,290],{},"Right now it's a working prototype. The core flows — creating workspaces, logging transactions, viewing summaries — are all functional. What's still missing is data visualisation (charts and spending trends over time), budget limits with alerts, and a proper export option for reports. The UI also needs a full pass before I'd consider it production-ready.",[17,292,293],{},"It's one of those projects I keep coming back to when I have time. The plan is to eventually migrate the frontend to Vue.js, add charts, and publish a Docker image so anyone can self-host it easily.",[12,295,297],{"id":296},"what-im-learning-from-it","What I'm learning from it",[17,299,300],{},"More than anything this project has been a good exercise in building something long-term. It's easy to keep a project clean when you're sprinting to ship it. It's a lot harder when you're returning to it in small sessions over months. So it's been a useful lesson in writing code that's readable and maintainable enough that future-me isn't completely lost when picking it back up.",[17,302,303],{},"The multi-tenant data model was also an interesting design challenge — making sure every query is properly scoped to a workspace so there's no chance of data leaking across them. Small detail but it matters a lot in a finance app.",[17,305,306],{},"Hopefully I'll have a proper v1 to show off soon. 🤘",{"title":101,"searchDepth":102,"depth":102,"links":308},[309,310,311,312,313],{"id":14,"depth":102,"text":15},{"id":44,"depth":102,"text":45},{"id":273,"depth":102,"text":274},{"id":286,"depth":102,"text":287},{"id":296,"depth":102,"text":297},"My ambition project Expense Tracker 🤘","2023-11-04","A .NET Core web application for managing personal and group finances. Supports multiple workspaces so each person can track their own incoming and outgoing transactions separately — built as an open-source side project.","\u002Fimg\u002FExpenseTrackerBannerWide.png",{},"\u002Fprojects\u002Fexpense-tracker","#",{"title":249,"description":316},[122,238,124,323,324],"JavaScript","CSS","Prototype","projects\u002Fexpense-tracker",[133,328,245,135,329],"Finance","Personal Project","Nn_jsosi3XJTXkZyIVOLdcHEm8z4I50ZhvhDoEJhTdw",1780509390895]