-
Notifications
You must be signed in to change notification settings - Fork 0
docs: domain glossary and ADRs for simplifying the stack #122
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
854aa99
docs: add domain glossary with account scope decision
claude 2b82eb6
docs: ADR 0001 — Firebase Auth and Firestore, no own server
claude 9fe630e
docs: ADR 0002 — guests use Firebase anonymous sign-in
claude 882c959
Merge remote-tracking branch 'origin/main' into docs/simplify-stack
claude 47e09e4
docs: match glossary and ADRs to the grill-with-docs formats
claude 05dadd6
docs: ADR 0001 — host the static app on Firebase Hosting
claude 58284ee
docs: submitted yields go public only after review
claude 628d952
docs: editing an approved yield resubmits it for review
claude 7fe0fad
docs: ADR 0003 — five pages; inventory is a separate tool
claude 8d25faf
docs: rejected yields return to private with an optional review note
claude 09dcc65
docs: ADR 0004 — community dataset is CC BY 4.0, download now
claude 7e6f8e9
docs: ADR 0004 — legacy shared yields need owner consent to be approved
claude c5a797d
docs: cover existing-account sign-in, reviewer rights and the address…
claude 0f98d9c
docs: guest-data handoff, display-name-only attribution
claude 27d36a8
docs: freeze writes on the old API before the Neon copy
claude 9e5b663
docs: rewrap ADR 0001 cutover paragraph
claude c22070a
docs: cover offline guests, public fields and last-write-wins
claude bf5cd82
docs: cover legacy logins, starting form and public copy removal
claude a59f12b
docs: map legacy accounts explicitly and keep the offline cache
claude 685f208
docs: read-only old client, anonymous write limits, CSV formulas
claude 051dfc8
docs: offline handoff file, sign-out cache, private source, quotas
claude 111f20f
docs: import columns, display name updates, zero yields, old address
claude File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| # Local Catch | ||
|
|
||
| A yield and cost calculator for fishermen and fishmongers. It turns what a fish | ||
| costs whole into what each finished product really costs, and lets people keep | ||
| and share the yields they measure themselves. | ||
|
|
||
| ## Language | ||
|
|
||
| ### Yields and costs | ||
|
|
||
| **Conversion**: | ||
| Going from one form of a fish to another, written `From → To` (e.g. | ||
| `Round → Skinless Fillet`). | ||
| _Avoid_: cut, transformation | ||
|
|
||
| **Yield**: | ||
| The share of weight kept by a conversion, as a percentage above 0 and up to 100. | ||
| _Avoid_: recovery rate, fraction (0.42) | ||
|
|
||
| **Reference yield**: | ||
| A published yield from the MAB-37 research that ships with the app. | ||
| _Avoid_: default yield, static data | ||
|
|
||
| **Custom yield**: | ||
| A yield a person measured from their own processing. Private unless approved | ||
| into the community dataset. | ||
| _Avoid_: user data, my data | ||
|
|
||
| **Saved calculation**: | ||
| A cost or weight calculation a person chose to keep. | ||
| _Avoid_: calc, saved calc | ||
|
|
||
| ### People and the community dataset | ||
|
|
||
| **Account**: | ||
| An optional sign-in that exists for two reasons only: keeping a person's custom | ||
| yields and saved calculations across devices, and submitting custom yields to | ||
| the community dataset. A reviewer's account can also review submitted yields. | ||
| _Avoid_: user, profile | ||
|
|
||
| **Guest**: | ||
| Someone using the app without signing in. A guest can save, but loses what they | ||
| saved if they clear their browser data, and cannot submit yields. | ||
| _Avoid_: anonymous user | ||
|
|
||
| **Submitted yield**: | ||
| A custom yield its owner has asked to add to the community dataset. It stays | ||
| private until a reviewer approves it. A rejected yield goes back to private, | ||
| where its owner can fix it and submit it again. Editing an approved yield takes | ||
| it out of the dataset and submits it again. | ||
|
coderabbitai[bot] marked this conversation as resolved.
paccloud marked this conversation as resolved.
|
||
| _Avoid_: shared yield, published yield, contribution | ||
|
|
||
| **Review note**: | ||
| An optional message from the reviewer to a yield's owner saying why it was | ||
| rejected. Only the owner sees it. | ||
| _Avoid_: rejection reason, feedback | ||
|
|
||
| **Reviewer**: | ||
| An account that has been granted the right to approve or reject submitted | ||
| yields. Being signed in is not enough. | ||
| _Avoid_: admin, moderator | ||
|
|
||
| **Community dataset**: | ||
| All approved yields, readable and downloadable by anyone under CC BY 4.0, | ||
| attributed only by display name or as "Anonymous". | ||
| _Avoid_: community pool, public data | ||
|
|
||
| **Display name**: | ||
| The only public identity a person has. Optional, chosen by them, never their | ||
| email. | ||
| _Avoid_: username, contributor name | ||
|
|
||
| _Dropped concepts_: contributor profile (bio/organization pages) and publishing | ||
| saved calculations publicly. Neither is one of an account's two jobs. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| --- | ||
| status: accepted | ||
| --- | ||
|
|
||
| # Firebase Auth, Firestore and Firebase Hosting, with no server of our own | ||
|
|
||
| The app ran two backends (Express + SQLite locally, Vercel functions + Neon in | ||
| production), a shared handler layer, a custom offline sync engine and two | ||
| sign-in systems, for about two accounts whose only jobs are keeping custom | ||
| yields and saved calculations across devices and submitting custom yields. We | ||
| chose Firebase Auth plus Cloud Firestore, reached directly from the browser: | ||
| security rules decide who reads and writes what, and Firestore's persistent | ||
| offline cache (so offline edits survive a reload) replaces our sync engine. The | ||
|
paccloud marked this conversation as resolved.
|
||
| static app is served from Firebase Hosting, so the whole app lives with one | ||
| provider. Firebase Auth was already in use, so no one signs up again. | ||
|
|
||
| ## Considered Options | ||
|
|
||
| - **Supabase** (Postgres, auth, row-level security): about as simple, but free | ||
| projects pause after a week idle, and it would change the sign-in system a | ||
| third time. | ||
| - **Keep Neon and delete the Express/SQLite backend** (the direction in | ||
| `AUDIT_REPORT.md` item 2.1): smallest change, but we'd still own API code, | ||
| token verification and a sync engine. | ||
| - **Firebase SQL Connect** (proved in `dataconnect/`): needs a paid Cloud SQL | ||
| instance; more than this app needs. | ||
|
|
||
| ## Consequences | ||
|
|
||
| - `api/`, `server/`, `shared/`, SQLite, Neon, the legacy password login and the | ||
| custom sync layer go away, and so does the rule to change both backends. | ||
|
paccloud marked this conversation as resolved.
|
||
| - Excel/CSV import parses in the browser. The import and export format gains | ||
| separate starting-form and finished-product columns; a row without a starting | ||
| form imports with it blank, like the Neon copy. | ||
| - Security rules cannot hide single fields of a readable document, so approved | ||
| yields are copied into a separate public collection holding only the public | ||
| fields (species, conversion, yield, display name). The owner's user id, the | ||
| free-text source note, submission details and review note stay in the owner's | ||
| private document. The reviewer's approval writes both in one batch. Changing | ||
| the display name rewrites the name on all of that owner's public copies in one | ||
| batch. Editing or deleting an approved yield deletes its public copy in the | ||
| same batch, and the rules let an owner delete the public copy of their own | ||
| yield. | ||
| - Firestore's persistent cache keeps private data in the browser after sign-out, | ||
| so signing out first sends pending writes (or, if offline, asks whether to | ||
| wait or discard them) and then clears the local cache. | ||
| - Our sync engine's revision check goes away: when the same record is edited on | ||
| two devices while one is offline, the later write wins. We accept this because | ||
| the accounts belong to one person; the conflict screen is dropped. | ||
| - The community dataset can be downloaded as CSV/JSON from the Community page. A | ||
| stable file address for other tools comes with the versioned releases in | ||
| ADR 0004. | ||
| - The Firebase SDK makes the app download larger than today's REST calls. | ||
| - Local development and CI use the Firebase emulators. | ||
| - The address moves from `*.vercel.app` to `*.web.app`. Browser storage belongs | ||
| to an address, so a redirect cannot carry a guest's saved data or unsynced | ||
| edits across. Before the redirect is switched on, the last version on the old | ||
| address asks guests to sign in so their data reaches their account, and | ||
| finishes syncing signed-in users. A later release makes the old app read-only | ||
| too: it stops accepting new edits, still pushes what is pending, and shows a | ||
| banner about the move. An old copy that was offline through all this can't be | ||
| seen from the server, so the read-only app also lets anyone save their unsent | ||
| changes as a file, which the new app's import accepts. After a waiting period | ||
|
paccloud marked this conversation as resolved.
|
||
| for devices to come online, the old API stops accepting writes (it answers | ||
| them with an error), so nothing changes in Neon while it is copied. The copy | ||
| uses a written list that maps each Neon account holding data to its Firebase | ||
| user id, checked by hand (there are about two accounts); it stops if an | ||
| account with data is missing from the list, appears twice, or two accounts map | ||
| to one Firebase user. Neon custom yields record only the finished product, not | ||
| the starting form, so the copy leaves the starting form blank for the owner to | ||
| fill in. The dry run lists any yield that is not above 0 and up to 100; the | ||
| owner fixes those before the freeze, and the copy refuses to run while any | ||
| remain. After the copy has been checked, the old address keeps serving the | ||
| read-only app for six months, so an installed copy that comes back online | ||
| still gets the save-to-file option and a link to the new address; only then is | ||
| Vercel reduced to a redirect. Bookmarks follow the redirect; installed copies | ||
| of the app need to be installed again from the new address. PR previews come | ||
| from Firebase preview channels. | ||
| - Supersedes `docs/AUTH_MIGRATION_ROADMAP.md` (Better Auth + Cloudflare). | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| --- | ||
| status: accepted | ||
| --- | ||
|
|
||
| # Guests use Firebase anonymous sign-in | ||
|
|
||
| People should be able to save before deciding to sign up. Instead of keeping | ||
| guest data in the browser and copying it into an account with our own code, a | ||
| guest's first save signs them in anonymously; their data lives in Firestore | ||
|
paccloud marked this conversation as resolved.
|
||
| under the same rules as any account, and signing in with Google or email later | ||
|
paccloud marked this conversation as resolved.
paccloud marked this conversation as resolved.
|
||
| links to that same user so nothing is copied. People who only use the calculator | ||
| never get an account. Anonymous sign-in needs the network, so a save made | ||
| offline before the guest has a user is kept in the browser and written to | ||
| Firestore once sign-in succeeds. | ||
|
|
||
| ## Consequences | ||
|
|
||
| - Guest data saved by the current app (in the browser, not Firestore) is not | ||
| read by the new app. It moves over the existing way before the switch: the | ||
| current app asks guests to sign in, its adoption code moves their records into | ||
| the account, and they reach Firestore with the one-time copy from Neon (see | ||
| ADR 0001). The old guest storage and adoption code are removed only after | ||
| that. | ||
|
|
||
| - If the guest signs in with a Google account or email that already belongs to | ||
| an account, Firebase cannot link it to the anonymous user. In that case the | ||
| app reads the guest's custom yields and saved calculations while still signed | ||
| in as the guest, signs in to the existing account, and writes them there. This | ||
| copy is the one piece of guest-transfer code we keep. | ||
|
|
||
| - A guest who clears browser data loses what they saved, as today. | ||
| - Unused anonymous accounts pile up and may need occasional cleanup. Deleting an | ||
| Auth user does not delete its Firestore documents, so cleanup removes the | ||
| user's custom yields and saved calculations along with the user. | ||
| - Anonymous users can write to Firestore without a verified account, so the app | ||
| uses App Check, and the rules cap the size and number of each user's records. | ||
| Those caps are per user, so the project-wide limits are App Check, Firebase | ||
| Auth's limit on new anonymous sign-ups from one IP address (kept low), and the | ||
| free plan's hard quotas, which stop writes instead of billing. A bot could | ||
| still exhaust the free quota and block saves until it resets; we accept that | ||
| for an app of this size and revisit it if it happens. | ||
| - Only a non-anonymous account can submit yields to the community dataset, so | ||
| every submitted yield has a real owner. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| --- | ||
| status: accepted | ||
| --- | ||
|
|
||
| # Five pages; inventory is a separate tool | ||
|
|
||
| The app is only the calculator and what an account needs around it: | ||
| Calculator, My data (custom yields, saved calculations, import, submit), | ||
| Community (the community dataset and where reference yields come from), About, | ||
| and Review (reviewers only). Sign-in is a panel, not a page. Contributor | ||
| profiles, the roadmap page and the "Inventory — coming soon" placeholder are | ||
| removed. Inventory belongs in a separate tool in the harvester suite, not in | ||
| this app, so it should not be added back here. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| --- | ||
| status: accepted | ||
| --- | ||
|
|
||
| # Community dataset is CC BY 4.0; download now, versioned releases later | ||
|
|
||
| Submitting a yield means its owner agrees that, once approved, it is released | ||
| under CC BY 4.0 with attribution by display name or "Anonymous"; the submit | ||
| dialog says so. No other identifying field (such as the organization from the | ||
| old contributor profiles) is published or exported. The code stays MIT. A | ||
| license on contributed data cannot be narrowed after the fact, so this is set | ||
| before any submissions under the new flow. For now the Community page offers a | ||
| CSV/JSON download built from the approved yields. Every CSV export, including | ||
| the later scheduled one, neutralizes cells that start with `=`, `+`, `-` or `@` | ||
| so a spreadsheet does not run them as formulas. Scheduled, versioned releases (a | ||
| GitHub Action exporting a numbered file at a stable address other tools can | ||
| fetch) will be added once there are enough approved yields to be worth citing. | ||
| Until then the dataset has no fixed download address. | ||
|
|
||
| ## Consequences | ||
|
|
||
| - Yields shared before this consent existed enter the community dataset only | ||
| with their owner's agreement to CC BY 4.0: the one-time copy from Neon marks | ||
| them approved only for owners who have agreed, and leaves the rest private for | ||
| their owners to submit again. A copied yield whose starting form is still | ||
| blank stays private until its owner fills it in and submits it. |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.