Oryn
An exercise in building multi-tenant architecture—how I learned to isolate data, manage subscriptions, and think in layers rather than features.
Context
I set out to understand how modern SaaS platforms (Linear, Notion, Figma) serve thousands of companies from a single codebase while keeping data strictly separated. Not by reading about it—by building the infrastructure myself.
The result is Oryn: a backend API where companies sign up, get provisioned an isolated workspace, and manage projects internally. Two levels—Tenant and User—with boundaries enforced at every layer.
This is the largest project I've built not by LOC count, but by discipline. I used Claude Code and Copilot to plan infrastructure before writing imports, challenging assumptions rather than generating code. Also built this interface with Kimi to document the journey.
How It Was Built
I started with the database. Multi-tenancy offers three paths: shared schema, isolated schema, or isolated databases. I chose shared database with row-level security—enforcing tenant isolation at the application layer through strict query scoping.
PyJWT • FastAPI Depends • SQLAlchemy
stripe-python • Webhooks • Async handlers
PostgreSQL triggers • Append-only tables
asyncpg • asyncio • Connection pooling
What I Learned
Planning is cheaper than refactoring. Two days whiteboarding database relationships saved weeks of migration headaches. The upfront cost of thinking through foreign key constraints and cascade behaviors paid for itself immediately.
Audit logs are infrastructure, not features. When built into the base class, tracking is automatic and comprehensive. When added later, it's patchy and unreliable.
Multi-tenancy is a business logic concern. Deciding where to enforce boundaries—database, application, or both—affects every query you write. I chose application layer enforcement with database constraints as backup.
I also learnt how to manage and build a real working subscription system with Strip integration which to me seemed complex, until I built it myself
On testing: I abandoned automated testing for this project, relying solely on Postman. Not proud of this—automated testing would have caught edge cases earlier. Next project, testing comes first, not last.
I learned how to implement rate limiting in my application using SlowAPI. This technique allows me to control how many requests a client can make within a specific time window. By enforcing these limits, I can protect the system from abuse and ensure fair access for all users.