Subscription Manager is a web application I built for managing recurring subscriptions for digital services and tracking their costs.
It began as a fairly straightforward .NET application.
Over time it grew to include a Blazor web application, an API, persistence, authentication, tests, cloud infrastructure and a few external integrations.
When I started thinking about another application, some of those pieces looked useful enough to reuse.
Starting from a copy of the whole project would have been easy. But it would also have brought along a lot of things that belonged specifically to Subscription Manager.
That became one of the reasons I started working on Launchpad.
Starting with something that had already been used
By that point, Subscription Manager had gone through several iterations.
I had a working Web-to-API boundary, authentication, account management, tests and a Blazor application talking to the API over HTTP.
None of that meant it was the right structure for every .NET application. It simply meant I had already used it in a real project and knew how it behaved.
That made it a useful starting point.
Launchpad began by reusing some of those pieces while leaving out the parts that only made sense for Subscription Manager.
Identity was a good example.
In Subscription Manager it had gradually picked up product-specific responsibilities: user preferences, email confirmation, password reset, subscription plans and other account settings.
The first Launchpad version needed much less.
I kept the general approach, but not all of the functionality that had accumulated around it.
The same was true elsewhere.
| Reused as a starting point | Kept in Subscription Manager |
|---|---|
| Web communicating with an API | Subscription domain |
| ASP.NET Core Identity | Digital service catalog |
| Current-user handling | Stripe integration |
| Account lifecycle | Exchange-rate integration |
| Testing conventions | Savings-plan functionality |
| Blazor interaction model | Product-specific screens |
The goal was not to find everything the projects could share.
It was mostly to avoid carrying things over just because they already existed.
Not every layer had to come with it
One small example is the Domain project.
Subscription Manager has one because it has actual domain behaviour around subscriptions and digital services.
The reusable Launchpad Template currently does not.
I could have added an empty Domain project to make the structure look more familiar, but there was nothing useful to put there.
So I left it out.
A generated application can add one when its domain needs one. Launchpad can also gain shared domain code later if a real use case appears.
For now, I did not have a concrete use for that layer.
The generator came later
I was also hesitant to build a generator too early.
At the beginning, I still did not know which parts of the foundation would remain stable. At that point I would have been adding configuration for cases I had not encountered yet.
So the earlier plan was simpler: keep working with the foundation, use it in concrete projects and learn what was actually repeating.
That plan changed as Launchpad became more concrete.
The repository eventually developed a clear split:
Launchpad
├── Template
│ └── reusable product foundation
│
└── Generator
└── tooling used to create a product
That made the boundary easier to reason about.
The Template is the part that can become a new application.
The Generator is tooling around that process and stays in Launchpad.
Once that distinction was clear, generation no longer had to solve a very general problem. It could work with a structure that Launchpad already knew.
Keeping predictable work predictable
Launchpad is also where I experiment with AI-assisted engineering.
That made repository generation an interesting case.
There are parts of creating a new product that do not need interpretation. Renaming projects, changing namespaces, updating known identifiers, rebuilding the solution and running tests all have a fairly clear expected result.
I preferred to keep those steps deterministic.
The current flow is roughly:
Product definition
↓
Copy Template
↓
Transform
↓
Validate
↓
Package
↓
Publish
Those steps are ordinary .NET code.
AI can still be useful later, when the work becomes less predictable: product-specific behaviour, UI decisions or changes where there is something to interpret rather than simply transform.
I find that separation useful in this project. It also makes failures in the generation pipeline much less mysterious.
Still an experiment
Launchpad is not a finished framework for every .NET application.
The Template contains things that have been useful so far. The Generator can prepare, transform, validate, package and publish a product based on it.
The next useful test is using the foundation again and seeing what survives.
Some parts may turn out to be genuinely reusable. Others may move back into individual products. Something that looks useful today may disappear entirely.
Subscription Manager gave me a concrete application to start from. Launchpad gives me a place to test which parts of that experience are actually worth carrying forward.
For me, that has been more useful than trying to design a reusable foundation before having something real to reuse.