Boring Docs
Project Structure — Where Everything Lives
Providers, libs, models, thin routes, pages, components, config, data, scripts.
In this guide
Project Structure
Convention over configuration. See CONVENTIONS.md — this doc mirrors it.
Top level
providers/db/<engine>/— one folder per database (sqlite,mongodb,supabase). Same exports everywhere. Plugged in viaproviders/db/index.js.providers/billing/<rail>.js— one file per rail (stripe,lemonsqueezy,dodo). Unified surface:createCheckoutSession,createPortal,verifyAndParse. Registry:providers/billing/index.js.providers/billing/access.js— sharedgrantAccess/revokeAccess. Only place money touches users/orders.providers/analytics/—track()write path +stats.jsread path on separateanalytics.sqlite.libs/— runtime helpers:config.js(toggles/limits),paywall.js(requirePaidUser),security.js(safeUrl,assertActorIntegrity,rateLimit,timeAgo),telemetry.js(screamalerts),admin.js,next-auth.js,stripe.js,resend.js,blog.js,seo.js,voter.js,mongo.js.libs/mongoose.jsis a frozen re-export shim.models/*.js— frozen one-line re-exports overproviders/db/index.js. Never add logic here.app/api/<thing>/route.js— thin handlers only: validate → auth → one provider call → JSON. ≤ 40 lines per handler.app/(pages)/<route>/page.js— public pages; private ones underapp/(pages)/dashboard/. Server components, data at top, props down.components/<Name>.js— presentational only, Tailwind, props in. No DB/driver imports in client components.config/— domain configs (app,billing,auth,email,theme,services,paths,paywall,navigation) re-exported byconfig/index.jsand rootconfig.js.data/blog/<slug>.md— markdown posts with frontmatter.data/docs/*.md— these guides.scripts/<verb>-<noun>.sh— wired asnpm run <verb>:<noun>,sh-compatible,set -eu.nginx/<name>.conf— deploy targets with__PLACEHOLDERS__..agents/+AGENTS.md— agent operating manual and skills.
Adding anything
| Creating… | Put it in | Shape |
|---|---|---|
| New database | providers/db/<name>/ + 1 line in registry |
connect, User, Board, Lead, Post, Vote, Comment, Product, Order |
| New entity | Same exports in every engine + delegate + models/<E>.js shim |
{ create, findById/getById, list*, set*, delete* } → plain { _id, id, … } |
| New rail | providers/billing/<name>.js + 1 registry line |
createCheckoutSession, createPortal, verifyAndParse |
| New endpoint | app/api/<thing>/route.js |
validate → auth → provider → JSON |
| New page | app/(pages)/<route>/page.js |
server component |
| New UI piece | components/<Name>.js |
props in, JSX out |
No new top-level folders without updating CONVENTIONS.md.