Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
172 commits
Select commit Hold shift + click to select a range
6a0ca66
docs(.design): add overhaul kickoff docs
rainxchzed May 21, 2026
d001b65
refactor: drop SponsorScreen, prep nav for redesign
rainxchzed May 21, 2026
8fd0834
feat(theme): add design tokens for 4 palettes
rainxchzed May 21, 2026
167a85d
feat(theme): swap to Nord/Cream/Forest/Plum palettes
rainxchzed May 21, 2026
d23f8df
feat(theme): swap fonts to Fraunces + Inter Tight + JBM
rainxchzed May 21, 2026
5943de2
feat(theme): add composition locals for token surfaces
rainxchzed May 21, 2026
a026dbe
feat(theme): add ThemeMode unified two-axis persistence
rainxchzed May 21, 2026
f2660a4
feat(vocabulary): add silent + expressive primitives
rainxchzed May 21, 2026
7c530f9
feat(components): WonkySquircleShape + 4 button variants
rainxchzed May 21, 2026
e4c5b55
feat(components): chips, section header, banner, accent resolver
rainxchzed May 21, 2026
a2f8e75
feat(components): cards (lead/compact/row), vital signs, wax-seal trust
rainxchzed May 21, 2026
a8bce32
feat(components): overlays (sheet, dialog, toast, fullscreen, dropdown)
rainxchzed May 21, 2026
a63004d
feat(chrome): Cookie BottomNav, Desktop drawer, Library label
rainxchzed May 21, 2026
2b17908
feat(onboarding): 3-step first launch + drawer Library fix
rainxchzed May 21, 2026
5245385
fix(onboarding): one-shot persistence read + system bars padding
rainxchzed May 21, 2026
093eac4
feat(onboarding): wire real permission requests + listed rows
rainxchzed May 21, 2026
1da7c3a
feat(home): multi-section state, actions, drop legacy mappers
rainxchzed May 21, 2026
740214d
feat(home): parallel section fetches, drop pagination
rainxchzed May 21, 2026
1d282bf
feat(home): section components and long-press sheet
rainxchzed May 21, 2026
c1c0c40
feat(home): rewrite Root to multi-section feed
rainxchzed May 21, 2026
de41bc0
feat(home): Discover topbar, CategoryList route, lead pill, accent rings
rainxchzed May 21, 2026
a0c72fa
fix(home): sub-day relative time labels in card pills
rainxchzed May 21, 2026
9fa83f0
feat(vocabulary): swap to 14 canonical topic codes + new glyphs
rainxchzed May 21, 2026
6d7810f
feat(vocabulary): add privacy topic glyph (eye + strikethrough)
rainxchzed May 21, 2026
5088ad8
fix(home): fetch full repo data for starred section via DetailsReposi…
rainxchzed May 21, 2026
6e8d2f7
fix(home): keep starred fetch in-module via HomeRepository.getReposit…
rainxchzed May 21, 2026
d207b05
build: cleanup gradle files — drop empty source sets + unused profile…
rainxchzed May 21, 2026
9c59721
feat: rip telemetry, device-identity, and analytics opt-in entirely
rainxchzed May 21, 2026
d39e2f9
chore: strip comments and KDoc from all Kotlin sources
rainxchzed May 21, 2026
abd39a0
refactor(network): lazy async ProxyManager bootstrap, drop runBlockin…
rainxchzed May 21, 2026
cfb29db
refactor(home): viewmodel-derived HomeRepoCardUi, inline composables,…
rainxchzed May 22, 2026
f632657
chore: drop unused pushed_at field
rainxchzed May 23, 2026
49e1624
feat(strings): add design-refresh resource keys
rainxchzed May 23, 2026
e1836b4
feat(theme): swap to Geist family, drop italic
rainxchzed May 23, 2026
0e05bd5
feat(color): off-thread avatar dominant color cache
rainxchzed May 23, 2026
68dd7b5
feat(vocabulary): real Apple and Tux platform glyphs
rainxchzed May 23, 2026
67b8792
feat(core): RepoStripeCard, FloatingPill, chips, Ember palette
rainxchzed May 23, 2026
e511763
feat(adaptive): list-detail scaffold with resizable divider
rainxchzed May 23, 2026
bee29ea
feat(overlays): Apple-style GhsDropdownMenu, dialog polish
rainxchzed May 23, 2026
1649023
fix(core): replace Unicode chevrons with vector icons
rainxchzed May 23, 2026
f3f150f
fix(home/data): preserve availablePlatforms in fan-out
rainxchzed May 23, 2026
099e1a5
feat(home): redesigned cards with avatar accent and platform glyphs
rainxchzed May 23, 2026
5c42486
feat(apps): floating topbar, Apple dropdowns, outlined rows
rainxchzed May 23, 2026
2efc645
feat(apps): updates banner and ready-to-install section
rainxchzed May 23, 2026
95b9f46
feat(details): hero header, two-layer state, inner About+WhatsNew routes
rainxchzed May 23, 2026
7982db5
feat(nav): adaptive two-pane on Home, Search, Library
rainxchzed May 23, 2026
3030bb8
chore: strip stale italic from chrome and onboarding
rainxchzed May 23, 2026
9de318a
feat(search): scroll-collapsing topbar (wip)
rainxchzed May 23, 2026
3261b42
chore(whatsnew): note design overhaul, two-pane, platform fix
rainxchzed May 23, 2026
b3a8a62
revert(whatsnew): drop misplaced 1.9.0 bullets from 17.json
rainxchzed May 23, 2026
c26bc10
chore: bump to 1.9.0 versionCode 19
rainxchzed May 23, 2026
2afa549
feat(whatsnew): 1.9.0 design overhaul and two-pane
rainxchzed May 23, 2026
be53fe8
fix(overlays): soften dropdown shadow 18dp to 6dp
rainxchzed May 23, 2026
a8306fa
fix(apps): last-checked label uses onSurfaceVariant
rainxchzed May 23, 2026
15e8834
feat(details): move translation into About and WhatsNew inner pages
rainxchzed May 23, 2026
43d68aa
fix(home/lead): boost light-theme contrast and warmth
rainxchzed May 23, 2026
d8bb21b
fix(home/lead): use Ember Ash ink on light theme, drop green clash
rainxchzed May 23, 2026
d7171d4
fix(home/lead): solid Ember Ash bg, white ink, theme-agnostic
rainxchzed May 23, 2026
ab88a41
fix(details/topbar): swap share to browser, ripple-clip pills
rainxchzed May 23, 2026
3844347
fix(details/header): auto-shrink long app names to fit
rainxchzed May 23, 2026
d5a7daf
feat(details/owner): show display name with @handle
rainxchzed May 23, 2026
ac465c3
feat(details): redesign SmartInstallButton with proper ripple and inl…
rainxchzed May 23, 2026
a216967
chore(details): strip dead translation params from sections
rainxchzed May 23, 2026
97146c4
chore(details): drop orphan TranslationControls, outlined LinkedRepoB…
rainxchzed May 23, 2026
10504d4
fix(details/whatsnew): drop !! on translatedText
rainxchzed May 23, 2026
affe7cf
feat(search): floating-pill topbar, outlined banners, drop scroll-col…
rainxchzed May 23, 2026
9244075
feat(search): consolidate filters into single sheet with active chips…
rainxchzed May 23, 2026
4814ce9
feat(search): compact RepositoryCard + readable result count
rainxchzed May 23, 2026
0289298
feat(auth): outlined cards, pill buttons, mono device code, collapsed…
rainxchzed May 23, 2026
1738d40
feat(tweaks): two-axis theme picker, outlined vocab sweep
rainxchzed May 23, 2026
4b06a4e
feat(profile): outlined vocab, wire Tweaks entry, dev-profile refresh
rainxchzed May 23, 2026
08451e0
docs(tweaks): P12.5 redesign spec and research
rainxchzed May 23, 2026
54429a2
feat(core): persist restart-required reasons
rainxchzed May 23, 2026
493fe7c
feat(core): proxy master config and per-scope useMaster
rainxchzed May 23, 2026
47b6412
feat(nav): add Tweaks sub-screen routes
rainxchzed May 23, 2026
b21e8b1
feat(tweaks): hub-and-spoke shell with search and restart banner
rainxchzed May 23, 2026
0601606
feat(tweaks): shared sub-screen scaffold with restart banner
rainxchzed May 23, 2026
f409e23
feat(tweaks): Appearance sub-screen
rainxchzed May 23, 2026
ce44001
feat(tweaks): Language sub-screen with searchable list
rainxchzed May 23, 2026
183ca67
feat(tweaks): Storage sub-screen for downloaded APKs
rainxchzed May 23, 2026
458efa9
feat(tweaks): App info and Licenses sub-screens
rainxchzed May 23, 2026
8b94912
feat(nav): wire Wave 2 Tweaks sub-screens
rainxchzed May 23, 2026
c0534b6
feat(tweaks): master proxy state actions and handlers
rainxchzed May 23, 2026
061b5ce
feat(tweaks): Connection sub-screen with main proxy and per-scope ove…
rainxchzed May 23, 2026
1818e13
feat(nav): wire Connection sub-screen
rainxchzed May 23, 2026
eb15183
feat(core): telemetry opt-out preference
rainxchzed May 23, 2026
38658e4
feat(tweaks): privacy state actions and handlers
rainxchzed May 23, 2026
a56276d
feat(tweaks): Privacy sub-screen with telemetry opt-out
rainxchzed May 23, 2026
80c5158
feat(tweaks): Update behavior sub-screen
rainxchzed May 23, 2026
c1c1a4c
feat(tweaks): Sources sub-screen for mirror and custom forges
rainxchzed May 23, 2026
6ce9d12
feat(tweaks): Translation sub-screen
rainxchzed May 23, 2026
04222d2
feat(tweaks): Install method sub-screen with desktop empty state
rainxchzed May 23, 2026
c6f768f
feat(nav): wire Wave 4 Tweaks sub-screens
rainxchzed May 23, 2026
dc43479
chore(tweaks): retire dead section files
rainxchzed May 23, 2026
960b992
chore(tweaks): rename labels and drop ALLCAPS section headers
rainxchzed May 23, 2026
0d8653d
feat(deeplink): tweaks app-info and licenses routes
rainxchzed May 23, 2026
21fa4bc
feat(desktop): Help menu and macOS about handler
rainxchzed May 23, 2026
661c25e
fix(tweaks): drop duplicate section headers inside sub-screens
rainxchzed May 23, 2026
462c972
feat(tweaks): per-scope proxy mini-editor inside override row
rainxchzed May 23, 2026
b54c091
fix(tweaks): mode pills wrap with FlowRow, trim button labels
rainxchzed May 23, 2026
a9f1a81
refactor(tweaks): move Hidden repositories from Updates to Privacy
rainxchzed May 23, 2026
af7cfa7
feat(tweaks): expressive per-row accent colors on entry tiles
rainxchzed May 23, 2026
a5c21b0
feat(core): GhsTextField squircle input vocab, swap into Connection form
rainxchzed May 23, 2026
d202a17
refactor: swap OutlinedTextField for GhsTextField across app
rainxchzed May 23, 2026
abffd89
feat(core): GhsButton canonical with variants, swap into Connection
rainxchzed May 23, 2026
0a0779c
refactor(ui): swap Material3 buttons for GhsButton across app
rainxchzed May 23, 2026
9c76a9e
fix(ui): mute Primary GhsButton in dark mode for issue #665
rainxchzed May 23, 2026
8b720bb
feat(core): GhsTextField minLines maxLines readOnly keyboardActions
rainxchzed May 23, 2026
cd8b49a
feat(core): GhsButton content slot, clear 7 TODO sites
rainxchzed May 23, 2026
73ef8db
feat(tweaks): paste full URL fast path for master proxy
rainxchzed May 23, 2026
1611c35
feat(tweaks): 3-endpoint parallel master proxy test
rainxchzed May 23, 2026
fe0d4b6
feat(core): v2 master proxy migration with plurality vote
rainxchzed May 23, 2026
63011c4
feat(tweaks): plural strings for custom forges and other counts
rainxchzed May 23, 2026
0a69b19
feat(p14): outlined Radii.row vocab for ExpressiveCard, consistent to…
rainxchzed May 24, 2026
5cadf96
feat(p14): outlined row vocab + StatChip for Favourites Starred Recen…
rainxchzed May 24, 2026
d04ea0e
refactor(p15): outlined row vocab and Ghs primitives across sub-screens
rainxchzed May 24, 2026
01fe6b0
feat(p16): outlined section containers and accent tile in ApkInspectS…
rainxchzed May 24, 2026
f7a3d22
feat(p16): trim sheet padding, long-press copy on identity fields
rainxchzed May 24, 2026
48ef92d
i18n: externalize Tweaks redesign hardcoded English strings
rainxchzed May 24, 2026
0df88a9
chore(p17): retire deprecated fraunces and jetbrainsMono refs
rainxchzed May 24, 2026
c95279b
chore(i18n): drop stale strings across English and 12 locales
rainxchzed May 24, 2026
0d433bc
i18n: translate 12 locales to 100% parity
rainxchzed May 24, 2026
a3e0a92
i18n(ru): normalize to informal ты register
rainxchzed May 24, 2026
c9f1c80
i18n: dedupe hidden_repositories_count to plurals across all locales
rainxchzed May 24, 2026
94e3835
feat(tweaks): community socials showcase in App info
rainxchzed May 25, 2026
56c84b7
i18n: translate socials strings into 12 locales
rainxchzed May 25, 2026
67d2683
tweaks(licenses): load library list from JSON asset
rainxchzed May 25, 2026
f648835
build: add printRuntimeDependencies audit task
rainxchzed May 25, 2026
464813d
core: lift hub primitives from tweaks to core
rainxchzed May 25, 2026
eda3bd2
feat(profile): hero card + sectioned hub redesign
rainxchzed May 25, 2026
4483bdb
i18n(profile): translate Library/Updates/Account to 12 locales
rainxchzed May 25, 2026
79ad4b9
feat(chrome): unify bottom-nav topbar style
rainxchzed May 25, 2026
acc5e95
core(theme): animate colorScheme transitions
rainxchzed May 25, 2026
b988a79
feat(tweaks): refactor appearance into mode/palette/display sections
rainxchzed May 25, 2026
a55a767
i18n(appearance): translate Mode/Display to 12 locales
rainxchzed May 25, 2026
b90dce5
feat(tweaks): restyle palette swatch as mini-ui preview
rainxchzed May 25, 2026
f9f4b3f
feat(theme): add dynamic color palette for Android 12+
rainxchzed May 25, 2026
17bfbb6
i18n(theme): translate Dynamic palette name to 12 locales
rainxchzed May 25, 2026
bd189a4
feat(desktop): cap content width on wide windows
rainxchzed May 25, 2026
88d4d64
fix(proxy): auto-save system/none, optimistic use-main toggle
rainxchzed May 25, 2026
6711b9e
fix(tweaks): hide installs/updates section on desktop
rainxchzed May 25, 2026
fc7fdb5
fix(profile): logout dialog uses GhsConfirmDialog
rainxchzed May 25, 2026
d4ad23f
l10n: cleanup single quote escaping across multiple locales
rainxchzed May 25, 2026
47e2f09
build: use sequences in printRuntimeDependencies task + clean up types
rainxchzed May 25, 2026
d5c2fb0
feat: remove telemetry completely
rainxchzed May 25, 2026
c19a3ab
fix(tweaks): tighten hosttokens spacing
rainxchzed May 25, 2026
1e99f33
i18n(auth): extract more-options labels
rainxchzed May 25, 2026
a953125
i18n(auth): translate more-options labels to 12 locales
rainxchzed May 25, 2026
9a898bd
feat(tweaks): discovery platforms picker in Sources
rainxchzed May 25, 2026
ac99a55
i18n(tweaks): translate discovery platforms strings to 12 locales
rainxchzed May 25, 2026
bca6294
feat(feedback): platform-aware sheet, dialog on desktop
rainxchzed May 25, 2026
804dfc8
feat(feedback): pill chips for category and topic selectors
rainxchzed May 25, 2026
b7a0701
feat(feedback): include theme palette and mode in diagnostics
rainxchzed May 25, 2026
91f611c
feat(feedback): prepend category and topic to issue body
rainxchzed May 25, 2026
f90e47b
feat(appinfo): brand icons for community tiles via simpleicons
rainxchzed May 25, 2026
53d5e91
refactor(ia): move app info from tweaks to profile as about
rainxchzed May 25, 2026
bf46dca
i18n(profile): translate About row to 12 locales
rainxchzed May 25, 2026
afee60d
tweaks: update privacy policy, mastodon, and contact email URLs
rainxchzed May 25, 2026
5f85498
feat(devprofile): hero card, identity rail, contribution chart, click…
rainxchzed May 25, 2026
3f7ff9a
feat(devprofile): native compose contribution calendar
rainxchzed May 25, 2026
01bda3e
feat(devprofile): split has-releases vs installable filters, DS pill …
rainxchzed May 25, 2026
660350f
i18n(devprofile): translate filter strings to 12 locales
rainxchzed May 25, 2026
28eee40
fix(theme): tint dynamic palette surfaces toward accent
rainxchzed May 25, 2026
dd02ec9
fix(theme): dynamic surfaces lower than containers for contrast
rainxchzed May 25, 2026
cdbb2f6
fix(devprofile): hide contribution chart for orgs
rainxchzed May 25, 2026
c99dfd5
feat(devprofile): show latest release date on repo cards
rainxchzed May 25, 2026
13c8be2
feat(tweaks): update interval slider up to 30 days
rainxchzed May 26, 2026
77e8d4f
i18n(tweaks): translate interval strings to 12 locales
rainxchzed May 26, 2026
7604ddc
feat(anim): nav slide transitions + lazy list animateItem on home
rainxchzed May 26, 2026
7d5fdaa
feat(anim): shared element container transform repo card to details
rainxchzed May 26, 2026
6681271
revert(anim): drop shared element wrap caused blank load delay
rainxchzed May 26, 2026
70e803f
feat(anim): direction-aware bottom nav transitions
rainxchzed May 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
166 changes: 166 additions & 0 deletions .design/BACKEND-REFINEMENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# Backend Refinements — Design Overhaul

