The first dev log on this site, covering the M1 (foundation) milestone finished on 2026-10-18.
Scope
The first public release is a complete site: blog, bilingual resume, project showcase, public feedback and discussion, progress, release notes, login/guest access, in-site and email notifications, admin tooling, plus the Civitas showcase and a verified playable entry. M1 is foundation only — no content yet.
What shipped
- Stack: Astro (static content + React islands) on Cloudflare Pages/Workers, D1 database, R2 reserved.
- Design system: tokens, light/dark themes, button/form/status/dialog/list components, mobile-first and keyboard accessible.
- Bilingual: dictionary + locale routing (Chinese at
/, English at/en/) with a blocking missing-key check at build time. - API contract: unified error codes, request IDs, no internal details leaked on 5xx, JSON size limits and field validation, 11 unit tests.
- Data: D1 migrations (project/module dictionary, rate-limit table), preview/production isolation, idempotent local replay.
- Security baseline: security headers, JSON 404 fallback for
/api/*, public-output secret scanning, CI workflow. - Guest & rate limiting: HttpOnly guest cookie + D1 fixed-window limiter; locally verified to return 429 from the 6th request.
Pitfalls
- JSX inside attribute expressions or inside Astro frontmatter fails the build.
- Node 24 running TypeScript tests directly does not support
as const. - Rate limiting “not working” during acceptance turned out to be entirely test-client issues: PowerShell’s
-Headersdoes not send Cookie headers, andcurl -b fileneeds Netscape format. The server was right all along — suspect the client first. - For local D1 checks, the
wrangler pages dev --d1flag and the config binding are not the same local database.
Next
M2 adds content: three home modes, resume page, blog pipeline, project pages and the Civitas showcase. Once official mod materials and cloud accounts are in place, the feedback loop (M3) can run for real.
Discussion
…