Changelog
All notable changes to shithub are documented here. This project follows Keep a Changelog conventions and Semantic Versioning.
Pre-1.0 versioning: minor versions may break the API. The stability contract begins at v1.0.0; until then, expect changes between minor releases.
Unreleased
Added
- REST API contract (S50 §0).
GET /api/v1/metareturns the server's version stamp and a list of feature capability strings for client-side feature detection. Every/api/v1/*response now carriesX-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset, and (when PAT-authenticated)X-OAuth-Scopes. The 403 scope-reject response also carriesX-Accepted-OAuth-Scopes. Operators tune the API rate-limit budgets viaratelimit.api.authed_per_hour/ratelimit.api.anon_per_hour(defaults: 5000 / 60). - Pagination helper
internal/web/handlers/api/apipage— emits canonical RFC 8288 Link headers (first/prev/next/last) with absolute URLs rooted at the configured public base URL. - REST: user emails (S50 §1).
GET /api/v1/user/emailslists the authenticated user's emails. Optional?verified=true|falsefilter. Scope:user:read. - REST: user SSH keys (S50 §1).
GET/POST /api/v1/user/keysandGET/DELETE /api/v1/user/keys/{id}expose CRUD for git authentication keys. Signing keys are tracked separately by a newkindcolumn onuser_ssh_keysand remain on the HTML surface for now. Scopes:user:readfor GETs,user:writefor mutations. - Capabilities:
user-emails,ssh-keysadded to/api/v1/metaresponse. - REST: repos core (S50 §2).
GET /api/v1/user/repos,GET /api/v1/users/{username}/repos,GET /api/v1/orgs/{org}/repos,GET /api/v1/repos/{owner}/{repo},POST /api/v1/user/repos,POST /api/v1/orgs/{org}/repos,PATCH /api/v1/repos/{owner}/{repo}(description, has_issues, has_pulls, archived, visibility), andDELETE /api/v1/repos/{owner}/{repo}(soft-delete). Visibility-aware listing: a user's/users/{u}/reposshows private rows only to that user; an org's/orgs/{o}/reposshows private rows only to members. Single-repo GETs404for callers who can't see the row (no existence leak). - Capability:
reposadded to/api/v1/meta. - REST: issues + comments + lock (S50 §3).
GET /api/v1/repos/{o}/{r}/issues(with?state=filter andLink:-header pagination),GET /api/v1/repos/{o}/{r}/issues/{number},POST /api/v1/repos/{o}/{r}/issues,PATCH /api/v1/repos/{o}/{r}/issues/{number}(title/body author-gated, state/state_reason policy-gated),GET / POST /api/v1/repos/{o}/{r}/issues/{number}/comments,PATCH / DELETE /api/v1/repos/{o}/{r}/issues/comments/{cid},PUT / DELETE /api/v1/repos/{o}/{r}/issues/{number}/lock. - REST: repo labels (S50 §3).
GET / POST /api/v1/repos/{o}/{r}/labelsandGET / PATCH / DELETE /api/v1/repos/{o}/{r}/labels/{name}. - Capabilities:
issues,labelsadded to/api/v1/meta. - REST: milestones + assignees (S50 §3 follow-up). Full CRUD
for
/api/v1/repos/{o}/{r}/milestones(with?state=filter on list and liveopen_issues/closed_issuescounters on every response), plusGET /api/v1/repos/{o}/{r}/assignees(repo owner + collaborators eligible for issue assignment). Scope:repo:readon GETs,repo:writeon mutations. Mutations gate onActionIssueLabel. - Issue PATCH extensions.
PATCH /api/v1/repos/{o}/{r}/issues/{n}now acceptslabels,assignees, andmilestonefields with GitHub-style full-replace semantics. Each gates on its own policy action (ActionIssueLabel/ActionIssueAssign) so a caller missing one capability gets a clean 403 rather than a partial update. Unknown label names or assignee usernames → 422; cross-repo milestone ids → 422. - Capabilities:
milestones,assigneesadded to/api/v1/meta. - Reach:
internal/web/handlers/api.resolveAPIReponow resolves both user-owner and org-owner repos — check-runs and every later batch implicitly gain org-repo support.
Added (internal)
- REST: pull requests core (S50 §4).
GET /api/v1/repos/{o}/{r}/pullswith?state=and?draft=filters,GET /api/v1/repos/{o}/{r}/pulls/{number},POST /api/v1/repos/{o}/{r}/pulls,PATCH /api/v1/repos/{o}/{r}/pulls/{number}(title/body author-gated, state viaActionPullClose, draft→ready author-only),GET /api/v1/repos/{o}/{r}/pulls/{number}/commits,GET /api/v1/repos/{o}/{r}/pulls/{number}/files,PUT /api/v1/repos/{o}/{r}/pulls/{number}/merge(honoring the repo's default merge method and the optionalshahead guard). Reviews + comments + reviewers + update-branch + auto-merge land in a follow-up. - Capability:
pullsadded to/api/v1/meta. - REST: PR reviews + inline comments + requested reviewers (S50 §4b).
GET / POST /api/v1/repos/{o}/{r}/pulls/{number}/reviews(eventsAPPROVE/REQUEST_CHANGES/COMMENT, with pending-draft attachment on submit),GET / POST /api/v1/repos/{o}/{r}/pulls/{number}/comments(inline review comments with file_path / side / position anchoring,pendingdrafts,in_reply_to_idthreading), andGET / POST / DELETE /api/v1/repos/{o}/{r}/pulls/{number}/requested_reviewers(byuser_idorusername). - Capability:
pr-reviewsadded to/api/v1/meta. - REST: search (S50 §5).
GET /api/v1/search/repositories,GET /api/v1/search/issues?type=issue|pr, andGET /api/v1/search/codeover the existing FTS corpus. Canonical gh-shaped envelope{ total_count, incomplete_results, items }withLink:pagination. Anonymous callers allowed (visibility filter inside the search package narrows to public).?q=honors the existing operator vocabulary (repo:,is:,state:,author:, phrase). Thesearch/commitsandsearch/usersendpoints, plus thesort=/order=knobs, are deferred to follow-ups. - Capability:
searchadded to/api/v1/meta. - REST: orgs (S50 §7).
GET /api/v1/user/orgs(self),GET /api/v1/users/{username}/orgs(public; shithub has no hidden membership distinction in v1),GET /api/v1/orgs/{org}(single fetch; 404 for soft-deleted),GET /api/v1/orgs/{org}/members. Scope:user:read. - Capability:
orgsadded to/api/v1/meta. - REST: repo webhooks (S50 §8). Full CRUD over a repo's
webhook subscriptions:
GET/POST /api/v1/repos/{o}/{r}/hooks,GET/PATCH/DELETE /api/v1/repos/{o}/{r}/hooks/{id}. Deliveries read-side:GET /api/v1/repos/{o}/{r}/hooks/{id}/deliveries(paginated;Link:headers) andGET /api/v1/repos/{o}/{r}/hooks/{id}/deliveries/{did}(full transcript).POST .../deliveries/{did}/redeliverre-enqueues. Scope:repo:write; role floor: settings:general. Webhook secrets are write-only — set on create, rotated via PATCH'ssecretfield, never echoed back. Create-time SSRF gate rejects loopback / private / disallowed-port targets so misconfigurations surface synchronously instead of as silent delivery failures. - Capability:
webhooksadded to/api/v1/meta. - REST: branches + tags (S50 §9). Read-only ref enumeration:
GET /api/v1/repos/{o}/{r}/branches(paginated; each entry carriesprotectedreflecting the longest-prefix match against the configured branch-protection rules, plusis_default),GET /api/v1/repos/{o}/{r}/branches/{name}(slashes in branch names accepted verbatim or URL-encoded), andGET /api/v1/repos/{o}/{r}/tags(paginated). Scope:repo:read. Empty / uninitialised repos return[]rather than404. - Capabilities:
branches,tagsadded to/api/v1/meta. - REST: repo collaborators (S50 §10).
GET /api/v1/repos/{o}/{r}/collaborators(list),GET .../collaborators/{username}(204 membership probe),GET .../collaborators/{username}/permission(permission level —"none"when not a collaborator),PUT .../collaborators/{username}(add / upgrade, body{"role": "..."}accepting both shithub names and gh-style aliasespull/push),DELETE .../collaborators/{username}(remove). Scope:repo:readon GETs,repo:writeon mutations; mutations layerActionRepoAdminon top. Refuses (422) to enrol the repo owner. - Capability:
collaboratorsadded to/api/v1/meta.
Added (internal)
issues.Editorchestrator wrapsUpdateIssueTitleBodywith markdown re-render + cross-reference re-indexing. Used by the new PATCH-issue endpoint; available for the HTML edit flow when it lands.
Changed
- JSON error envelope on
/api/v1/*.401and403responses now emit{"error": "..."}withContent-Type: application/json(previouslytext/plain). Existing4xx/5xxresponses from the handler bodies are unchanged.
0.1.0 — TBD (operator fills in cutover date)
The first public release of shithub. Pre-1.0: there is no backward-compatibility promise yet. Migrations are forward-only; schema may change between minor versions.
Initial public surface
- Identity — signup, email verification, password reset, TOTP 2FA + recovery codes, SSH keys, scoped PATs, sessions with per-account epoch invalidation.
- Repositories — create, fork, archive, transfer, soft-delete with grace, rename with redirects, visibility toggles, branch protection, default-branch swap, topics, README/license/ .gitignore templates.
- Git — bare repos on disk; HTTPS smart-HTTP push/pull; pre/post-receive hook integration.
- Code browsing — tree, blob (chroma syntax highlighting), raw, blame, commit history, individual commit views, branch/tag listings, compare views, file finder.
- Issues + PRs — full CRUD; reviews; required-reviewer enforcement; status-check gates; three merge methods.
- Social — stars, watches, forks,
/explore, stargazer/ watcher lists. - Search — code, repo, user, issue.
- Notifications — in-app inbox, email fan-out, one-click unsubscribe.
- Orgs + teams — roles, invitations, one-level nesting, max-of-sources policy.
- Webhooks — HMAC-signed delivery, exponential backoff, auto-disable, SSRF defense, redelivery UI.
- Observability — structured logs, Prometheus metrics, optional OTel tracing, Sentry-protocol error reporting.
- Operations — Ansible playbook, systemd units, Caddy edge, WireGuard mesh for monitoring, Postgres WAL archive + daily logical backups to Spaces, cross-region DR, restore drill.
- Public landing page on
/for anonymous viewers; signed-in viewers get a quick-link dashboard. - Lightweight status page at
docs.<host>/status.html. - Cutover artifacts under
deploy/cutover/. - Public docs site built with mdBook.
- Operator runbooks for incidents, backups, restore, upgrade, rollback, rotate-secrets, rotate-keys, regenerate-akc, drain-workers, read-only-mode, day-one.
- a11y tooling (pa11y + axe) and k6 load-test scenarios.
- THIRD_PARTY_NOTICES.md with a CI-verified generator.
Known gaps at v0.1.0
- SSH git transport (HTTPS only)
- Actions / CI runner
- Packages, Releases, Pages, Projects, Gists
- GraphQL API (only a small REST surface today)
- Activity feed UI
These are all on the post-MVP roadmap.
View source
| 1 | # Changelog |
| 2 | |
| 3 | All notable changes to shithub are documented here. This project |
| 4 | follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) |
| 5 | conventions and [Semantic Versioning](https://semver.org/spec/v2.0.0.html). |
| 6 | |
| 7 | Pre-1.0 versioning: minor versions may break the API. The |
| 8 | stability contract begins at v1.0.0; until then, expect changes |
| 9 | between minor releases. |
| 10 | |
| 11 | ## [Unreleased] |
| 12 | |
| 13 | ### Added |
| 14 | |
| 15 | - **REST API contract (S50 §0).** `GET /api/v1/meta` returns the |
| 16 | server's version stamp and a list of feature capability strings |
| 17 | for client-side feature detection. Every `/api/v1/*` response |
| 18 | now carries `X-RateLimit-Limit`, `X-RateLimit-Remaining`, |
| 19 | `X-RateLimit-Reset`, and (when PAT-authenticated) `X-OAuth-Scopes`. |
| 20 | The 403 scope-reject response also carries |
| 21 | `X-Accepted-OAuth-Scopes`. Operators tune the API rate-limit |
| 22 | budgets via `ratelimit.api.authed_per_hour` / |
| 23 | `ratelimit.api.anon_per_hour` (defaults: 5000 / 60). |
| 24 | - **Pagination helper** `internal/web/handlers/api/apipage` — |
| 25 | emits canonical RFC 8288 Link headers (`first`/`prev`/`next`/`last`) |
| 26 | with absolute URLs rooted at the configured public base URL. |
| 27 | - **REST: user emails (S50 §1).** `GET /api/v1/user/emails` lists |
| 28 | the authenticated user's emails. Optional `?verified=true|false` |
| 29 | filter. Scope: `user:read`. |
| 30 | - **REST: user SSH keys (S50 §1).** `GET/POST /api/v1/user/keys` |
| 31 | and `GET/DELETE /api/v1/user/keys/{id}` expose CRUD for git |
| 32 | authentication keys. Signing keys are tracked separately by a |
| 33 | new `kind` column on `user_ssh_keys` and remain on the HTML |
| 34 | surface for now. Scopes: `user:read` for GETs, `user:write` for |
| 35 | mutations. |
| 36 | - **Capabilities:** `user-emails`, `ssh-keys` added to |
| 37 | `/api/v1/meta` response. |
| 38 | - **REST: repos core (S50 §2).** |
| 39 | `GET /api/v1/user/repos`, `GET /api/v1/users/{username}/repos`, |
| 40 | `GET /api/v1/orgs/{org}/repos`, |
| 41 | `GET /api/v1/repos/{owner}/{repo}`, |
| 42 | `POST /api/v1/user/repos`, |
| 43 | `POST /api/v1/orgs/{org}/repos`, |
| 44 | `PATCH /api/v1/repos/{owner}/{repo}` (description, has_issues, |
| 45 | has_pulls, archived, visibility), and |
| 46 | `DELETE /api/v1/repos/{owner}/{repo}` (soft-delete). |
| 47 | Visibility-aware listing: a user's `/users/{u}/repos` shows |
| 48 | private rows only to that user; an org's `/orgs/{o}/repos` |
| 49 | shows private rows only to members. Single-repo GETs `404` |
| 50 | for callers who can't see the row (no existence leak). |
| 51 | - **Capability:** `repos` added to `/api/v1/meta`. |
| 52 | - **REST: issues + comments + lock (S50 §3).** |
| 53 | `GET /api/v1/repos/{o}/{r}/issues` (with `?state=` filter and |
| 54 | `Link:`-header pagination), |
| 55 | `GET /api/v1/repos/{o}/{r}/issues/{number}`, |
| 56 | `POST /api/v1/repos/{o}/{r}/issues`, |
| 57 | `PATCH /api/v1/repos/{o}/{r}/issues/{number}` (title/body |
| 58 | author-gated, state/state_reason policy-gated), |
| 59 | `GET / POST /api/v1/repos/{o}/{r}/issues/{number}/comments`, |
| 60 | `PATCH / DELETE /api/v1/repos/{o}/{r}/issues/comments/{cid}`, |
| 61 | `PUT / DELETE /api/v1/repos/{o}/{r}/issues/{number}/lock`. |
| 62 | - **REST: repo labels (S50 §3).** |
| 63 | `GET / POST /api/v1/repos/{o}/{r}/labels` and |
| 64 | `GET / PATCH / DELETE /api/v1/repos/{o}/{r}/labels/{name}`. |
| 65 | - **Capabilities:** `issues`, `labels` added to `/api/v1/meta`. |
| 66 | - **REST: milestones + assignees (S50 §3 follow-up).** Full CRUD |
| 67 | for `/api/v1/repos/{o}/{r}/milestones` (with `?state=` filter |
| 68 | on list and live `open_issues`/`closed_issues` counters on |
| 69 | every response), plus `GET /api/v1/repos/{o}/{r}/assignees` |
| 70 | (repo owner + collaborators eligible for issue assignment). |
| 71 | Scope: `repo:read` on GETs, `repo:write` on mutations. |
| 72 | Mutations gate on `ActionIssueLabel`. |
| 73 | - **Issue PATCH extensions.** `PATCH /api/v1/repos/{o}/{r}/issues/{n}` |
| 74 | now accepts `labels`, `assignees`, and `milestone` fields with |
| 75 | GitHub-style full-replace semantics. Each gates on its own |
| 76 | policy action (`ActionIssueLabel` / `ActionIssueAssign`) so a |
| 77 | caller missing one capability gets a clean 403 rather than a |
| 78 | partial update. Unknown label names or assignee usernames → |
| 79 | 422; cross-repo milestone ids → 422. |
| 80 | - **Capabilities:** `milestones`, `assignees` added to |
| 81 | `/api/v1/meta`. |
| 82 | - **Reach:** `internal/web/handlers/api.resolveAPIRepo` now |
| 83 | resolves both user-owner and org-owner repos — check-runs and |
| 84 | every later batch implicitly gain org-repo support. |
| 85 | |
| 86 | ### Added (internal) |
| 87 | |
| 88 | - **REST: pull requests core (S50 §4).** |
| 89 | `GET /api/v1/repos/{o}/{r}/pulls` with `?state=` and `?draft=` |
| 90 | filters, |
| 91 | `GET /api/v1/repos/{o}/{r}/pulls/{number}`, |
| 92 | `POST /api/v1/repos/{o}/{r}/pulls`, |
| 93 | `PATCH /api/v1/repos/{o}/{r}/pulls/{number}` (title/body |
| 94 | author-gated, state via `ActionPullClose`, draft→ready |
| 95 | author-only), |
| 96 | `GET /api/v1/repos/{o}/{r}/pulls/{number}/commits`, |
| 97 | `GET /api/v1/repos/{o}/{r}/pulls/{number}/files`, |
| 98 | `PUT /api/v1/repos/{o}/{r}/pulls/{number}/merge` (honoring |
| 99 | the repo's default merge method and the optional `sha` |
| 100 | head guard). Reviews + comments + reviewers + update-branch + |
| 101 | auto-merge land in a follow-up. |
| 102 | - **Capability:** `pulls` added to `/api/v1/meta`. |
| 103 | - **REST: PR reviews + inline comments + requested reviewers (S50 §4b).** |
| 104 | `GET / POST /api/v1/repos/{o}/{r}/pulls/{number}/reviews` |
| 105 | (events `APPROVE` / `REQUEST_CHANGES` / `COMMENT`, with |
| 106 | pending-draft attachment on submit), |
| 107 | `GET / POST /api/v1/repos/{o}/{r}/pulls/{number}/comments` |
| 108 | (inline review comments with file_path / side / position |
| 109 | anchoring, `pending` drafts, `in_reply_to_id` threading), and |
| 110 | `GET / POST / DELETE /api/v1/repos/{o}/{r}/pulls/{number}/requested_reviewers` |
| 111 | (by `user_id` or `username`). |
| 112 | - **Capability:** `pr-reviews` added to `/api/v1/meta`. |
| 113 | - **REST: search (S50 §5).** `GET /api/v1/search/repositories`, |
| 114 | `GET /api/v1/search/issues?type=issue|pr`, and |
| 115 | `GET /api/v1/search/code` over the existing FTS corpus. |
| 116 | Canonical gh-shaped envelope `{ total_count, |
| 117 | incomplete_results, items }` with `Link:` pagination. |
| 118 | Anonymous callers allowed (visibility filter inside the search |
| 119 | package narrows to public). `?q=` honors the existing operator |
| 120 | vocabulary (`repo:`, `is:`, `state:`, `author:`, phrase). The |
| 121 | `search/commits` and `search/users` endpoints, plus the |
| 122 | `sort=`/`order=` knobs, are deferred to follow-ups. |
| 123 | - **Capability:** `search` added to `/api/v1/meta`. |
| 124 | - **REST: orgs (S50 §7).** `GET /api/v1/user/orgs` (self), |
| 125 | `GET /api/v1/users/{username}/orgs` (public; shithub has no |
| 126 | hidden membership distinction in v1), |
| 127 | `GET /api/v1/orgs/{org}` (single fetch; 404 for soft-deleted), |
| 128 | `GET /api/v1/orgs/{org}/members`. Scope: `user:read`. |
| 129 | - **Capability:** `orgs` added to `/api/v1/meta`. |
| 130 | - **REST: repo webhooks (S50 §8).** Full CRUD over a repo's |
| 131 | webhook subscriptions: `GET/POST /api/v1/repos/{o}/{r}/hooks`, |
| 132 | `GET/PATCH/DELETE /api/v1/repos/{o}/{r}/hooks/{id}`. Deliveries |
| 133 | read-side: `GET /api/v1/repos/{o}/{r}/hooks/{id}/deliveries` |
| 134 | (paginated; `Link:` headers) and |
| 135 | `GET /api/v1/repos/{o}/{r}/hooks/{id}/deliveries/{did}` (full |
| 136 | transcript). `POST .../deliveries/{did}/redeliver` re-enqueues. |
| 137 | Scope: `repo:write`; role floor: settings:general. Webhook |
| 138 | secrets are write-only — set on create, rotated via PATCH's |
| 139 | `secret` field, never echoed back. Create-time SSRF gate |
| 140 | rejects loopback / private / disallowed-port targets so |
| 141 | misconfigurations surface synchronously instead of as silent |
| 142 | delivery failures. |
| 143 | - **Capability:** `webhooks` added to `/api/v1/meta`. |
| 144 | - **REST: branches + tags (S50 §9).** Read-only ref enumeration: |
| 145 | `GET /api/v1/repos/{o}/{r}/branches` (paginated; each entry |
| 146 | carries `protected` reflecting the longest-prefix match against |
| 147 | the configured branch-protection rules, plus `is_default`), |
| 148 | `GET /api/v1/repos/{o}/{r}/branches/{name}` (slashes in branch |
| 149 | names accepted verbatim or URL-encoded), and |
| 150 | `GET /api/v1/repos/{o}/{r}/tags` (paginated). Scope: `repo:read`. |
| 151 | Empty / uninitialised repos return `[]` rather than `404`. |
| 152 | - **Capabilities:** `branches`, `tags` added to `/api/v1/meta`. |
| 153 | - **REST: repo collaborators (S50 §10).** |
| 154 | `GET /api/v1/repos/{o}/{r}/collaborators` (list), |
| 155 | `GET .../collaborators/{username}` (204 membership probe), |
| 156 | `GET .../collaborators/{username}/permission` (permission |
| 157 | level — `"none"` when not a collaborator), |
| 158 | `PUT .../collaborators/{username}` (add / upgrade, body |
| 159 | `{"role": "..."}` accepting both shithub names and gh-style |
| 160 | aliases `pull`/`push`), |
| 161 | `DELETE .../collaborators/{username}` (remove). Scope: |
| 162 | `repo:read` on GETs, `repo:write` on mutations; mutations |
| 163 | layer `ActionRepoAdmin` on top. Refuses (422) to enrol the |
| 164 | repo owner. |
| 165 | - **Capability:** `collaborators` added to `/api/v1/meta`. |
| 166 | |
| 167 | ### Added (internal) |
| 168 | |
| 169 | - `issues.Edit` orchestrator wraps `UpdateIssueTitleBody` with |
| 170 | markdown re-render + cross-reference re-indexing. Used by the |
| 171 | new PATCH-issue endpoint; available for the HTML edit flow when |
| 172 | it lands. |
| 173 | |
| 174 | ### Changed |
| 175 | |
| 176 | - **JSON error envelope on `/api/v1/*`.** `401` and `403` |
| 177 | responses now emit `{"error": "..."}` with |
| 178 | `Content-Type: application/json` (previously `text/plain`). |
| 179 | Existing `4xx`/`5xx` responses from the handler bodies are |
| 180 | unchanged. |
| 181 | |
| 182 | ## [0.1.0] — TBD (operator fills in cutover date) |
| 183 | |
| 184 | The first public release of shithub. Pre-1.0: there is no |
| 185 | backward-compatibility promise yet. Migrations are forward-only; |
| 186 | schema may change between minor versions. |
| 187 | |
| 188 | ### Initial public surface |
| 189 | |
| 190 | - **Identity** — signup, email verification, password reset, TOTP |
| 191 | 2FA + recovery codes, SSH keys, scoped PATs, sessions with |
| 192 | per-account epoch invalidation. |
| 193 | - **Repositories** — create, fork, archive, transfer, soft-delete |
| 194 | with grace, rename with redirects, visibility toggles, branch |
| 195 | protection, default-branch swap, topics, README/license/ |
| 196 | .gitignore templates. |
| 197 | - **Git** — bare repos on disk; HTTPS smart-HTTP push/pull; |
| 198 | pre/post-receive hook integration. |
| 199 | - **Code browsing** — tree, blob (chroma syntax highlighting), |
| 200 | raw, blame, commit history, individual commit views, branch/tag |
| 201 | listings, compare views, file finder. |
| 202 | - **Issues + PRs** — full CRUD; reviews; required-reviewer |
| 203 | enforcement; status-check gates; three merge methods. |
| 204 | - **Social** — stars, watches, forks, `/explore`, stargazer/ |
| 205 | watcher lists. |
| 206 | - **Search** — code, repo, user, issue. |
| 207 | - **Notifications** — in-app inbox, email fan-out, one-click |
| 208 | unsubscribe. |
| 209 | - **Orgs + teams** — roles, invitations, one-level nesting, |
| 210 | max-of-sources policy. |
| 211 | - **Webhooks** — HMAC-signed delivery, exponential backoff, |
| 212 | auto-disable, SSRF defense, redelivery UI. |
| 213 | - **Observability** — structured logs, Prometheus metrics, |
| 214 | optional OTel tracing, Sentry-protocol error reporting. |
| 215 | - **Operations** — Ansible playbook, systemd units, Caddy edge, |
| 216 | WireGuard mesh for monitoring, Postgres WAL archive + daily |
| 217 | logical backups to Spaces, cross-region DR, restore drill. |
| 218 | - **Public landing page** on `/` for anonymous viewers; signed-in |
| 219 | viewers get a quick-link dashboard. |
| 220 | - **Lightweight status page** at `docs.<host>/status.html`. |
| 221 | - **Cutover artifacts** under `deploy/cutover/`. |
| 222 | - **Public docs site** built with mdBook. |
| 223 | - **Operator runbooks** for incidents, backups, restore, upgrade, |
| 224 | rollback, rotate-secrets, rotate-keys, regenerate-akc, |
| 225 | drain-workers, read-only-mode, day-one. |
| 226 | - **a11y tooling** (pa11y + axe) and **k6 load-test scenarios**. |
| 227 | - **THIRD_PARTY_NOTICES.md** with a CI-verified generator. |
| 228 | |
| 229 | ### Known gaps at v0.1.0 |
| 230 | |
| 231 | - SSH git transport (HTTPS only) |
| 232 | - Actions / CI runner |
| 233 | - Packages, Releases, Pages, Projects, Gists |
| 234 | - GraphQL API (only a small REST surface today) |
| 235 | - Activity feed UI |
| 236 | |
| 237 | These are all on the post-MVP roadmap. |
| 238 | |
| 239 | [Unreleased]: https://shithub.sh/shithub/shithub/compare/v0.1.0...trunk |
| 240 | [0.1.0]: https://shithub.sh/shithub/shithub/releases/tag/v0.1.0 |