Hand this to your backend coding agent. Every item is a field/endpoint/storage gap surfaced during design handoff analysis. Frontend ships with fallbacks for unfulfilled items, but full design fidelity requires these.

Origin: `~/Downloads/handoff 4/DESIGN.md` §14 + agent specs (`.design/UX-AUDIT.md`, `UX-ARCHITECTURE.md`, `UI-SPEC.md`).

## Priority legend

- **P0** — Blocks a core primitive from rendering correctly. Frontend uses neutral fallback.
- **P1** — Enables a richer signal. Frontend renders partial state until backend lands.
- **P2** — Nice-to-have polish.

---

## R1 — `trendingScore` (P0)

**Field:** `Repository.trendingScore: Float?` (or `Int?` rank position)
**Where used:** Trending section on Home (DESIGN.md §9.3 / §10.1). Drives the `#1 / #2 / #3` rank chip.
**Today:** Sample API returned `null`. Frontend currently uses a local affinity-`score` proxy in `HomeRepositoryImpl.kt:571-604`.
**Need:** Server-side ranking (e.g. release count × stars × freshness × velocity in last 7d). Stable per request; cache TTL ≥ 1h. Position (1, 2, 3…) is preferred over percentage to honor DESIGN.md §11 "no invented percentages."

## R2 — `popularityScore` (P0)

