ADR 0001 — Single collection, no accounts (with a forward-compat hedge)
- Status: Accepted
- Deciders: scryme maintainers
- Related issues: #205 (decision spike), #202–#204 (settings + device tokens)
Context
scryme's founding constraint is single-user, no auth — one implicit collection per
deployment (see the README, CLAUDE.md, and src/config.py). Two forces put pressure on that
constraint:
- Mobile-app integration. Two sibling apps are planned (a scanner, per #164–#168, and a browser app). They need to authenticate to an instance and sync against a collection.
- Settings sprawl. Configuration lives in three unrelated places — environment variables
(
config.py), a single DB row (LLMSettings,id == 1), and client-sidelocalStorage/cookies — with no clear line between "operator configures the server" and "user sets their preferences."
The instinctive fix — "add accounts" — is the heaviest possible answer, and it is paid for by the 99% case that scryme is explicitly built for: one person, one collection.
The reframe
"Accounts" bundles three separable concerns. Only the third is actually about accounts:
| Concern | What it really needs | Requires accounts? |
|---|---|---|
| Client/device authorization | A revocable per-app credential (#204) | No |
| Preferences grouping | A per-collection preferences store (#203, #202) | No |
| Multi-tenant identity | Real human accounts + per-user collection isolation | Yes |
Nothing shipped or currently planned requires the third row. The mobile apps need device authorization, not identity; the settings work needs a preferences store, not identity.
The shared-collection case
A real, common scenario informed this decision: a household (e.g. a partner who does organization/input and another who builds decks and manages trade/sell binders) shares one physical collection. This is still one collection — it argues against per-user identity, not for it. What it genuinely requires is that two people editing the same collection at the same time cannot silently clobber each other's changes. That is a concurrency-safety problem, not an identity problem (see Consequences).
Decision
Option A — stay single-collection, with a forward-compat hedge.
- Keep one implicit collection per deployment. Do not build human accounts, login, sessions, or per-user data isolation.
- Serve mobile integration with revocable per-device tokens (#204).
- Serve settings/preferences with a per-collection preferences singleton (#203) surfaced in a unified settings page (#202).
- Hedge: add a nullable
owner_id/collection_idcolumn to collection-scoped and new settings/token tables now. It is alwaysNULLtoday and unused by any query. Its only job is to make a future reversal to multi-collection an additive migration rather than a schema-wide rewrite.
Options considered
Option A — single-collection + hedge (chosen).
- Pro: no auth/session/password-reset/tenant-isolation tax; matches the stated 1 person : 1 collection reality; self-hosters need nothing more; mobile + settings both unblocked.
- Con: a hosted multi-user SaaS would require future work (bounded by the hedge).
Option B — build multi-user accounts now (rejected).
- Pro: enables a hosted SaaS / cloud sync / multiple humans with isolated collections on one box.
- Con: large surface area (auth, sessions, isolation, migrating every collection-scoped query), paid for by the overwhelmingly common single-user case, to serve demand that does not exist yet.
Triggers to revisit (A → B)
Reopen this decision only when one of these becomes real. Until then, "should we do accounts?" is a lookup against this list, not a fresh debate:
- A hosted, multi-user SaaS offering (many users' data on infrastructure the maintainers run).
- Cloud sync of many users' collections through a single deployment.
- Genuine multiple humans with separate collections on one self-hosted box — distinct from a household sharing a single collection, which Option A already serves.
Consequences
- The
owner_idhedge is a standing convention. New collection-scoped tables and the settings/token tables carry a nullableowner_id/collection_id, defaulting toNULL. Reviewers should expect it; leaving it off a new mutable table is the thing to catch. - Shared editing must be made safe. Because one collection is deliberately shared by more than
one person, scryme takes on responsibility for concurrent-edit safety — two simultaneous
editors must not silently overwrite each other. The chosen approach is optimistic concurrency
control (a version/
updated_atguard on mutable rows → HTTP 409 + a "this changed since you loaded it" merge prompt, rather than last-write-wins) plus live sync so both people see changes as they happen. The live-sync stream generalizes the SSE work already proposed for scanning (#166) into a collection-events stream. Full Google-Docs-style character-level co-editing (OT/CRDT) is explicitly out of scope: collection edits act on discrete stacks (quantity, tags, location, condition), so row-level optimistic locking is sufficient. Tracked in #207. - No user attribution by default. Since there are no accounts, changes are not attributed to a named person. If "who changed this" becomes desirable for shared households, it can be layered on via the device-token label (#204) without introducing identity — a deliberately lighter step than accounts.