App Bootstrap Template
Use for client-only applications that build to static files and deploy to S3. State lives in the browser (localStorage by default), there’s no server runtime, and no backend calls without explicit feature work. Cheaper to host and faster to ship than the Simple Bootstrap, at the cost of anything that needs a server — auth, secrets, persistent shared state, server-side rendering.
Distinct from the Simple Bootstrap — that’s Next.js on Vercel with a server runtime available even when you don’t use it. Use this when the app is genuinely client-only and you want S3-grade hosting.
This is Prompt 01 — the bootstrap. Claude Code will scaffold the project, create governance files, and stop at PLAN.md for your approval.
The prompt
Section titled “The prompt”You are bootstrapping a new client-only application. Read this entireprompt before starting.
MISSION:[One sentence describing what this app does, for whom, and why.]
TECH STACK:- Vite (react-ts template)- React 18, TypeScript (strict mode)- Tailwind CSS- React Router (BrowserRouter)- Static build, deployed to AWS S3- No backend, no database, no Vercel, no server runtime
ARCHITECTURE CONSTRAINTS:- All state lives in the browser. localStorage for anything that should survive reload; useState / useReducer for ephemeral state; Context only where shared state genuinely needs to cross the tree.- No API keys in the client. If the app needs a third-party API, flag it before adding — the answer is usually "wrong bootstrap, use Simple Bootstrap instead".- All assets local. No fonts loaded over the network, no CDNs.
REQUIRED FILES — create these exactly:
1. .claude/settings.json With this content exactly: { "permissions": { "allow": [ "Read", "Glob", "Grep", "LS", "Edit", "MultiEdit", "Write(src/**)", "Write(public/**)", "Write(docs/**)", "Write(index.html)", "Write(vite.config.ts)", "Write(tsconfig*.json)", "Write(tailwind.config.js)", "Write(postcss.config.js)", "Bash(npm run *)", "Bash(npm install *)", "Bash(npm test *)", "Bash(npx tsc *)", "Bash(git status)", "Bash(git diff *)", "Bash(git log *)", "Bash(git add *)", "Bash(git commit *)" ], "deny": [ "Read(**/.env*)", "Read(**/.dev.vars*)", "Read(**/*.pem)", "Read(**/*.key)", "Read(**/secrets/**)", "Read(**/credentials/**)", "Read(**/.aws/**)", "Read(**/.ssh/**)", "Read(**/.npmrc)", "Read(**/.pypirc)", "Edit(**/.env*)", "Write(**/.env*)", "Write(**/secrets/**)", "Write(**/.ssh/**)", "Bash(cat *.env*)", "Bash(head *.env*)", "Bash(tail *.env*)", "Bash(less *.env*)", "Bash(more *.env*)", "Bash(rm -rf *)", "Bash(sudo *)", "Bash(git push *)", "Bash(npm publish *)", "Bash(aws *)", "Bash(curl * | sh)", "Bash(wget *)" ], "defaultMode": "acceptEdits" } }
2. CLAUDE.md Sections: Mission, Tech Stack, Conventions, Coding Standards, Uncertainty Handling. Include these specifics: - Client-only architecture. No backend, no API keys in the client bundle. Flag any feature that would require either. - State persistence pattern: a single `usePersistedState` custom hook in `src/hooks/`, wrapping useState with localStorage read/write, namespaced keys (e.g. "app:settings", "app:session"). Use this hook for anything that should survive reload; useState / useReducer for the rest. - Routing: BrowserRouter. The S3 bucket must be configured to return index.html for 404s so refresh on a sub-route works. This config lives in docs/features/ as a deploy note, not in the app code. - All assets local. No CDN fonts, no externally hosted images. - Never run aws commands directly. Deployment is via the `npm run deploy` script only. - Uncertainty handling: flag uncertainty about APIs, libraries, or existing file structure rather than guessing. Never invent function names, types, or import paths.
3. memory.md — empty decision log.
4. .gitignore — standard Node + Vite: node_modules/ dist/ .env* !.env.example .DS_Store *.log
5. Folder structure: /src /components /hooks — usePersistedState lives here from day one /lib — pure utility functions, no React imports /routes — one file per route component /styles — global.css for Tailwind directives App.tsx main.tsx /public — static assets copied as-is to dist/ /docs — PRD, design briefs, feature briefs /docs/features
6. README.md — project name, mission, how to develop / build / deploy.
7. package.json scripts: - dev: vite - build: tsc -b && vite build - preview: vite preview - typecheck: tsc -b --noEmit - deploy: aws s3 sync dist/ s3://$BUCKET_NAME/ --delete
8. .env.example with empty values: BUCKET_NAME= AWS_REGION=
9. vite.config.ts — minimal config, base path configurable via env var (useful for deploying under an S3 subpath).
10. tsconfig.json — strict mode on, no implicit any, no unchecked indexed access.
11. tailwind.config.js + postcss.config.js — Tailwind wired into the Vite build. src/styles/global.css has the three Tailwind directives and is imported once in main.tsx.
12. src/hooks/usePersistedState.ts — the localStorage hook. Signature: usePersistedState<T>(key: string, initial: T): [T, (v: T) => void]. Reads on mount, writes on every change, handles JSON parse failures by falling back to the initial value.
INSTALL:- npm create vite@latest . -- --template react-ts- npm install- npm install react-router-dom- npm install -D tailwindcss postcss autoprefixer- npx tailwindcss init -p- Confirm clean install- Confirm `npm run dev` boots and renders the default Vite page- Confirm `npm run typecheck` passes
GIT:- git init, first commit "Initial bootstrap"- No remote yet
WHEN DONE:Write PLAN.md with: - Route structure (one line per route, even if it's just "/") - Component tree (top-level shape) - State map: what lives in usePersistedState, what's ephemeral, what's in Context (if anything) - File count estimate - Deploy target: S3 bucket name placeholder + region - Confirmation that no backend or API key access is required; if any feature might need either, flag it here for discussion before writing codeThen STOP and wait for approval.