**Field:** `Repository.popularityScore: Int?` (rank position)
**Where used:** "Most popular" section on Home. Drives the rank numbers (Fraunces italic, opacity 0.55).
**Today:** Sample returned `null`. Frontend sorts by `stargazersCount` locally.
**Need:** Server-side all-time rank. Same caching as trending. Independent of time window.

## R3 — Per-app accent color (P1)

**Field:** `Repository.accent: { hex: String, lightTint: String, darkTintAlpha: Float }?`
**Where used:** Lead card bg tint, FreshnessRing outer, install-panel bloom, Apps row tinted leading icon.
**Today:** No field. Frontend will resolve in this order (per UX-Architecture §7): backend → topic-derived → language-derived → blue fallback.
**Backend opportunity:** Run a color-thief / palette extraction on `avatarUrl` once at index time; persist `{ hex, lightTint, darkTintAlpha }`. Saves CPU on every device + stays consistent across devices. **Deferred per D5** — frontend ships topic/language fallback first. Re-evaluate after overhaul lands.

## R4 — Sub-day release recency (P2)

**Field:** `Release.publishedAtUtcSeconds: Long` (in addition to current `publishedAt: Instant`)
**Where used:** FreshnessRing for releases <24h. Currently rounds to "1 day ago"; design wants "5 hours ago" granularity for the Hot bucket.
**Today:** `publishedAt: Instant` exists — frontend can derive seconds locally. **No backend change required if backend already returns ISO-8601 with seconds precision.** Confirm.

