steid

@jamesgill /

docs: settle milestone 2 open questions

Settings live at /{handle}/settings -- they belong to the organisation, so
this scales to real orgs in milestone 7 without moving.

Render the full frame from the start, sections included, even while they are
empty. I had leaned towards omitting them as speculative scaffolding; for a
portfolio-first product the shape of the page is part of what is being built,
and a profile rendering almost nothing is a poor start.

Route precedence drops from a blocking spike to an assertion when the route
lands. The reserved list stops a user owning "auth", but it does not stop the
router matching /api/me against /{handle}/{x} and shadowing a real route --
different problem, still worth checking, not worth a separate step.

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

1 file changed+16 −14

plans/current.md+16 −14View file
@@ -21,12 +21,11 @@ Shippable on its own: a public profile that renders signed out.
2121 - [x] Settle URL shape — handles at the root, routes grouped under prefixes
2222 ([0004](decisions/0004-root-handles-grouped-routes.md))
2323 - [x] Reserved-handle denylist in `OrgName::new`; auth routes moved under `/auth/`
24- [ ] **Spike: route precedence.** Does `/auth/login` still win once `/{handle}` exists
25 at the root? Most routers prefer a static segment over a parameterised one, but
26 this is load-bearing and unverified — check before designing around it
27- [ ] Decide `module_router!` vs explicit `#[page]` paths, informed by the spike
24+- [ ] Decide `module_router!` vs explicit `#[page]` paths
2825 - [ ] `PublicProfile` read model + `view_profile` use case — **must not carry email**
29- [ ] `/{handle}` page: renders label and handle, 404 on unknown, case-insensitive
26+- [ ] `/{handle}` page: label, handle, bio, and the section frame; 404 on unknown,
27+ case-insensitive
28+- [ ] Assert `/auth/login` and `/api/me` still route once `/{handle}` exists at the root
3029 - [ ] `/` redirects to the owner's profile once claimed, retiring the placeholder
3130 - [ ] `/api/users/{handle}` — same read model, public JSON
3231
@@ -38,7 +37,7 @@ A profile you can't change is a stub. This is what makes it a portfolio page.
3837 - [ ] Flash messages — the first edit form needs success and failure feedback, and
3938 every form after it inherits whatever we build here
4039 - [ ] `/{handle}/settings` — edit display name and bio, owner only, enforced in the use
41 case
40+ case (settings belong to the org, and this scales to organisations)
4241 - [ ] Owner-only affordances on the profile (edit link)
4342
4443 ### Done when
@@ -54,7 +53,10 @@ on the page. `/api/users/{handle}` returns the same public view.
5453 profile needs its **own** read model; reusing `Identity` would publish the owner's
5554 email address to anonymous visitors. This is the single most likely mistake in this
5655 milestone.
57- **Route precedence** between `/auth/login` and `/{handle}`. Verify, don't assume.
56+- **Route precedence** between static routes and `/{handle}`. The reserved list stops a
57+ user *owning* `auth`, but it does not stop the router matching `/api/me` against
58+ `/{handle}/{x}` and shadowing the real route. Static-over-parameterised is near
59+ universal, so this is an assertion when the route lands, not a blocking spike.
5860 - **Case-insensitive handles.** Storage is `collate nocase` and `OrgName::new`
5961 lowercases, so `/JamesGill` must resolve rather than 404.
6062 - **Authorization on settings** belongs in the use case, taking an `Actor` — not in the
@@ -65,14 +67,14 @@ on the page. `/api/users/{handle}` returns the same public view.
6567 - **Reserve handles early.** Adding to the denylist later is a breaking change for
6668 whoever holds that handle ([0004](decisions/0004-root-handles-grouped-routes.md)).
6769
68### Open questions
70+### Settled
6971
70- **Where do settings live?** `/{handle}/settings` is consistent with grouping and
71 scales to organisations; `/settings` is simpler for a single user but would need
72 another reserved word (already reserved). Leaning `/{handle}/settings`.
73- **Empty sections or none?** Rendering "Repositories (none yet)" makes the frame
74 visible but is speculative scaffolding for things that don't exist. Leaning towards
75 omitting them until the content type lands.
72+- **Settings live at `/{handle}/settings`.** They belong to the organisation, which
73+ scales to real organisations in Milestone 7 without moving.
74+- **Render the full frame from the start**, including sections with nothing in them.
75+ A profile page that renders almost nothing is a poor start for a portfolio-first
76+ product; the shape of the page is part of what is being built, not scaffolding for
77+ it.
7678
7779 ### Carried over — small, unblocked
7880