Context
Pocket Family runs today on my home stack, used by my family and reachable over Tailscale. I built it solo over about five months, from January to June 2026, directing Claude Code as my coding agent rather than writing every line by hand.
The constraints were self-imposed. It had to run on the AWS free tier since this was a hobby project with no budget, and it had to work both ways: self-hosted for daily family use, and deployable to AWS to prototype the cloud architecture. I also used the project to test my T-shaped range. My depth is in Python and integration systems, REST APIs, data pipelines, so the goal was to prove I could go wide too and direct a coding agent to build the multi-tenant SaaS patterns, the React frontend, and the AWS infrastructure well, not just the area I already knew.
My Role
I acted as the architect and conductor for the whole project. I owned the architecture, the data model, and every plan before code got written, and reviewed every PR that came out of it. Claude Code did the actual legwork of implementation.
One constraint shaped that workflow more than anything else: I ran the whole project on a Claude Pro subscription, not Max or API credits. That forced me to be deliberate about every prompt and every model choice, since I couldn’t just burn through context and retry. It taught me more about using AI efficiently and managing context than any course or guide would have.
I’d tried both ChatGPT and Claude before settling into this workflow, and the biggest lesson was where to spend my review effort. Skimming code line by line didn’t matter much, the agents were genuinely strong at things like JWT patterns and general application code. What couldn’t be skipped was reviewing the plan itself, since a wrong assumption there would compound across dozens of files. I also learned where agents got stuck in loops, most reliably around devcontainer setup and Docker volumes, and learned to step in early rather than let them retry the same fix five times.
The clearest example of steering the agent was testing. Left alone, Claude wanted to test everything, down to Pydantic’s own validation behavior, and would produce something like 100 tests for a single feature. That volume made the suite impossible to actually trust, I couldn’t tell if it covered what mattered or just padded the count. I redirected it to test business outcomes and the intent of the code instead, and to present tests clearly enough that I could review and trust them at a glance.
Dragan’s agentic-qe.dev framework deserves a specific mention here. It enforces that same test-intent discipline I was trying to get to by hand, and it’s a big part of why the test suite ended up trustworthy rather than just large.
Architecture
The app is built as a containerized monolith, not microservices. As a solo developer who’s also the only real user, the operational overhead of true microservices didn’t make sense here. Instead there are five containers (frontend, backend, a single central Postgres database, Redis, and a background worker for CSV imports), split cleanly enough that any of them could become a real separate service later if the app ever needed it. Frontend/backend separation is standard, and giving the background worker its own container was mostly about being able to update and redeploy it independently. The result is fast iteration, easy debugging, and a deploy story simple enough for an app I actually run and use myself.
The part I’m proudest of is the AWS architecture, specifically the decisions Claude couldn’t make for me. Claude is genuinely good at generating Terraform or CloudFormation once you tell it what to build, that part’s well known. What takes actual judgment is choosing what to build, EC2 vs. Fargate, RDS vs. Aurora Serverless, and that depends on the specific project. For a demo instance that gets infrequent traffic, I picked Aurora Serverless v2 and ECS Fargate because both scale down when idle, so a low-traffic demo isn’t paying for compute sitting around unused. An Application Load Balancer sits in front of everything, partly for routing, but mostly because it’s a managed service: HTTPS, security, and scaling all come as part of the AWS package instead of me building them by hand.

Alternatives & Tradeoffs
The alternative I weighed most seriously was schema-per-tenant instead of a shared schema with tenant_id filtering. Performance wasn’t the deciding factor, at the scale I’m running (many small tenants, each family with a modest amount of data) the two options behave about the same. What mattered more was operational cost: schema-per-tenant means every migration runs once per tenant schema and connection/search-path management gets a lot more complex, for isolation guarantees I don’t need yet.
The real tradeoff is that shared schema puts isolation entirely on the application, not the database. Postgres will happily return every tenant’s rows if a query is missing its WHERE tenant_id = ... clause. I addressed that by resolving tenant context in exactly one place: every router depends on get_active_context, which resolves the active user, tenant, and membership once and hands them down, so the isolation check isn’t reimplemented per route, it’s enforced through dependency injection at the FastAPI layer and centralized again in the service layer underneath it. That’s the DRY version of the guarantee schema-per-tenant gives you for free at the database level, backed by tests that specifically check cross-tenant isolation, but it’s still a discipline I have to maintain rather than a wall Postgres enforces for me.
I also treated it as a choice I could revisit rather than a permanent bet. If the shared schema ever gets too large, sharding is still on the table without redesigning the tenant model.
Another downside is encryption. Schema-per-tenant would make per-tenant encryption close to trivial, since each tenant’s data already lives in its own namespace. My approach means that if I ever want to encrypt tenant data at rest beyond what Postgres/Aurora already gives me, I’d have to add application-level encryption before every write. That’s a wishlist item today, not a current requirement, but it’s the real cost of the choice I made.
Results
I use the app daily now, and it’s changed how I actually handle money admin. I don’t enter transactions in real time anymore, I batch them: import a CSV once a month, assign categories, and the whole thing takes about five minutes instead of being a running chore.
Being my own user turned out to matter for the product itself. Two features came directly from using it myself: duplicate detection on import (it can tell if a transaction was already entered manually and skips re-adding it), and dynamic column mapping from CSV to the Expense model, something that came straight from my integration-systems background, since every bank exports columns differently.
It’s also cheap to run. Locally the whole Docker stack is capped at 1 CPU total. On AWS each container runs on 0.25 vCPU, and the Aurora Serverless v2 and Fargate scale-to-zero choices keep compute cost near zero for a low-traffic demo. The Application Load Balancer ends up being the single biggest line item, simply because it’s always on.
The QE work paid off in numbers, not just process. The latest hardening pass shows 84% statement / 78% branch test coverage, an ~79% mutation score, and 86% TDD adherence, with 0 high/critical security findings and average cyclomatic complexity of 2.82 in the service layer (2.43 in routers). That’s the agentic-qe.dev framework mentioned earlier doing its job: tests that measure whether the code is actually correct, not just executed.
Lessons Learned
The lessons from directing the agent solo hold up here: plan thoroughly and review the plan, not just the diff. That’s the one that would have saved me the most rework if I’d internalized it from month one instead of learning it gradually.
The other thing I’d change is the scale of the workflow itself, not the app. Pocket Family was built on a single Pro subscription, which forced me to be the coordinator for every step by hand. For a real production system, I’d drop that constraint and run specialized agents in parallel loops: write the tests first, implement against them until they pass or escalate back to a coordinator if a test itself needs to change, then a review-and-improve pass on top. I orchestrated that pattern manually here and it works, it’s just that running it fully automated burns far more tokens than a Pro subscription can support. Pocket Family proved the workflow, it just didn’t have the budget to run it unattended.