## R5 — Maintenance state (commit recency) (P1)

**Field:** `Repository.lastCommitAt: Instant?` or `Repository.daysSinceLastCommit: Int?`
**Where used:** Heartbeat animation period (active 1.4s / recent 2.4s / quiet 4.2s / dormant none — per DESIGN.md §6.1).
**Today:** Repository has `updatedAt` (last metadata update) but that's not commit recency. GitHub API exposes `pushed_at` — pipe through.
**Need:** Backend persists + serves `pushed_at` (default branch HEAD timestamp) per repo. Refresh hourly or on release.

## R6 — Mirror health for `SignalBars` (P0)

**Field:** Per-mirror `health: { latencyMs: Int, lossPercent: Float, lastCheckedAt: Instant }`
**Where used:** Mirror picker — `SignalBars` (4 ascending bars, WiFi-style) shows mirror quality.
**Today:** GHS pings mirrors client-side (existing `AutoSuggestMirror` logic). Lives on device, not in `MirrorsRepository`.
**Need (backend):** Optional — backend-aggregated health metrics across users would improve cold-start UX. Not required if client-side latency probe stays.

## R7 — Expected APK signing fingerprint (P0)

**Field:** `Repository.signingFingerprint: { sha256: String, source: "first_install" | "publisher_declared" }?`
**Where used:** Wax-seal trust card (DESIGN.md §7.8). Cracked-seal red state requires comparing installed APK fingerprint to expected.
**Today:** No "expected" fingerprint stored anywhere. Cracked-seal state can never fire.
**Need:**
- On-device: persist fingerprint of first successful install per `InstalledApp` (Room schema addition). Subsequent installs compare against this.
- Optional backend: publisher-declared fingerprint (maintainer registers via dashboard) — out of scope for this overhaul unless backend wants it.

