What we hold, and what we do not
The promise is this: your feedback lives in your GitHub, not our database. Every idea, comment and vote is a real GitHub object in the maintainer's own repository, and we keep no copy.
That sentence is a claim about content, not about all state. The list below is the state that is not content: everything we do hold, what each row contains, why we cannot avoid holding it, and the source files that write it — or, where the writer is outside this repository or not built yet, a note saying so — so you can go and check. It is generated from the same catalog the code is checked against; a store missing from this page fails the build.
Held whichever way you answered the footprint
Read cache
- What we hold
- Short-lived copies of the public GitHub reads a Board is built from — Discussions, Issues and Releases — keyed by Board and operation, with a TTL, and never keyed by viewer.
- Why we hold it
- GitHub has no unauthenticated GraphQL API, so one Reader Token serves every anonymous visitor and its rate limit is shared; without a cache one popular Board would exhaust it (BR-007, BR-014).
- Written by
src/github/cache.tssrc/app/api/github/route.ts
Claim state
- What we hold
- Which GitHub accounts have proven write access to which Board, and when that check last passed.
- Why we hold it
- Write access is the only authority we recognise and we grant none, so we have to remember whose check passed to know who the Client is (CONTEXT.md → Claim).
- Written by
src/components/board/claim/claim-store.tssrc/features/claim/permission.tssrc/lib/board/shell/claims.tssrc/services/store/supabase-claim-store.tssupabase/migrations/20260919120200_claim_state.sql
Takedown blocklist
- What we hold
- Permanent owner/repo keys for repos whose owner removed the Unclaimed Board, with who removed it and when.
- Why we hold it
- A removal that lasts only until the next visitor re-types the URL is not a removal; only a Claim by an account with write access reopens a blocked repo (BR-015).
- Written by
src/lib/blocklist.tssrc/features/unclaimed/takedown-action.tssrc/services/store/supabase-blocklist-store.tssupabase/migrations/20260919120000_blocklist.sql
Stripe entitlement
- What we hold
- Who is paying for what: the subscription state Stripe reports for an Account, projected from verified webhook events.
- Why we hold it
- A private Board is a paid feature (BR-011, BR-033); serving it means knowing whether the Account's payment stands.
- Written by
src/app/api/stripe/webhook/route.ts
Not yet durable: the webhook route verifies and deduplicates each event and today only logs the projection. The row itself lands with the ticket that builds the entitlement projection; nothing is stored until then.
GitHub provider token
- What we hold
- The user's own GitHub OAuth token, returned by Supabase as session.provider_token on the sign-in code exchange, sealed in an httpOnly server-only cookie for the life of the session. Never persisted: no database row, no Supabase user metadata.
- Why we hold it
- Every write in this product is authored by the user's own GitHub account (ADR 0003), so the token has to be available server-side after sign-in. It is the one credential here capable of writing to someone's repositories.
- Written by
src/app/api/auth/callback/route.tssrc/lib/session.ts
Coduo Account
- What we hold
- The Coduo Account row a Stripe Customer resolves to — the Supabase Auth user id, carried on the Customer as the gitbackAccountId metadata key.
- Why we hold it
- Billing runs on the shared Coduo estate (ADR 0006); a Customer without that key is foreign and its events are ignored, so the link is what makes a payment reach the person who made it.
- Written by
src/app/api/stripe/_lib/stripe.tssrc/app/api/stripe/checkout/route.ts
The Account row itself is the estate's, created by Supabase Auth at sign-in (ADR 0003, ADR 0006); this repository writes only the gitbackAccountId link onto the Stripe Customer and reads the row back in src/app/api/stripe/_lib/account.ts.
Product membership
- What we hold
- The membership rows that tie a Coduo Account to Gitback, inside the estate's per-product membership index.
- Why we hold it
- One Supabase project serves every Coduo product; membership is how an Account is scoped to this one and how a paying Account is recognised here (ADR 0006).
- Written by
src/app/api/stripe/_lib/account.ts
Written by the estate, not by this repository: membership rows are the estate's own (coduo-billing-infra, ADR 0006), and nothing under src/ writes or reads them. The path above is where an Account is resolved from the session, which is the seam the membership scopes.
Footprint consent record
- What we hold
- The Client's footprint answer — granted, declined or withdrawn — keyed footprint-consent per Board, with when it was given.
- Why we hold it
- Every footprint-dependent surface has to know which mode the Board is in, and the answer is held whichever way it went (BR-031).
- Written by
src/features/footprint/consent.tssrc/lib/board/home/home-reads.ts
Your browser's own storage
- What we hold
- Nothing on our side. This record is the state Gitback parks in your own browser, which never leaves it and never reaches us: no row, no request, no copy. Today it holds three entries. The unposted feedback draft, in sessionStorage, keyed by Board, written when an anonymous Submit sends you to GitHub to sign in, read back into the composer when you return, and deleted the moment it is — it dies with the tab whether or not you come back. And your light-or-dark choice, in localStorage under `theme`, written by next-themes when you use the theme toggle and read back on your next visit so the page does not flash the wrong one — it stays until you clear your browser's storage. And, since #226, when you last looked at each column of each Roadmap: one timestamp per Board per lane in localStorage, written when you reveal the "n new items" banner, read on your next visit to work out what arrived since — the comparison happens in your browser, against cards it already has, and asks us nothing. It stays until you clear your browser's storage.
- Why we hold it
- Signing in is a navigation away from the Board, which unmounts the composer and takes the sentence you had typed with it; parking the draft for the round trip is the only way it survives (BR-013 is untouched — the draft is in your browser, not our database).
- Written by
src/components/board/feedback/composer-draft.tssrc/components/board/feedback/feedback-module.tsxsrc/components/board/theme-toggle.tsxsrc/components/theme-shortcut.tsxsrc/features/roadmap/last-seen.ts
One record, not one per storage area, because what these entries share is the thing that matters here: they live in your browser and we never see them. They do not share a lifetime, so each entry above names its own — sessionStorage dies with the tab, localStorage does not — and an entry added to this record has to say which it is.
Board exposure
- What we hold
- A private Board's public/private switch, as the Client last set it.
- Why we hold it
- A Board on a private repo is served only as far as the Client chose to expose it (BR-011).
- Written by
src/features/claim/exposure.ts
Held only when the footprint was declined
With a footprint these two live in the Source Repo, under .gitback/ and as labels. A Client who declines the footprint gets a working Board in no-footprint mode, and then there is nowhere else for them to go (BR-031).
Roadmap status
- What we hold
- Which roadmap column each Issue sits in, keyed roadmap-statuses per Board.
- Why we hold it
- With a footprint the status lives as a label in the Source Repo; when the Client declined the footprint there is nowhere else for it to go (BR-031).
- Written by
src/services/store/app-backed-store.tssrc/services/store/supabase-backed-store.ts
Board config
- What we hold
- The board-config document: the feedback category mapping and the roadmap ↔ Issue links, keyed board-config per Board.
- Why we hold it
- With a footprint the config is a file in the Source Repo; when the Client declined the footprint it has to live with us (BR-031).
- Written by
src/services/store/app-backed-store.tssrc/services/store/supabase-backed-store.tssrc/features/board-config/config-store.tssrc/lib/board/home/home-reads.ts
Withdrawing consent
Withdrawing consent stops our future writes and we delete nothing: what is in the repository is yours, and nothing we wrote is ever removed from a Source Repo (BR-030, BR-032). Everything under .gitback/ and every label stays in your repository, working, whether you stop paying, unclaim the Board, or Gitback disappears.