| 1 | # Current |
| 2 | |
| 3 | > Keep this file short. One active step, one ordered backlog. Completed work moves to |
| 4 | > [progress.md](progress.md). If this file starts reading like a changelog, it has |
| 5 | > drifted — that's exactly what went wrong last time. |
| 6 | |
| 7 | ## Active: Milestone 0 — Skeleton |
| 8 | |
| 9 | **Goal:** a Topcoat app that boots, serves one page, reads config from env, and opens |
| 10 | a SQLite pool. No domain logic yet. The point is to learn Topcoat's shape before |
| 11 | committing the architecture to it. |
| 12 | |
| 13 | ### Steps |
| 14 | |
| 15 | - [ ] Add `topcoat` 0.5 + `tokio` to `Cargo.toml`; install `topcoat-cli` |
| 16 | - [ ] Get the getting-started hello-world page rendering |
| 17 | - [ ] Work out how `#[page]` / `module_router!` discovery wants the source tree laid |
| 18 | out — this constrains everything after it |
| 19 | - [ ] Config from env via `envy` (`STEID_*`), mirroring `.env.dev` from the previous |
| 20 | attempt (see [runbook.md](runbook.md)) |
| 21 | - [ ] SQLite pool registered as app context; confirm a page can read it via |
| 22 | `app_context::<T>(cx)` |
| 23 | - [ ] Decide the layering question in [architecture.md](architecture.md#open-question-topcoats-data-access-vs-clean-architecture) |
| 24 | — this is the one genuinely open design question and it blocks Milestone 1 |
| 25 | |
| 26 | ### Done when |
| 27 | |
| 28 | `cargo run` (or `topcoat` CLI) serves a page that renders a value read from SQLite, |
| 29 | with config supplied by env. |
| 30 | |
| 31 | ## Backlog |
| 32 | |
| 33 | Ordered. Pull from the top. |
| 34 | |
| 35 | 1. **Milestone 1 — Identity.** Domain model (User, Org, Membership, Actor, Role), |
| 36 | value objects (Email, PasswordHash), typed IDs, repository ports, Argon2 hashing, |
| 37 | registration policy, session cookies. Reference implementation exists and was |
| 38 | solid — port the domain layer, rewrite the web layer. |
| 39 | 2. **Milestone 2 — Repo model.** `Repository` entity, `Visibility`, `create_repo` use |
| 40 | case, bare repo on disk at `{data_dir}/{org}/{repo}.git`. Watch the |
| 41 | DB-plus-filesystem atomicity problem — see |
| 42 | [architecture.md](architecture.md#db-plus-filesystem-writes). |
| 43 | 3. **Milestone 3 — Git over SSH.** `GitProtocolServer` port, `GitBinary` adapter, |
| 44 | embedded russh. Channel-splitting is fiddly; the notes in |
| 45 | [progress.md](progress.md#ssh-channel-bridging) are hard-won. |
| 46 | 4. **Milestone 4 — SSH key auth + authz.** |
| 47 | |
| 48 | ## Open questions |
| 49 | |
| 50 | - **Topcoat is nine days old** (v0.5.0, first release 2026-07-22, breaking changes |
| 51 | expected). Pin the exact version and expect to chase it. Budget time for churn that |
| 52 | isn't feature work. |
| 53 | - Does Topcoat's asset/CSS pipeline coexist with an embedded russh server in one |
| 54 | binary, or does the CLI's watch-and-rebuild model push SSH into a separate process? |
| 55 | Unresolved — affects the embedded-SSH approach and single-binary deploy. |
| 56 | - Topcoat ships Tailwind without Node. That reopens the design system from attempt #1 |
| 57 | that was dropped purely to avoid an npm build step — see [ui.md](ui.md). |