## R8 — Translation cache persistence (P2)

**Field:** Backend-side translation cache keyed by `(target_lang, version_tag, repo_id)`.
**Where used:** Inner Detail screen language toggle. Hot path: user clicks "Translate to es", waits for provider response.
**Today:** Client-side in-memory cache only (kills on app restart).
**Need:** Either (a) backend caches translations and serves them via `/v1/translate/cache` so cold-start re-opens are instant, or (b) client persists to Room (already aligned with KSafe stack — frontend can do this).
**Recommendation:** Client-side persistence to Room is simpler. Skip backend cache unless multi-device sync is desired.

## R9 — `permissionRisk` summary (P1)

**Field:** `Repository.permissionRisk: "low" | "moderate" | "high"?`
**Where used:** Vital signs grid (Permissions tile) on Detail. `PermDot` color (green/amber/red).
**Today:** Frontend computes locally from APK Inspect results (Android only). Desktop can't show — needs backend.
**Need (backend):** When scanning a release's APK assets, classify by protection-level groups (Android docs: normal/signature/dangerous). Cache per `(repoId, releaseTag)`. Required for Desktop parity.

## R10 — `licensePosture` from SPDX (P1)

**Field:** `Repository.licensePosture: "copyleft" | "permissive" | "unknown"`
**Where used:** `LicensePosture` glyph (Filled © tile vs dashed · tile).
**Today:** `Repository.license` is a free-text string today. Frontend has hardcoded mapping in tokens.json (`licenses.copyleft`, `licenses.permissive`).
**Need:** Backend normalizes to SPDX identifier on indexing. Frontend uses the tokens.json map. **No backend change needed if license already SPDX.**

