Signed by hannaSSH key fingerprint: SHA256:4g9cWhkAAw8gwqhJUcVbSnGEvdGwklW+1Aa/fMUu59k
docs/decisions.md +29 −0
| @@ -555,3 +555,32 @@ re-exports `ssh-key` at a patch level distinct from the workspace's, so the two | |||
| 555 | by key fingerprint, not the SSH username (everyone connects as `git@`); | 555 | by key fingerprint, not the SSH username (everyone connects as `git@`); |
| 556 | `channel_open_session` must explicitly `reply.accept()` in 0.62 or the channel is | 556 | `channel_open_session` must explicitly `reply.accept()` in 0.62 or the channel is |
| 557 | rejected; exec output streams through the `Clone + Send` `Handle` from a task. | 557 | rejected; exec output streams through the `Clone + Send` `Handle` from a task. |
| 558 | |||
| 559 | ## 2026-07-25 — UI refresh: inline icons, Carbon themes, dashboard/explore split, profiles | ||
| 560 | |||
| 561 | **Decision:** Vendor UI glyphs as an inline-SVG `icons` module (Lucide, ISC) with | ||
| 562 | brand marks from Simple Icons (CC0), replacing the emoji glyphs. Rebase the default | ||
| 563 | `dark`/`light` themes on IBM Carbon (Gray 100 / White) as pure `--fb-*` token | ||
| 564 | changes. Split `/` into a signed-in dashboard and a public `/explore` landing (the | ||
| 565 | anonymous landing carries no in-content sign-in button). Give users a profile | ||
| 566 | (display name, pronouns, bio, location, website, GitHub/Mastodon handles) edited at | ||
| 567 | `/settings`, and avatars served from `/avatar/{username}`. | ||
| 568 | |||
| 569 | **Avatar storage:** the bytes live on disk at `{storage.data_dir}/avatars/{id}`; | ||
| 570 | `users.avatar_mime` (nullable TEXT, migration 0002) records the content type and its | ||
| 571 | presence means "serve the file". A NULL falls back to a deterministic FNV-derived | ||
| 572 | 5×5 identicon SVG generated in-process. | ||
| 573 | |||
| 574 | **Alternatives:** an icon font or sprite sheet (extra asset, worse a11y); storing | ||
| 575 | avatar bytes in the DB (BLOB vs BYTEA is not portable across SQLite/Postgres, which | ||
| 576 | § store portability forbids); Gravatar or any remote avatar (a network request from | ||
| 577 | a page, forbidden by §9.5); a single combined home page (the prior behaviour). | ||
| 578 | |||
| 579 | **Rationale:** inline SVG inherits `currentColor`, scales to `1em`, needs no network | ||
| 580 | request, and keeps the "no CDN / no build step" rule. Carbon is a documented, freely | ||
| 581 | usable palette and the swap touches only theme token values, proving the | ||
| 582 | structure-only `base.css` contract. On-disk avatars keep the schema in the portable | ||
| 583 | subset. Uploads are limited to raster types (PNG/JPEG/GIF/WebP, ≤ 1 MiB); SVG upload | ||
| 584 | is refused so no user-supplied markup is ever served, while our own identicons are | ||
| 585 | SVG. Both mutating routes (`POST /settings`, `POST /settings/avatar`) verify the | ||
| 586 | double-submit CSRF token; `/settings` redirects anonymous visitors to `/login`. | ||