Capability pack
Accounts
The part that is expensive to get right and cheap to copy. Credentials and OAuth through one Auth.js configuration, password hashing that is not a hand-rolled hash, ownership checked server-side on every action rather than hidden in the UI, and the rights a person has over their own data: export everything, delete the account.
Capabilities
11
All of them are built.
Watched in production
0
11 have never been watched against a real provider.
Provider variables for a fresh project
3
Including the packs it sits on. 3 unset here, each running its documented fallback.
Needed regardless of providers
- A Postgres database — accounts, sessions, tokens, and the audit log.
- AUTH_SECRET, which is not a provider key: it is the site's own signing secret.
What is in it
Each row links to where it lives, and carries the state it has in THIS deployment.
- Ready
Credentials sign-in with an httpOnly, encrypted session cookie.
Auth.js v5 (beta)
OAuth providers
FallbackSign in with Google or GitHub beside email + password. A provider identity is linked to an existing account by email only when the provider verified that email; otherwise the person is told to sign in with their password first. Accounts created this way have no password until they set one.
Needs
AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET. Without it: Only email and password sign-in is offered; the provider buttons are hidden rather than shown broken.Auth.js — Google and GitHub, present only when configured
Password hashing
ReadyPer-user salt, a memory-hard KDF, and constant-time comparison.
node:crypto scrypt
Email verification
FallbackSign-up sends a 24h link; recorded but not enforced at sign-in — by design here.
Needs
RESEND_API_KEY. Without it: The verification link prints to the server console.Single-use hashed tokens
- Fallback
A 30-minute link that burns on use; the change and the burn commit together.
Needs
RESEND_API_KEY. Without it: The reset link prints to the server console.Single-use hashed tokens
- Ready
Edge-safe config, plus a second check the page makes for itself.
Middleware + page checks
- Ready
Authorization on every mutation, not just hidden buttons in the UI.
Server Actions + Prisma
- Ready
A person can download everything the site holds about them as one JSON file, and delete their account: typed-email confirmation, the password when there is one, the last-admin invariant, orders kept as records without a link, an audit entry that outlives the account, uploads removed from storage.
Export route + deletion action under the admin-count lock
- Ready
Records that outlive the rows they describe, via a nullable relation.
Prisma + Server Actions
- Ready
Written in the same transaction as the event they announce; mark-read scoped to the reader in the WHERE clause; the badge polls every 30s only while the tab is visible.
Notification table + a polling bell
The important few notifications go out at once — queued in the same transaction as the notification, sent by the outbox drainer — and the rest arrive as a daily or weekly digest whose window and marker move together. Preferences live on the account so every device agrees; every email carries a signed link that turns both off.
Needs
RESEND_API_KEY. Without it: Digests and immediate mail print to the console.Account preferences, MailOutbox rows written with the notification, a digest cron, purpose-scoped signed stop links
First steps in a fork
- 1Set AUTH_SECRET and DATABASE_URL, then run the migrations.
- 2Create your own account through the site and promote it: npm run admin:grant you@example.com.
- 3Add Google or GitHub credentials only if you want them; the buttons appear when the keys do.
What to delete
- Nothing — every other pack sits on this one.
Provider variables a fresh project would set
AUTH_GOOGLE_IDAUTH_GOOGLE_SECRETRESEND_API_KEY
Shaded green: set on this deployment.
The full inventory, with the tests that cover each capability and what has actually been watched working.
Capability inventory