## R11 — `downloads` field (P1)

**Field:** `Repository.totalDownloads: Long` (sum across all release assets)
**Where used:** `DownloadWeight` primitive (radius is log10(downloads)) + meta line "4.8M dl" on Detail.
**Today:** Existing Forgejo path aggregates client-side. GitHub doesn't expose easily — current GHS backend likely already proxies.
**Need:** Confirm `totalDownloads` populated for both GitHub + Forgejo paths.

## R12 — `topics` field (P1)

**Field:** `Repository.topics: List<String>`
**Where used:** TopicGlyph row (up to 3, mapped via `tokens.json.topicGlyphs.supported` + `topicAliases`).
**Today:** GitHub API returns topics; confirm backend forwards them. Forgejo `/repos/topics` endpoint exists.
**Need:** Both branches expose `topics` consistently. If topic count is high, prioritize ones in our supported map.

## R13 — `pushedAt` vs `updatedAt` clarity

**Field naming:** Distinguish "last metadata change" (`updatedAt`) from "last commit" (`pushedAt`).
**Today:** `Repository.updatedAt` ambiguous in our API.
**Need:** Rename or split — UX-Audit flagged this as confusing.

## R14 — Backend support for accent override on a per-repo basis (P2)

**Field:** Allow maintainer-published `accent: {hex, lightTint, darkTintAlpha}` overrides.
**Where:** Some apps have brand colors that don't match topic/language fallback. Maintainer should be able to opt in.
**Today:** No mechanism.
**Need:** Out of scope unless backend wants. Frontend's fallback chain (topic → language → blue) is acceptable for v1.

---

## Endpoint additions needed

| Endpoint | Purpose | Priority |
|----------|---------|----------|
| `GET /v1/repo/{owner}/{repo}/trending-rank` | Returns `{ rank: Int, lastComputedAt: Instant }` if repo in top-100 trending. Else 404. | P0 |
| `GET /v1/repo/{owner}/{repo}/popularity-rank` | Same shape, all-time. | P0 |
| `GET /v1/repo/{owner}/{repo}/permissions-summary` | Returns `{ posture: low|moderate|high, dangerous: List<String>, sensitive: List<String> }` for latest release. | P1 |
| `GET /v1/translate/cache?lang=&version=&repo=` | Returns cached translation or 204. Skip if going Room-only. | P2 |

