docs: bootstrap project instructions and roadmap

Add CLAUDE.md with authoritative stack (FastAPI + Jinja2 + SQLite),
deployment topology (CF-proxied -> OPNsense -> Caddy -> VM),
security must-haves, magic-link auth, and project git flow.

Add docs/ROADMAP.md with phased build plan, dataclasses, SQL schema,
caching strategy, visual design tokens (light-blue farm palette),
and .env contract.

Commit generic code_guidelines.md and security.md, note FastAPI
per-project override. Add docs/README.md. Commit logo assets and
.gitignore (venv, .env, data/, SQLite, caches).

No app code in this pass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-21 14:22:34 -05:00
parent 2f84a6327f
commit bf4352231a
9 changed files with 2845 additions and 0 deletions

116
CLAUDE.md Normal file
View File

@@ -0,0 +1,116 @@
# Chicken Babies R Us — Project Instructions
Small farm website for **Chicken Babies R Us** (Morrison TN — address is intentionally **not** displayed publicly). Public brochure site with a blog-style home, About, Contact, and a disabled "Shop (coming soon)" placeholder. The owner's wife, **Head Hen**, edits all content through an admin area protected by email magic-link authentication.
> This file is authoritative for *this project*. Where it conflicts with `code_guidelines.md`, this file wins.
---
## Stack (authoritative for this project)
| Layer | Choice |
|---|---|
| Language | Python 3.12 |
| Web framework | **FastAPI** (overrides the Flask default in `code_guidelines.md`) |
| Templates | Jinja2 |
| ASGI server | Uvicorn, behind Caddy reverse proxy |
| Database | SQLite (WAL mode) — single-writer is fine at this scale |
| Cache | In-process TTL cache + row-level rendered-HTML cache (no Redis) |
| Email | Resend (contact form + magic-link auth) |
| Anti-spam | hCaptcha + honeypot + SlowAPI rate limits |
| Logging | `structlog` |
| Container | Docker (multi-stage), target = Debian 12 VM on home server |
| Repo host | Gitea (Actions for image build/publish wired later) |
## Deployment Topology
```
Internet
→ Cloudflare (proxied DNS)
→ OPNsense firewall (inbound 443 allowed only from Cloudflare IP ranges)
→ Virtual IP
→ Debian 12 VM
→ Caddy (TLS termination)
→ Uvicorn + FastAPI container
```
The app MUST trust `X-Forwarded-For` / `X-Forwarded-Proto` **only from Caddy's IP**. Run Uvicorn with `--proxy-headers --forwarded-allow-ips=<caddy-ip>`. Never read `X-Forwarded-*` in application code directly — let Starlette's `ProxyHeadersMiddleware` do it.
## Target Repository Layout (after Phase 0)
```
/ repo root
├── app/ FastAPI application package
│ ├── main.py app factory + startup
│ ├── config.py typed config loader (pydantic-settings)
│ ├── models/ dataclasses + SQL schema + migrations
│ ├── routes/ public_router.py, admin_router.py, auth_router.py
│ ├── services/ auth, email, cache, markdown, media, hcaptcha
│ ├── templates/ Jinja2 (public/ + admin/ + emails/)
│ └── static/ CSS, JS, site images, logo
├── data/ runtime (SQLite DB + uploads) — mounted volume in prod
├── docs/ business + architecture docs (NO application code)
│ ├── README.md
│ ├── ROADMAP.md
│ └── MANUAL_TESTING.md (added in Phase 1)
├── tests/ pytest
├── Logo/ brand assets (source)
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
├── .env.example
├── .gitignore
├── CLAUDE.md
├── code_guidelines.md
└── security.md
```
## Security Must-Haves (in addition to `security.md`)
- **SQL**: parameterized statements only (sqlite3 `?` placeholders or SQLAlchemy Core bind params). Never f-string a query.
- **Markdown**: hardened pipeline `markdown-it-py``bleach` allowlist. No raw HTML pass-through.
- **Image uploads**: validate magic bytes with `python-magic`, cap at 8 MB, re-encode through Pillow, store under a random filename, discard the client-supplied extension.
- **CSRF**: double-submit cookie on every admin `POST` / `PUT` / `DELETE`.
- **Cookies**: `Secure`, `HttpOnly`, `SameSite=Lax`; session IDs signed with `itsdangerous`.
- **Security headers** (middleware): strict nonce-based CSP, HSTS, `X-Content-Type-Options: nosniff`, `Referrer-Policy: strict-origin-when-cross-origin`, `Permissions-Policy`.
- **Magic-link tokens**: 256-bit random (`secrets.token_urlsafe(32)`), stored hashed (SHA-256), single-use, 15-minute expiry. IP is logged but not enforced (mobile roaming).
- **Rate limits** on auth endpoints: 5 requests / 15 min / IP *and* / email.
- **Admin allowlist**: only addresses in `ADMIN_EMAILS` env var may request a magic link. Any other address silently succeeds (no user enumeration) but sends no email.
- **Secrets**: env / `.env` only, never committed. `.env.example` is the public contract.
- **Audit logging**: every auth event (link requested, link consumed, session created/revoked, rate-limit hit) at INFO. Never log raw tokens or email bodies.
## How to Run (dev)
```bash
python3.12 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # fill RESEND_API_KEY, HCAPTCHA_*, ADMIN_EMAILS, SECRET_KEY
uvicorn app.main:app --reload
```
Docker (parity with prod):
```bash
docker compose up --build
```
## Testing
- `pytest` for auth, magic-link lifecycle, markdown sanitization, rate limits, contact form.
- **Never mock the DB** in auth/magic-link tests — use a temp SQLite file so behavior matches prod.
- Manual test checklist lives in `docs/MANUAL_TESTING.md` (added in roadmap Phase 1).
## Git Strategy (this project)
- Branches: `master` (prod) · `dev` (integration) · `feat/*`, `chore/*`, `docs/*`, `fix/*` (work branches).
- **Work branches off `dev`.** Local `--no-ff` merge into `dev`, then push `dev`. Promote `dev``master` with `--no-ff` for releases. Tag `master` with `vX.Y.Z`.
- Conventional commits: `feat:`, `fix:`, `chore:`, `docs:`, `refactor:`, `test:`.
- Do **not** push directly to `master`. Do **not** force-push shared branches.
## Pointers
- Generic Python standards: `code_guidelines.md` (FastAPI overrides its Flask default)
- Security baseline: `security.md`
- Phased roadmap, dataclasses, SQL schema, visual design: `docs/ROADMAP.md`
- Docs folder guide: `docs/README.md`