Repository navigation
v0.4.0 Development
Note: Documentation of Guestroll v0.4.0. The latest release is v0.5.0: this page in v0.5.0 · what changed · other versions
git clone https://github.com/achedon12/guestroll && cd guestroll
nvm use # Node 22, see .nvmrc
npm ci
echo "ADMIN_PASSWORD=dev-password-123" > .env.local
npm run dev # http://localhost:3000Fill it with demo events and photos (through the public API, in another terminal):
BASE_URL=http://localhost:3000 ADMIN_PASSWORD=dev-password-123 npm run seed:demoTo try the camera on a real phone, the page must be HTTPS. The quickest way is
a tunnel (cloudflared tunnel --url http://localhost:3000) or
next dev --experimental-https on your LAN.
npm run lint
npm run typecheck # generates Next's route types first
npm test # unit + integration (Vitest)
npm run test:coverage # the same, with a coverage report in coverage/
npm run build
npm run test:e2e # functional tests on the production build (Playwright)npm run test:e2e starts the production build on port 3210 with a temporary
data folder, so it never touches your data. Locally it uses your installed
Chrome; in CI, the Chromium installed by npx playwright install.
| Layer | Where | What it runs against |
|---|---|---|
| Unit | tests/unit/ |
Pure modules: access policy, validation, rate limiter, QR rendering… |
| Integration | tests/integration/ |
Real SQLite in a temp folder, real images through sharp, real ZIPs, QR codes decoded by ZXing |
| Functional | tests/e2e/api/ |
The HTTP API of a running production build: guest and admin scenarios, security, quotas |
| Browser | tests/e2e/browser/ |
Real journeys: a guest on a phone, an admin on a desktop |
Unit-level files:
| File | What it locks |
|---|---|
policy.test.ts |
Every access rule: who sees which photo, in which size |
routeGuards.test.ts |
Every admin page and route checks the session; every guest mutation checks the origin |
qrScan.test.ts |
Every QR preset and shape is rendered and decoded with ZXing |
qr.test.ts |
Style parsing, escaping, logo excavation |
request.test.ts |
Client IP and origin rules, the streaming body cap |
rateLimit.test.ts, validation.test.ts, ids.test.ts, negotiate.test.ts, translate.test.ts
|
The rest of the pure modules |
develop is the default branch, where pull requests land; main is
production. Every change on either branch runs:
| Workflow | What it does |
|---|---|
| Quality | Lint, types, production build |
| Tests | Vitest with coverage, then Playwright on a production build |
| Security | CodeQL (code and workflows) and npm audit on production dependencies, plus a weekly run |
| Docker image | Builds the image, runs it on a custom port and user, uploads a photo end to end, then upgrades: the latest release fills a data folder and the new image must start on it with every event and photo intact |
| Workflows | actionlint and zizmor on .github/
|
Publish to production (manual) fast-forwards main to develop once
Quality and Tests passed there; Align develop carries anything that lands on
main back to develop. Tagging main with vX.Y.Z runs Release: the
multi-arch image on GHCR (and Docker Hub when its secrets are set) and a GitHub
release with generated notes. Docs builds the website and the wiki from
docs/ (see below) when develop changes them and when a release is tagged.
tests/integration/upgrade.test.ts rebuilds the database of every release from
the migrations it shipped, fills it the way that version did, and opens it with
today's code. When a release adds migrations, add it to SHIPPED_MIGRATIONS.
Never edit a migration once it's released: instances already applied it.
- Move the Unreleased entries of
CHANGELOG.mdunder a new## [X.Y.Z] - dateheading, with an Upgrading list when something needs the admin's attention, and update the compare links at the bottom. - Bump
versioninpackage.json, push todevelop, wait for the checks. - Run Publish to production, then tag
mainwithvX.Y.Z.
The release notes are that changelog section (the release fails without one), and the admin's update page shows it to everyone running an older version.
docs/ is both the documentation read on GitHub and the source of the website
(VitePress) and of the wiki. Write Markdown there, nowhere else: the wiki is
regenerated by the Docs workflow, edits made on it are lost.
cd docs
npm install
npm run dev # http://localhost:5173/guestroll/.github/scripts/build-docs.py builds every release's docs (the latest at the
root, develop under /next/ once it differs, older ones under /vX.Y.Z/),
with today's configuration and theme so they all share the version switcher.
.github/scripts/build-wiki.py does the same for the wiki, with a page per
release under vX.Y.Z-Page. Links to files outside docs/ (like
../SECURITY.md) point at GitHub on the website.
Housekeeping: Dependabot (grouped, one-week cooldown), stale issues, a welcome message on first pull requests, a "merge conflict" label, and pull requests sent back to draft when changes are requested.
Edit src/lib/db/schema.ts, then:
npm run db:generate -- --name short_descriptionCommit the generated folder under drizzle/. Migrations run automatically on
startup. Never edit a migration that has been released.
- TypeScript strict, ESM, the
@/alias forsrc/. - Access rules go in
lib/policy.tswith a test. Routes stay thin. - UI text goes in
lib/i18n/messages.ts, in all four languages. - Colors only through the tokens in
globals.css(bg-surface,text-ink-muted…), so both themes keep working. - Comments explain why, not what.
- Commits follow Conventional Commits.
The visual direction is described in design-prompt.md: read it before changing the interface.