# Discographic Discographic is a self-hosted app for keeping a user's Discogs collection useful as a local vinyl collection workspace. This context records project-specific language that should guide architecture decisions. ## Language **Discogs sync run**: A user-triggered attempt to refresh local collection data from Discogs and carry out the related follow-up work needed for the local workspace to become current. _Avoid_: fetch job, collection download, sync route **Local collection**: The user-scoped SQLite copy of Discogs releases, notes, ratings, marketplace value, listing state, and cached metadata. _Avoid_: cache, database rows **Marketplace enrichment**: An explicit user-triggered operation, owned by the **Discogs sync run** module, that resolves value/listing availability state for releases whose marketplace value is pending or retryable. _Avoid_: value fetch, price lookup **Thumbnail warmup**: The part of a **Discogs sync run** that prepares cached cover variants for wall and poster workflows. _Avoid_: image prefetch, cover job **Sync adapter**: A concrete dependency supplied to the **Discogs sync run** module for persistence, Discogs access, cover caching, marketplace enrichment, exchange rates, or time. _Avoid_: global helper, singleton dependency **Release shape**: The canonical representation rules for turning stored **Local collection** release data into collection, detail, cover wall, random card, and export representations. _Avoid_: response mapper, serializer helper **Import workflow**: The user flow that turns an uploaded CSV/XLSX into a preview, lets the user verify proposed release edits, applies confirmed edits locally, and then syncs those edits back to Discogs while keeping progress visible. _Avoid_: file upload route, import parser **Radar update run**: A user-triggered refresh that brings the Discogs Wantlist into Radar while preserving the user's local buying decisions. _Avoid_: sync button, enrichment panel, price refresh **Account state**: The user's authenticated app state plus Discogs account configuration and preferences needed to decide which workflows are available. _Avoid_: auth status, account response, frontend fallback **Database schema lifecycle**: The startup process that creates, migrates, indexes, and cleans stored Discographic SQLite data so the app can safely use the current schema. _Avoid_: migration helper, startup SQL ## Relationships - A **Discogs sync run** updates one user's **Local collection**. - A **Discogs sync run** owns **Marketplace enrichment**, but full collection sync does not automatically start marketplace enrichment. - User-facing copy should describe **Marketplace enrichment** as reviewing or updating prices; "enrichment" is implementation language, not primary interface wording. - A **Discogs sync run** may perform **Thumbnail warmup** after the collection page download completes. - A **Discogs sync run** uses **Sync adapters** supplied at module creation time rather than importing production singletons directly. - The **Discogs sync run** module returns result objects for expected start/stop conflicts and dependency failures; unexpected background failures are reflected in status. - A **Release shape** includes export serialization because exports are another representation of **Local collection** release data. - A **Release shape** receives already-converted price values for normal app views; export serialization receives a currency conversion adapter because export rows contain converted price columns. - A **Release shape** should be introduced contract-first: define and test the shared release representation functions before rewiring routes. - A **Release shape** uses explicit representation functions rather than mode strings. - A **Release shape** owns synthetic local cover URL fields as pure string construction; it does not fetch or verify cover files. - A **Release shape** is produced from untrusted external or stored data through explicit normalization before app code treats it as canonical. - A **Release shape** keeps its type contract next to the normalization rules that produce it. - An **Import workflow** has an explicit verification step before confirmed edits are synced to Discogs. - An **Import workflow** must expose enough progress and result state for the UI to explain each step clearly and keep the user informed. - An **Import workflow** applies confirmed edits to the **Local collection** before attempting Discogs sync, so user-confirmed edits are not lost when Discogs is unavailable. - An **Import workflow** receives persistence, parsing, ID, clock, and translation dependencies at module creation time; Discogs access is supplied when the user confirms a preview. - An **Import workflow** interface follows the user-visible journey: upload creates a preview, confirmation applies edits, status reports Discogs progress/result, and clearing dismisses stale results. - An **Import workflow** returns result objects for expected user-facing failures such as invalid files, missing columns, expired previews, and no-change previews. - A **Radar update run** is the primary Radar action and refreshes the Wantlist; it does not perform **Marketplace enrichment** or review prices. - A **Radar update run** preserves local Radar decisions while updating external Wantlist facts. Target price and minimum condition are local preferences and do not produce automatic buying-opportunity classifications. - Radar file import is a fallback workflow, not a competing primary path; after applying imported rows, the interface should guide the user back toward updating Radar rather than launching a full Discogs refresh unexpectedly. - Radar's main list is for scanning wanted releases and choosing what deserves attention; the Radar release detail is where local buying decisions are edited and saved with explicit feedback. - A Radar release detail is a navigable page for one wanted release, not a transient modal. - Radar's main list should stay dense: long notes, minimum condition, hidden, and resolved controls belong in the Radar release detail, not inline in every row. - Radar local decisions are saved explicitly; the interface must distinguish unsaved changes, saving, saved, and failed states. - Radar summary metrics should be operational filters that answer what the user can act on next; total counts and technical states are secondary context. - When a wanted release already exists in the **Local collection**, Radar should expose a navigable collection match, including a link to a local release detail and the number of matching collection copies. - **Account state** is a shared contract used by backend responses and frontend state, not a frontend-only normalization layer. - **Account state** has one target combined shape; first adoption may bridge existing auth and account endpoints before a combined endpoint is added. - **Account state** distinguishes unknown facts from false facts; an unavailable account uses unknown/null Discogs configuration rather than pretending Discogs is unconfigured. - **Account state** includes computed workflow capabilities so pages do not duplicate availability rules. - The first **Account state** implementation slice should rewire `AuthContext` to consume the shared contract rather than leaving the contract unused. - **Account state** is produced from authentication, Discogs account, and preference facts through explicit normalization before pages use it for capability decisions. - **Account state** keeps its type contract next to the normalization rules that produce it. - The **Database schema lifecycle** owns base table creation, legacy table migrations, incremental column migrations, index creation, and startup data cleanup. - The **Database schema lifecycle** exposes one startup entry point that receives an open SQLite database adapter and optional cleanup hooks. - The **Database schema lifecycle** returns a migration report for tests and optional logging; production may ignore the report. ## Example Dialogue > **Dev:** "Should the route own pruning and thumbnail preparation after downloading releases?" > **Domain expert:** "No - those are part of the **Discogs sync run** because the user expects the **Local collection** to be current after syncing." ## Flagged Ambiguities - "sync" can mean only downloading collection pages or the full user-facing refresh. Resolved: use **Discogs sync run** for the full user-facing refresh. - "sync" in Radar can mean only refreshing the Wantlist or the full user-facing Radar update. Resolved: use **Radar update run** for the full Radar action. - **Import workflow** stores confirmed outbound rating and Notes edits in SQLite in the same transaction as their **Local collection** changes. Pending fields overlay incoming **Discogs sync run** data; unrelated note fields continue to reconcile normally. Each field has a fresh revision and exact-value acknowledgement, so older completions cannot clear newer intent, even when the value repeats. - **Import workflow** exposes authenticated `POST /api/import/retry` to retry the user's durable pending fields without another CSV preview. A concurrent import run returns 409. Retry is explicit, survives restart, resolves the current collection folder, and acknowledges successful fields independently. `GET /api/import/status` (and apply/retry responses) adds `pending` and `pendingFailed` as durable field counts; existing `failed`/`failures` describe records in the last in-memory run. After restart the last run is idle, but durable counts remain available. - Individual collection edits and imported writes serialize per user and collection instance in the active server process. Successful individual field edits supersede older pending imports atomically; an import confirmed while an older individual write is awaiting Discogs keeps its newer local value and revision. An equal-local no-op does not acknowledge an unsent pending edit. - A complete collection snapshot may remove an absent instance from the **Local collection**, but its unsent values remain pending with a missing-instance failure. **Account state** reset/deletion cancels active work and clears pending edits. The **Database schema lifecycle** creates this user-scoped storage without changing existing releases. - The durable contract preserves local intent and orders active outbound writers. Cancellation cannot undo a remote write that Discogs already accepted or whose outcome is ambiguous. No background retry runs on startup; explicit retries repeat only set-value rating/field operations. Cross-process writer coordination and a remote atomic snapshot are outside this contract.