| | @@ -21,19 +21,22 @@ Shippable on its own: a public profile that renders signed out. |
| 21 | 21 | - [x] Settle URL shape — handles at the root, routes grouped under prefixes |
| 22 | 22 | ([0004](decisions/0004-root-handles-grouped-routes.md)) |
| 23 | 23 | - [x] Reserved-handle denylist in `OrgName::new`; auth routes moved under `/auth/` |
| 24 | | −- [ ] Decide `module_router!` vs explicit `#[page]` paths |
| 25 | | −- [ ] `PublicProfile` read model + `view_profile` use case — **must not carry email** |
| 26 | | −- [ ] `/{handle}` page: label, handle, bio, and the section frame; 404 on unknown, |
| 24 | +- [x] Explicit `#[page]` paths for now; `module_router!` still unexamined, and four |
| 25 | + routes is too few to judge it against |
| 26 | +- [x] `PublicProfile` read model + `view_profile` use case — no email field, by design |
| 27 | +- [x] `/{handle}` page: label, handle, bio, and the section frame; 404 on unknown, |
| 27 | 28 | case-insensitive |
| 28 | | −- [ ] Assert `/auth/login` and `/api/me` still route once `/{handle}` exists at the root |
| 29 | | −- [ ] `/` redirects to the owner's profile once claimed, retiring the placeholder |
| 30 | | −- [ ] `/api/users/{handle}` — same read model, public JSON |
| 29 | +- [x] Asserted `/auth/login` and `/api/me` still route with `/{handle}` at the root — |
| 30 | + static beats parameterised |
| 31 | +- [x] `/` redirects to the owner's profile once claimed, retiring the placeholder |
| 32 | +- [x] `/api/users/{handle}` — same read model, public JSON |
| 33 | +- [x] Migration `orgs.bio`, pulled forward so the page had a field to render |
| 31 | 34 | |
| 32 | 35 | ### Phase 2 — make it yours |
| 33 | 36 | |
| 34 | 37 | A profile you can't change is a stub. This is what makes it a portfolio page. |
| 35 | 38 | |
| 36 | | −- [ ] Migration: `orgs.bio` |
| 39 | +- [ ] Decide the styling approach — Tailwind and Topcoat UI, or hand-rolled CSS |
| 37 | 40 | - [ ] Flash messages — the first edit form needs success and failure feedback, and |
| 38 | 41 | every form after it inherits whatever we build here |
| 39 | 42 | - [ ] `/{handle}/settings` — edit display name and bio, owner only, enforced in the use |
| | @@ -46,6 +49,18 @@ Signed out, `/{handle}` renders the owner's display name and handle and nothing |
| 46 | 49 | private. An unknown handle 404s. The owner can set a display name and bio and see them |
| 47 | 50 | on the page. `/api/users/{handle}` returns the same public view. |
| 48 | 51 | |
| 52 | +### Findings — phase 1 |
| 53 | + |
| 54 | +- **`path_param` is an attribute in Topcoat 0.5**, applied to a tuple struct |
| 55 | + (`#[path_param] struct Handle(str);`), not the function-like `path_param!(handle)` |
| 56 | + that the docs on `main` describe. **Read the vendored crate, not GitHub `main`** — |
| 57 | + the framework is two weeks old and the two have already diverged. |
| 58 | +- A `str` inner type yields the raw percent-decoded segment with no parsing, which |
| 59 | + suits validating through `OrgName` and 404ing what fails. |
| 60 | +- **Static routes beat parameterised ones**, so `/auth/login` and `/api/me` still work |
| 61 | + with `/{handle}` registered at the root. Verified, not assumed. |
| 62 | +- Topcoat serves bundled assets from `/_topcoat/assets/…` with content-hashed URLs. |
| 63 | + |
| 49 | 64 | ### Watch for |
| 50 | 65 | |
| 51 | 66 | - **Do not leak email.** `describe_identity` carries email, and `/api/me` returns it — |