Work / Trunk / Wiki / Decisions
2026-10-12-stack
Decisioncanonicalverified 2026-10-12
DECISION.2026-10-12.STACKThe stack: one Next.js app, one worker, one Postgres
Decision
| Part | Choice |
|---|---|
| Repo | Turborepo + pnpm |
| Web and API | one Next.js app (App Router), React, Tailwind. The API is tRPC inside it |
| Capture | a Node worker driving Chromium with Playwright |
| Database | Postgres with Prisma |
| Jobs | the CaptureRun table is the queue. A worker takes the oldest waiting row with FOR UPDATE SKIP LOCKED. No Redis, no queue library |
| Sign-in | Better Auth, self-hosted: email and Google. Companies, members, teams and invites are Trunk's own tables |
| Files | Cloudflare R2, through the S3 API |
| AI | Anthropic SDK |
| Amazon SES | |
| Tests | Vitest, and Playwright for end-to-end |
| Hosting | one server running Docker Compose: web, worker, Postgres, a reverse proxy |
Why
The owner asked for the cheapest stack that fits. Two things decide it.
- Capture needs a real browser in a long-lived process. That rules out serverless-only hosting. Once one server exists, running everything on it is the cheapest setup: one fixed bill, no per-request or per-user fees.
- Every client of the API is this app's own TypeScript. A second API server and a schema language would be extra code with no user.
Each paid service is replaced by something free to run: sign-in is a library, the queue is a table, files have no download fee. The AI is the only cost that grows with use, and it is metered (plans).
Alternatives
- The Scrvio stack (NestJS, GraphQL). Known, and its sign-in, storage and billing code exists. It adds a second server and code generation. Its storage and billing logic is still reused, as plain modules.
- Firebase, as in AskCal and Chitragupt. Components, variants and their usages are relational. Firestore fits them badly.
- A hosted browser service for the live session. Paid per minute. The worker streams its own browser instead.
Impact
apps/web,apps/worker,packages/db,packages/capture,packages/ui.- Prisma and S3-style storage match Scrvio, Learning Platform and Dwarseva. Anthropic matches AskCal and Chitragupt.
- The worker opens addresses typed by users. It must refuse private network addresses.
- Company data is protected in the database itself. See tenant-isolation.
- Moving to managed hosting later is a deploy change. Nothing in the code assumes one server.
Not settled: the hosting provider and the payment provider. Both are chosen when their step comes.
Status
Accepted 2026-10-12. The owner asked for the recommendation by cost and fit.
Sources
- The owner's answers in the session of 2026-10-12.
- The
package.jsonfiles of Scrvio, Learning Platform, Dwarseva, AskCal and Chitragupt. ~/git/products/PLAYBOOK.md, "What to charge for".