steid

@jamesgill /

docs: add CLAUDE.md

Codifies what has been working and what hasn't. The docs rule is the point:
plans/ was updated reactively twice this session after being asked, rather
than as part of finishing the work. Given the project has been restarted
three times and both previous attempts lost their reasoning at exactly those
handover points, that lag is the failure mode worth naming.

Scoped rather than absolute -- which file to update when, plus an explicit
skip list for typos and dependency bumps, so it doesn't become noise that
gets ignored.

Also records the conventions, the verification steps, and the gotchas that
cost real time: the topcoat v0.0.0 placeholder on old toolchains, the
silently-dropped Secure cookie, and the in-memory setup token rotating on
every dev rebuild.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
JamesPatrickGill authored 1 month agoparent076dbc9Browse files10ecb9976c293a5c89dbef0f03b67d785f568ada

1 file changed+93 −0

CLAUDE.md+93 −0View file
@@ -0,0 +1,93 @@
1+# Steid
2+
3+A personal-first gitforge in Rust. Hosts git repos, writing, and projects for one
4+developer or an organisation. **Portfolio-first, not a Gitea clone** — the profile page
5+is the product and repos are one kind of thing on it. Use that to break ties.
6+
7+## Read first
8+
9+`plans/` is the source of truth and is tracked in git. Read it at the start of a
10+session rather than inferring intent from the code.
11+
12+| File | Holds |
13+|---|---|
14+| `plans/ROADMAP.md` | vision, stack, the single milestone ladder |
15+| `plans/current.md` | the active milestone only — steps, watch-fors, backlog |
16+| `plans/progress.md` | what shipped, and the decisions worth not rediscovering |
17+| `plans/architecture.md` | layer rules and conventions |
18+| `plans/runbook.md` | how to run it, config, manual verification |
19+| `plans/decisions/` | ADRs; `TEMPLATE.md` defines the format |
20+
21+## Keep the docs current
22+
23+**Before reporting work complete, update `plans/`.** This is part of finishing the
24+work, not a follow-up chore — the project has been restarted three times and the
25+previous attempts lost their reasoning at exactly these handover points.
26+
27+- `current.md` — tick off finished steps; move completed work out to `progress.md`.
28+ If it starts reading like a changelog, it has drifted.
29+- `progress.md` — record decisions and gotchas that aren't obvious from the code. The
30+ test is: would the next session waste an hour rediscovering this?
31+- `ROADMAP.md` — only when a milestone's status actually changes.
32+- `decisions/` — a new ADR when a choice would be expensive to reverse or constrains
33+ future work. Write it when the decision is made; reconstructed rationale is fiction.
34+
35+Also update `current.md` when a *new* problem is found — an unfinished item, a
36+shortcut taken, a hole opened. Carry those forward explicitly at milestone rollover
37+rather than letting them vanish.
38+
39+Skip all of this for typos, formatting, and dependency bumps.
40+
41+## Working style
42+
43+- **Commit directly to `main`.** No feature branches — solo repo. Cleanliness comes
44+ from small, self-contained commits that each compile, not from branching.
45+- Small steps. Build up slowly; prefer a working increment over a big drop.
46+- Explain *why* in commit messages, not just what.
47+
48+## Conventions
49+
50+Full detail in `plans/architecture.md`. The short version:
51+
52+- **Layers:** `domain` (no knowledge of HTTP/SQL/git/Topcoat) → `application` (use
53+ cases and ports) → `infrastructure` (adapters, web). Dependencies point inward.
54+- **Every use case takes an `Actor`** and enforces authorization before any side
55+ effect — one place, reachable from a page, an `/api` route, or a future transport.
56+- **Typed IDs**, never raw `String` for entity references.
57+- **`new()` validates, `from_trusted()` doesn't.** Storage adapters use
58+ `from_trusted`; re-validating stored rows makes a tightened rule unreadable.
59+- **`from_str` returns `Result`, never `Option`.** A silently-defaulted enum surfaces
60+ later as the wrong permissions.
61+- **Every repository port gets two implementations** — in-memory (what makes use cases
62+ testable without a database) and SQLite.
63+- Request helpers are **functions taking `cx`**, not middleware or extractors. A page
64+ that forgets to call one gets nothing; a route added without middleware silently
65+ gets someone else's data.
66+- Safe Rust only. No `unsafe`.
67+
68+## Before saying it's done
69+
70+```bash
71+cargo test
72+cargo clippy --all-targets # expect zero warnings
73+cargo fmt
74+```
75+
76+Report counts accurately — don't state a test number without running it.
77+
78+Verify behaviour rather than asserting it. A passing unit test is not evidence that a
79+page works; the session-cookie bug passed every test and failed silently in the
80+browser. Say plainly what was checked and what wasn't.
81+
82+## Gotchas
83+
84+- **Topcoat 0.5 needs rustc ≥ 1.95.** On older toolchains `cargo add topcoat` silently
85+ resolves to an empty `topcoat v0.0.0` placeholder instead of failing.
86+- **Topcoat is very new** (first release 2026-07-22) and expects breaking changes.
87+ Check its docs on GitHub rather than assuming an API.
88+- **`STEID_INSECURE_COOKIES=true`** is set in a gitignored `.env` for local dev,
89+ because a `Secure` cookie is dropped silently over plain-HTTP localhost. Never
90+ deploy it.
91+- **The setup token is in memory only**, so every restart — including each `topcoat
92+ dev` rebuild — mints a new one.
93+- Don't leave background servers running; the user drives the app.