# app
A project started from `template-react`. **Rename `app` first** — README step 1.
**Bun · Hono · React 19 · Tailwind v4 · shadcn/ui · Postgres with Drizzle.**
## Read these before writing code
| | |
|---|---|
| `CONVENTIONS.md` | React patterns — feature folders, manager hooks, colocated state — and layout |
| `docs/DATABASE.md` | Drizzle structure, `push` not migrations, `check()` vs open `text` |
| `docs/SURFACES.md` | The JSON API and the app: one process, one query layer |
| `README.md` | Setup, scripts, configuration |
## Rules that are load-bearing
**`APP_ENV`, never `NODE_ENV`.** Must be `production` or `development`; throws when unset. Hosts export
`NODE_ENV=production` into everything they spawn, so anything keyed on it treats development as
production silently. `NODE_ENV` is still set explicitly by both scripts because React's runtime
resolves against it — Bun emits `jsxDEV()` in development and React's production runtime defines it
as `void 0`.
**Env files are read with the ambient environment LAST**: `.env.production.local` (production only)
→ `.env.local` → `.env` → `process.env`.
**Asset URLs in components are relative — never start with `/`.** `` in `index.html`
is what a path-prefix proxy rewrites; a leading slash bypasses it. `asset-urls.test.ts` enforces this.
`fetch('/api/...')` is the exception.
**Routing is in the hash.** The app may be mounted under a prefix it only learns at runtime, and a
hash means the same thing at either mount point. `lib/routes.ts`.
**One feature folder per screen, one manager hook per feature.** State lives in the hook, components
receive the manager. `CONVENTIONS.md`.
**Serializers live in `src/servers/serialize.ts` only.** Its test walks the module's exports for
camelCase keys and for serializers without a case.
## Bun
- `bun ` not `node`, `bun test` not jest/vitest, `bun install`, `bunx`
- `Bun.serve()` — not express. `Bun.file` over `node:fs`. `Bun.$` over execa
- Bun loads `.env` automatically; do not add dotenv
- `bun dev` and `bun start` set the env markers. Running `src/server.ts` directly throws, by design
## Before you finish
- `bunx tsc --noEmit` and `bun test`
- Verify claims rather than asserting them — start the server and request the thing
- Commit with a message that says *why*, not what the diff already shows