parlor
parlor is the front door of every product built on cafaye: a Next.js app shell —
signup, login, accounts and tenancy, team and invitation management, and the
billing screens — plus the admin surface they all inherit. It is Next.js,
because it is the web and nothing else needs to be.
It is a template, not a platform dependency
Section titled “It is a template, not a platform dependency”That is the design decision to understand before using it. You clone it, you read all of it, you change what you need and ship your fork: no license key, no feature gate, no call home, and no vendor who can raise your prices or pull the rug later. Anything cafaye adds to the shell arrives as code in your repository, not as a runtime dependency, and upstream improvements come back as a merge rather than a migration.
The test of whether that is real: if cafaye disappeared tomorrow, a
parlor-based product would keep shipping.
The tenancy surface is gated by role, transcribed from identity
Section titled “The tenancy surface is gated by role, transcribed from identity”src/lib/roles.ts is the capability matrix, transcribed from identity’s own
authorization — so the UI hides what the API would refuse, and the API is still
the authority. Each account call declares the minimum role its route needs:
| Call | Minimum role |
|---|---|
listAccounts(token) |
any session |
| read one account, list members | member |
| create a tenant | any session |
| rename, invite, remove a member | admin |
| change a role, delete the account | owner |
The invitation route does not accept on load — it takes a deliberate click, because an invitation token redeemed by a prefetch or a crawler is an account created for whoever the link was forwarded to.
Money is integers here too
Section titled “Money is integers here too”src/lib/money.ts takes integer minor units in and gives a price out, and the
billing client has its own error type rather than borrowing identity’s. The rule
is the platform’s rule and the shell follows it, so a fork does not start with a
Float.
Session handling is settled in the repository, not the template
Section titled “Session handling is settled in the repository, not the template”Because the browser reaches identity cross-origin, session handling is a
deliberate decision here: a BFF route owns the cookie before it can be one. The
token is in an injectable localStorage store rather than a hard-coded
access, which is what makes the test rig possible and a future cookie-based BFF a
change rather than a rewrite.
The Playwright suite (signup, login, MFA, invites, checkout) is born here and is not written yet.
- Repository: github.com/cafaye/parlor
- Language: Next.js / TypeScript
- Local port: 3000 ·
bun run dev - Health:
GET /healthz→{"status":"ok"}·GET /readyz→{"status":"ok","deps":"none"}, wheredepsis a reserved placeholder