# template-react A starting point for an app. **Bun · Hono · React 19 SPA · Tailwind v4 · shadcn/ui · Postgres with Drizzle.** A JSON API at `/api` and a React app at `/`, over one query layer. ## 1. Make it yours Everything project-specific is called `app`. Rename it once, before the first commit: | Find | Replace with | Where | |---|---|---| | `APP_ENV` | `MYPROJECT_ENV` | `src/env-file.ts`, `package.json` scripts, `test-setup.ts`, `src/databases/app_db/src/env.ts` | | `appEnv` | `myprojectEnv` | `src/env-file.ts` and its importers | | `appdb` / `app_db` | `myprojectdb` / `myproject_db` | `src/databases/`, `tsconfig.json` paths, `package.json` scripts | | `app` / `app_dev` (database names) | `myproject` / `myproject_dev` | `src/databases/app_db/src/env.ts`, `.env.example` | | `"name": "app"` | your package name | `package.json` | | `App` | your brand | `src/apps/frontend/App.tsx`, `index.html` `` | | `3000` | a port of your own | `.env.example`, `src/server.ts` | A case-sensitive search for `app`, `App` and `APP` finds all of it. Thirty seconds now, a chore later. ## 2. Setup ```bash bun install cp .env.example .env # BUN_PORT, PUBLIC_URL, POSTGRES_URL_DEV createdb app && createdb app_dev # or however you make databases bun run db:push # applies the schema — no tables yet, by design bun dev ``` ## Scripts ```bash bun dev # development on app_dev, with HMR bun start # production on app bun test bun run build # bundle the SPA to dist/ bun run gen:index # index.gen.html from index.html — also run by predev/prestart/prebuild bun run db:push # schema -> app_dev; APP_ENV=production bun run db:push for production ``` ## What is served | Path | | |---|---| | `/` and every unmatched path | the SPA — `src/apps/frontend` | | `/api/*` | the JSON API — `src/servers/api` | | everything in `public/` | from the root | ## Configuration, and the rules behind it **`APP_ENV`, never `NODE_ENV`.** It must be `production` or `development` and throws when unset. Some hosts export `NODE_ENV=production` into every process they spawn, so anything keyed on it silently treats development as production. **`NODE_ENV` is still set by both scripts, and must stay explicit.** React resolves its runtime against it: Bun's bundler emits `jsxDEV()` calls in development, and React's *production* `jsx-dev-runtime` defines `jsxDEV` as `void 0`. Inherit production while transforming for development and the app dies with "jsxDEV is not a function". **Env files are read with the ambient environment last:** `.env.production.local` (production only) → `.env.local` → `.env` → `process.env`. **The database follows from `APP_ENV`** and is enforced before a connection opens; tests cannot reach production data. **`PUBLIC_URL`** is substituted into `index.html` by `scripts/gen-index.ts` because Bun's HTML bundler fails the build on a root-relative favicon `href`. It must be the public origin in production. ## The placeholder `src/apps/frontend/App.tsx` is a shell with one tab and no features. Add the first screen as a feature folder — `CONVENTIONS.md` describes the shape. The database has **no tables**; `docs/DATABASE.md` describes adding the first. ## Documentation | | | |---|---| | `CLAUDE.md` | The rules an agent needs before touching anything | | `CONVENTIONS.md` | React patterns — feature folders, manager hooks — and the project layout | | `docs/DATABASE.md` | Drizzle structure, `push` not migrations, `check()` vs open `text` | | `docs/SURFACES.md` | The API and the app over one query layer |