The work every product repeats
A new product starts with a particular problem. Its first weeks often look much less particular: sessions, workspace records, subscription state, background work, and email delivery. These pieces need to cooperate before the product can do anything useful.
supastack gives that repeated work a home. A Next.js web app and an Expo mobile app share TypeScript packages for the infrastructure underneath. The aim is to make those boundaries understandable enough that a product can configure them without inheriting somebody else’s domain model.
Give each module one responsibility
Identity establishes who is making a request. Workspaces determine which records that person can access. Billing records payment state, while entitlements answer whether a capability is available. Keeping these concerns distinct prevents a successful payment redirect from becoming an authorization decision.
The same discipline applies to background work. The shared JobRunner contract promises enqueue, status, and cancel. Trigger.dev owns the workflow behavior. A small interface is valuable when its limits are visible; hiding retries or scheduling behind a generic method would make the system harder to reason about.
Leave room for the product
A prospecting workflow, a document editor, and a research assistant may use the same identity and billing modules. Their records, language, and workflows are still different. Product-specific logic belongs in the consuming product codebase, with configuration connecting it to the foundation.
This separation is also a practical maintenance decision. A fix to workspace isolation should be reusable. A change to how one product scores a prospect should not become a new requirement for every other product.
Start with one complete flow
Begin with the local reference flow: sign in, inspect access, submit a task, and read its result. Fake and local adapters let deterministic tests exercise the path without paid provider requests. Then configure the production integrations your product actually needs.
Local acceptance and production acceptance answer different questions. A passing local test establishes application behavior under controlled conditions. Real authentication persistence, provider delivery, deployment, and device behavior still need their own verification. Keep that distinction visible as the product grows.