Bring the README and landing tiles up to what the forge does

7a1d662 · Gabriel Morell · 2026-09-11 04:56

10 files +56 -2
Message
{commit_body(@commit)}

Files changed

modified README.md
+23 −2
@@ -26,10 +26,22 @@ external tools (Forgejo runner, Garage, zot) rather than reinvent them.
26 26 - **Full GFM markdown** with cross-references (`#42`, `#x2a` hex, `owner/repo#42`), GitHub-style alerts, footnotes, task lists, fenced-code syntax highlighting — cached per-render
27 27 - **Language stats**: 0.3em GitHub-style bar on the repo page driven by a per-commit Oban job; click for `/stats/languages` (full table) and `/stats/committers` (commits + churn per author)
28 28 - Per-user editor theme (curated subset of Lumis themes — Dracula, Solarized, Monokai, Tokyo Night, Catppuccin, etc) — separate from the daisyUI page theme
29 +- **Discovery**
30 + - **Dashboard at `/`** for signed-in visitors — PRs waiting on your review (asked of you first, maintainer inference as a fallback), your open PRs and issues, CI, pinned and recently-pushed repos, org invitations. Logged-out visitors get the landing page
31 + - **Topic tags** — up to seven per repo, plus one derived automatically from its primary language and kept current by the stats worker. Browse at `/tags`, filter the repo listing by them
32 + - **Syms** — stars, but with a configurable set of symbols; instance-wide rankings at `/syms`
33 + - Repository and organization listings as cards with filter, sort and scope, paginated and deep-linkable (`/repositories/2`, `/orgs/page/2`)
29 34 - **Collaboration**
30 35 - Issues + comments with Write/Preview tabs, label picker, query-string autofill
31 36 - **Quote-reply** button on every comment — appends `> `-prefixed source with attribution
32 − - Pull requests with mergeability probe, 3-way merge, cross-repo (fork) PRs, line-level diff inline
37 + - **History subpage** on every issue and PR — pushes (with sha pair and commit count), renames, description edits, labels, state changes, reviews, comment edits and moderation, interleaved in one timeline. Body edits fold their before/after into a collapsed diff that renders from the recorded payload, so it survives the comment being deleted
38 + - **Cross-reference backlinks** — writing `#42` leaves a linked entry in *that* item's history, so the relationship reads from both ends. Only genuinely new references record, and a `#42` inside backticks is text rather than a link
39 + - Pull requests with mergeability probe, 3-way merge, cross-repo (fork) PRs, reopen, and a **dedicated code review screen** at `/pulls/:n/files` — the diff gets the whole viewport instead of sharing a column with the discussion
40 + - **Review flow** on its own tab: assigned reviewers (requested by handle, or from chips suggesting who actually reviews in this repo), one standing verdict per reviewer rather than a pile of contradictory rows, and the full log behind a disclosure
41 + - **Line comments** anchored to a file and line, pinned to the head they were written against
42 + - **Suggested changes** — a ```` ```suggestion ```` block renders as the proposed replacement with an Apply button that commits it to the source branch. Refuses rather than guesses: `:stale` if the branch moved since, and the ref update is a compare-and-swap so a concurrent push loses the race instead of being overwritten
43 + - **Per-repo merge rules**, all off by default except the last: block merging while changes are requested, require N approving reviews, and stop authors approving their own PR (on for new repos). Repo admins can override, and an override is recorded as such
44 + - **Editable titles and descriptions** on issues and PRs, plus editable and soft-deletable comments — deletion is soft so the history can still render what was edited before it went
33 45 - Forks + fork-sync (fast-forward CAS) + compare-any-two-refs view
34 46 - **Repository import** from a GitHub org/user, a GitLab group (subgroups included) or user, or any single git URL — `git clone --mirror` per repo on its own background job, with a live progress page and an on-demand "fetch from upstream" re-sync. Git data only; issues and PRs don't come across. Provider tokens are encrypted at rest, handed to `git` out-of-band (never in the clone URL), and wiped when the import finishes
35 47 - Branch protection, deploy keys, webhooks, wikis
@@ -43,12 +55,18 @@ external tools (Forgejo runner, Garage, zot) rather than reinvent them.
43 55 - **Registration modes**: `:open` / `:invite_only` (default) / `:closed`, configurable per-instance
44 56 - **Invites** — single-use tokens with create / list / revoke per user; UI at `/users/settings/invites`
45 57 - **Org visibility**: `public` / `internal` / `private`. Repos can't be more open than their org; tightening an org cascades to over-public repos in one transaction. Public orgs are accessible to anonymous viewers; private orgs require membership.
46 − - **Org members management** at `/orgs/:handle/settings/members` — add by handle or email, change roles, remove, with a last-admin guard so an org can never end up admin-less
58 + - **Org membership by invitation** at `/orgs/:handle/settings/members` — an admin invites by handle or email and the invitee accepts from their dashboard; nobody is added to an org without agreeing. Withdraw a pending invite, change roles, remove members, with a last-admin guard so an org can never end up admin-less
59 +- **Moderation for owners**
60 + - Org and repo admins get their own queue at `/orgs/:handle/settings/moderation` and `/r/:owner/:name/settings/moderation` — reports about *their* content, which previously only an instance admin could see
61 + - **Scoped bans** on local users: a repo admin can stop someone acting in their repo, an org admin across every repo the org owns. Neither reaches further; suspending an account instance-wide stays an instance admin's power
62 + - Bans stop writing — opening issues and PRs, commenting, reviewing — and fold away what the person already wrote in that scope. Hiding happens at render time, so lifting a ban restores everything without rewriting a row
63 + - Optional expiry, with no sweeper to run: a lapsed ban simply stops matching. The row survives as a record of who banned whom, when, why, and who lifted it
47 64 - **Auth & MFA**
48 65 - Magic-link login + email/password
49 66 - **TOTP** (any RFC 6238 authenticator) with QR enrollment + 10 single-use recovery codes
50 67 - **WebAuthn / FIDO2** — hardware security keys (YubiKey, Titan), platform authenticators (Touch ID / Windows Hello), browser passkeys
51 68 - Recovery codes shared across factors; instance-level enforcement with N-day grace period
69 + - **Sudo mode** on every credential-management page — settings, SSH keys, API tokens, two-factor, invites all demand a recent re-authentication, so a stolen session cookie can't enrol its own authenticator or mint a token
52 70 - **Federation (ForgeFed / ActivityPub)**
53 71 - HTTP Signatures on inbound + outbound deliveries; outbound dead-letter after 8 retries
54 72 - Push / ticket / merge / comment activities outbound; per-task hourly key refresh of stale remote actors
@@ -152,6 +170,7 @@ These all live in `config/*.exs`. Key ones:
152 170 | `:registration_mode` | `:open` / `:invite_only` / `:closed` | `:invite_only` |
153 171 | `GitGud.Federation` `federation_mode` | `:allowlist` or `:open` | `:allowlist` |
154 172 | `GitGud.Cache` | Nebulex cache sizing | 50k entries / 200MB |
173 +| `:syms` | Symbols repos can be marked with; `[]` disables the feature | `["⭐", "🚀", "💔", "⁉️", "❤️"]` |
155 174 | `GitGud.Accounts.TwoFactor` `required` / `grace_period_days` | Instance-wide MFA enforcement + grace window | `false` / `14` |
156 175 | `GitGud.Workflows.Workers.CacheEviction` `max_age_days` / `per_repo_max_mb` | `actions/cache` pruning knobs | `90` / `500` / `dry_run: false` |
157 176 | `GitGudWeb.PackagesWebhookController` `shared_secret` | Bearer-token gate on the zot webhook (env: `ZOT_WEBHOOK_SECRET`) | `nil` (open in dev) |
@@ -197,6 +216,8 @@ The federation admin LiveView at `/admin/federation` exposes:
197 216 - instance + actor block CRUD
198 217 - allowlist CRUD with mode toggle
199 218 - open report queue with dismiss / action / forward-to-source actions
219 + (instance-wide; org and repo admins see the reports scoped to their
220 + own content on their own moderation pages)
200 221
201 222 Federated PRs (inbound `Offer`) materialize as local PR rows with
202 223 `source_actor_id` pointing at the remote actor and no `author_id`.
modified lib/git_gud_web/components/landing_components.ex
+25 −0
@@ -67,6 +67,31 @@ defmodule GitGudWeb.LandingComponents do
67 67 title="Moderation up front"
68 68 body="Per-repo interaction policy, quarantine queue, rate limits, peer-block suggestions, and a reversible 'replace with mod message' that keeps the original visible to admins + author."
69 69 />
70 + <.feature
71 + icon="hero-hand-raised"
72 + title="Owners moderate their own ground"
73 + body="Org and repo admins see the reports about their content — not just the instance admin — and can ban someone from one repo or from every repo an org owns. A ban stops them writing and folds away what they already wrote, at render time, so lifting it restores everything."
74 + />
75 + <.feature
76 + icon="hero-check-badge"
77 + title="Reviews that hold a verdict"
78 + body="Assign reviewers, or take a chip suggesting who actually reviews here. One standing verdict each, not a pile of contradictory rows. Optional rules: block merging while changes are requested, require N approvals, stop authors approving their own — admins can override, and the override is recorded."
79 + />
80 + <.feature
81 + icon="hero-code-bracket-square"
82 + title="Suggest a change, apply it"
83 + body="Comment on a line, or propose the replacement in a suggestion block that anyone with write access can commit. Refuses rather than guesses — if the branch moved since, it says so, and the ref update is a compare-and-swap so a concurrent push can't be clobbered."
84 + />
85 + <.feature
86 + icon="hero-clock"
87 + title="History on everything"
88 + body="Pushes, renames, labels, reviews, edits and moderation in one timeline per issue and PR. Body edits fold their before/after into a collapsed diff. Writing #42 leaves a backlink in that item's history, so a reference reads from both ends."
89 + />
90 + <.feature
91 + icon="hero-magnifying-glass"
92 + title="Find things by what they are"
93 + body="Seven topic tags per repo plus one derived from its primary language, browsable at /tags. Syms — stars, but with a set of symbols. Listings filter, sort and paginate with links you can send someone."
94 + />
70 95 <.feature
71 96 icon="hero-finger-print"
72 97 title="MFA + WebAuthn"
modified test/git_gud_web/live/page_live/home_test.exs
+8 −0
@@ -48,6 +48,14 @@ defmodule GitGudWeb.PageLive.HomeTest do
48 48 assert html =~ "Forgejo Actions CI"
49 49 assert html =~ "Federation that works"
50 50 assert html =~ "Invite-gated signups"
51 +
52 + # The tiles added as the forge grew — a stale grid is worse than
53 + # a short one.
54 + assert html =~ "Reviews that hold a verdict"
55 + assert html =~ "Suggest a change, apply it"
56 + assert html =~ "History on everything"
57 + assert html =~ "Owners moderate their own ground"
58 + assert html =~ "Find things by what they are"
51 59 end
52 60
53 61 test "no dashboard leaks to anonymous visitors", %{conn: conn} do

Parents: 6280797