React + TypeScript + Tailwind v4 + shadcn/ui frontend (client), Express + better-sqlite3 backend (server) in a pnpm workspace. Includes vite-plugin-pwa manifest, service worker, and iOS install meta tags. GET /api/hello increments a visit counter in SQLite; backend serves the built client in production.
6.0 KiB
AGENTS.md — How to work in this project
A guide for AI agents (and humans) contributing to Pocket Pascal, a small installable PWA with a React/shadcn frontend and an Express + SQLite backend.
1. Overview
- Frontend (
client/): Vite + React + TypeScript, Tailwind CSS v4, shadcn/ui,vite-plugin-pwafor the service worker + web manifest. - Backend (
server/): Express + TypeScript (tsxin dev,tscfor the production build) withbetter-sqlite3as the database. - Workspace: a single pnpm workspace with two packages:
clientandserver.
Runtime model
- Dev: run
pnpm devfrom the repo root. It starts both packages in parallel. The Vite dev server (defaulthttp://localhost:5173) proxies/api/*to the backend (http://localhost:3001), so there are no CORS issues. - Prod / install test: run
pnpm build && pnpm start. The backend serves the built client fromclient/dist(static files + SPA fallback), so a single process onhttp://localhost:3001serves the whole app. This is the easiest way to test PWA "Add to Home Screen".
2. Prerequisites
- Node.js >= 22 (developed on Node 22).
- pnpm (developed on 10.25). The root
package.jsonpins the version viapackageManager.
better-sqlite3ships a native module. It is listed underpnpm.onlyBuiltDependenciesin the rootpackage.json, so a normalpnpm installcompiles/fetches it automatically. If it ever fails to load, runpnpm rebuild better-sqlite3(or from its.pnpmdir:npx prebuild-install -r node).
3. First-time setup
pnpm install
4. Common commands
Run these from the repo root:
| Command | What it does |
|---|---|
pnpm dev |
Start client + backend in parallel (concurrently). |
pnpm build |
Build the server (tsc) then the client (tsc -b && vite build). |
pnpm start |
Run the production server (node server/dist/index.js). |
pnpm lint |
Lint every workspace package. |
pnpm typecheck |
Type-check every workspace package (tsc). |
Run these against a single package with the filter flag, e.g.:
pnpm --filter client dev
pnpm --filter server dev
pnpm --filter client build
5. Project layout
pocket-pascal/
├─ package.json # workspace root + orchestration scripts
├─ pnpm-workspace.yaml # packages: client, server
├─ AGENTS.md
├─ README.md
├─ client/ # Vite + React + Tailwind v4 + shadcn/ui (PWA)
│ ├─ components.json # shadcn config
│ ├─ pwa-assets.config.ts # @vite-pwa/assets-generator config
│ ├─ vite.config.ts # react + tailwind + pwa + /api proxy + "@" alias
│ └─ src/
│ ├─ App.tsx # Hello World UI (fetches /api/hello)
│ ├─ lib/api.ts # typed fetch helpers
│ ├─ lib/utils.ts # cn() helper (shadcn)
│ └─ components/ui/ # shadcn components live here
└─ server/ # Express + better-sqlite3 (ESM, TypeScript)
├─ .env.example
└─ src/
├─ index.ts # express app; serves client/dist in prod
├─ db.ts # opens SQLite, creates schema, exposes helpers
└─ routes/hello.ts # GET /api/hello
6. Conventions
- Language: TypeScript everywhere. The server is ESM (
"type": "module"). - Path alias (client):
@/*maps toclient/src/*(configured intsconfig.json,tsconfig.app.json, andvite.config.ts). Prefer@/components/...,@/lib/.... - API contract: all backend endpoints are prefixed with
/api(e.g.GET /api/hello,GET /api/health). The frontend calls them with relative URLs (fetch("/api/hello")) so the Vite proxy and the prod static server both work without extra config. - Environment: the backend reads
process.env.PORT(default3001). Seeserver/.env.example. - Styling: Tailwind v4 + shadcn theme tokens (CSS variables in
client/src/index.css). Use shadcn primitives; reach forcn()in@/lib/utilswhen composing classes.
7. Database
- The SQLite file lives at
server/data/app.db(auto-created on first run; the wholeserver/data/directory is gitignored). - There is no migration tool. Schema changes use idempotent statements
(
CREATE TABLE IF NOT EXISTS ...) inserver/src/db.ts, which runs on boot. - The demo
visitstable has a single enforced row (id = 1) holding a counter thatGET /api/helloincrements.
8. Adding a shadcn/ui component
Run from the client/ directory (it reads components.json):
cd client
pnpm dlx shadcn@latest add <component> # e.g. card, input, dialog
The component is written to client/src/components/ui/. shadcn was initialized
with the neutral base color and the base-nova style.
9. Regenerating PWA icons
Icons are generated from client/public/icon.svg via @vite-pwa/assets-generator:
cd client
pnpm dlx @vite-pwa/assets-generator # uses pwa-assets.config.ts
Outputs land in client/public/ (pwa-*.png, maskable-icon-*.png,
apple-touch-icon-*.png). The manifest in vite.config.ts references them.
10. PWA / install notes
- iOS Safari needs the meta tags already in
client/index.html(apple-mobile-web-app-capable,apple-touch-icon, etc.) and a valid icon set. - Service worker + manifest are produced by
vite-plugin-pwa. To verify installability:pnpm build && pnpm start, openhttp://localhost:3001, then DevTools → Application → Manifest / Service Workers. Real-device install off localhost requires HTTPS.
11. Before you finish a change
Always run, from the repo root:
pnpm typecheck
pnpm lint
pnpm build
Then sanity-check pnpm dev (or pnpm build && pnpm start) end to end.