---

## Data model summary

Backend `Repository` payload after refinements should have these new/clarified fields:

```jsonc
{
"id": 123,
"owner": "...",
"name": "...",
// ... existing fields ...

// NEW or clarified
"trendingScore": 1, // rank position in trending (nullable)
"popularityScore": 47, // rank position all-time (nullable)
"pushedAt": "2026-05-20T...",// last commit (DISTINCT from updatedAt)
"totalDownloads": 4843201,
"topics": ["self-hosted", "photos"],
"licensePosture": "copyleft", // server-normalized from SPDX
"permissionRisk": "moderate", // optional pre-computed summary
"accent": null // deferred — null until D5 reversed
}
```

---

## Frontend fallback behavior (what ships without backend changes)

Per UI-SPEC.md §5 Data Honesty Audit Hooks:

- `trendingScore` null → drop rank chip; sort by local affinity
- `popularityScore` null → sort by stars; drop rank number
- `accent` null → topic → language → blue fallback
- `pushedAt` null → use `updatedAt` (with caveat in Heartbeat label)
- `mirrorHealth` null → client-side ping
- `signingFingerprint` not stored locally → Wax-seal stays in "Unsigned" open state forever
- `permissionRisk` null → derive on Android via APK Inspect; show "—" on Desktop
- `licensePosture` SPDX missing → "unknown" → dashed neutral tile
- `topics` missing → no TopicGlyph row

Nothing fabricated. Missing primitives just don't render.
127 changes: 127 additions & 0 deletions .design/DECISIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# Design Overhaul Decisions

Locked decisions before Phase 0. Source: maintainer answers during kickoff session (2026-05-21).

## D1 — Bottom nav 5 → 4

Drop **Tweaks** tab from bottom nav. Reachable via Profile → Settings (already wired).
Keep Home / Search / Apps / Favourites.
Override: handoff's 3-tab + Search-FAB rejected as too disruptive to muscle memory.

## D2 — Noto fonts

Bundle **Latin-only** Fraunces, Inter Tight, JetBrains Mono with the app.
Non-Latin scripts (CJK / Devanagari / Arabic / Hebrew / Thai etc.) fall back to system fonts.
Modern Android / macOS / Windows ship Noto-like coverage; Linux may show tofu (acceptable risk).
Total bundled font weight target: ≤ 4 MB across all three families.

## D3 — AppTheme migration map

Legacy `AppTheme` enum → new `Palette`:
- `OCEAN` → `NORD`
- `SLATE` → `NORD`
- `PURPLE` → `PLUM`
- `FOREST` → `FOREST`
- `AMBER` → `CREAM`

One-time migration on first launch after upgrade. Surface a non-blocking banner ("Themes refreshed — try the new palettes in Tweaks") via a new one-shot flag in `TweaksRepository`.

## D4 — Wonky-squircle scope

Full DESIGN.md coverage: hero CTAs, lead cards, search input, bottom sheets, confirm dialogs, toasts, device-code box, and any "wonky" call-out in the handoff. Implement as custom `WonkySquircleShape : Shape` using `Path.arcTo` with elliptical bounding rects. No fallback to `RoundedCornerShape`; the asymmetric character is brand-defining.

## D5 — Sponsor cut

Cut `SponsorScreen` entirely. Remove:
- Route `GithubStoreGraph.SponsorScreen`
- Profile sponsor row (`feature/profile/.../Options.kt:114`)
- Nav wiring in `AppNavigation.kt`
- Any deep links / strings

Aligns with MIGRATION.md "no donations in UI."

## D6 — Desktop two-pane Library

Build during **Phase 4**. Desktop `feature/apps/` adopts list (380dp) + detail (660dp) two-pane per DESIGN.md §8.3. Android remains single-pane → full-screen detail.
Existing single-pane code path retained behind the same composable signature; platform branch picks layout.

## D7 — AMOLED mode

`ThemeMode` enum = `LIGHT` / `DARK` / `AMOLED` / `SYSTEM`. AMOLED is a Dark sub-mode (resolves to Dark when `SYSTEM = dark`). All 4 palettes ship an AMOLED variant — pure-black `bg` (#000) + dimmed `surface` (lift one notch up). Adds ~30% token surface but contained to `Tokens.kt`.

## D8 — Visual reference

Open `desktop-app.html` / `mobile-app.html` / `design-system.html` **per phase** as side-by-side reference. Not opened upfront en-masse.

---

## Carry-over from agent specs (no decision needed — accepted as written)

- Tokens delivered as hand-written `Tokens.kt`, not Gradle codegen (UX-Architect §1).
- Single `core/presentation/.../vocabulary/` module hosts all primitives (UX-Architect §8).
- Per-app accent at UI mapper layer, not domain model (UX-Architect §7).
- `GhsTheme` composable wraps `MaterialExpressiveTheme` + 6 composition locals (UX-Architect §2).
- Build order: Phase 0 → 8 per UX-Architecture sequencing.
- Vocabulary uses `ImageVector.Builder` + `Canvas`; Material Symbols painters where applicable (UX-Architect §9).

## D9 — Coverage policy

Design handoff covers only some screens (Home, Library, Detail incl. Inner About/What's-new, Search, APK Inspect, overlay surfaces, Tweaks fragments). Many screens are uncovered. Policy: **plan each uncovered screen before implementing**, extrapolating from DESIGN.md primitives + patterns + tokens. Ask clarification questions before building.

## D10 — Motion scope (rich)

Beyond DESIGN.md §6.2 baseline (Heartbeat + 120ms tap + palette/mode crossfade):
- Shared-element transitions (Compose `SharedTransitionLayout`) on avatar → Detail hero
- Spring physics on press / release (`spring(dampingRatio = MediumBouncy)`)
- List item enter/exit (slide 200ms)
- Parallax on Detail hero scroll
- Skeleton loaders during async fetches

Quick, never blocking user. Spring stiffness defaults: high (300+) so transitions feel snappy.

## D11 — Backend refinements doc

`.design/BACKEND-REFINEMENTS.md` drafted upfront. Hand to backend coding agent in parallel while frontend builds. Frontend ships with fallbacks for any field not yet populated.

## D12 — PR cadence

**One mega-PR** at the end of overhaul. Commits per feature / milestone (atomic). Memory rule (commit msgs ≤10 words) applies. Each commit compiles + runs.

## D13 — Build order

User-directed: **Root + Navigation first**, then **core module fully**, then **feature-by-feature**. Translated to 17 phases — see `MEMORY.md` `project_design_overhaul` and the task list.

## D15 — SponsorScreen full delete

Delete `feature/profile/.../SponsorScreen.kt` composable, its route in `GithubStoreGraph`, nav wire in `AppNavigation`, sponsor row in `feature/profile/.../Options.kt`, and all related strings across 13 locales. No flag, no shim.

## D16 — Apps tab renamed "Library"

Label change only. Route name `AppsScreen` stays (no breaking change for deep links). BottomNav + Drawer label → "Library". String resource updated across 13 locales.

## D17 — Onboarding (3 steps)

New first-launch flow:
1. **Palette pick** — 4 Cookie swatches (Nord/Cream/Forest/Plum) + System/Light/Dark mode default
2. **Sign in (optional)** — entry point to web-OAuth or device-flow or skip
3. **Permissions (Android)** — notifications + install-from-unknown-sources prompts (skip-able)

One-shot. Persisted via `TweaksRepository.onboardingComplete: Boolean`. Skipped on subsequent launches. Lives in `composeApp/` as app-level orchestration (no new feature module — too small).

## D18 — Shared elements: Android only

Use `SharedTransitionLayout` + `sharedElement` modifier (`@OptIn(ExperimentalSharedTransitionApi::class)`) on Android only. Desktop uses standard slide/fade nav transitions via Compose Navigation's `enterTransition` / `exitTransition`. Platform branch via `expect/actual` or runtime platform check.

## D14 — Architecture skills

Source of truth for ViewModel/State/Action/Event/Root/Screen structure, navigation, DI, error handling, testing: `~/.claude/skills/android/*`. Applied to KMP/CMP common code (most patterns platform-agnostic).

---

## Deferred / explicitly out of scope for this overhaul

- Color-thief / server-side accent derivation from avatar (UX-Architect Q6) — use topic + language fallbacks only.
- Translate-the-app (Crowdin pipeline) (UI-Designer §8).
- Material You dynamic color override (themes.md §Disallowed).
- New 5th palette (themes.md §Disallowed).
- Fake trending percentages / "Featured" curation / invented data (DESIGN.md §11).
Loading