Add specs for the account menu, downloads-as-offline-library, offline downloaded-only filter, and scoped search (+ boundary revision). Add the new UR/DR entries to requirements.md, update ux-flows, and regenerate the traceability matrix. TRACES: UR-049, UR-050, UR-052, UR-053, UR-054, UR-055, UR-056
106 lines
4.1 KiB
Markdown
106 lines
4.1 KiB
Markdown
# Spec: <feature name>
|
||
|
||
<!--
|
||
Copy this file to docs/specs/<kebab-name>.md and fill it in. Delete the HTML
|
||
comments as you go. The section that matters most for this project is
|
||
"Layer assignment" — read its comment before writing it.
|
||
|
||
Before merging a spec, run it past docs/specs/SPEC-REVIEW-CHECKLIST.md.
|
||
-->
|
||
|
||
**Status:** Proposed <!-- Proposed | Accepted | Implemented | Superseded -->
|
||
**Requirements:** <!-- UR-xxx → DR-yyy; allocate new DRs in requirements.md. -->
|
||
**UX spec:** <!-- link to the relevant ux-flows.md section, or "n/a". -->
|
||
**Supersedes / revises:** <!-- link any spec this changes, or delete this line. -->
|
||
|
||
## Summary
|
||
|
||
<!-- 2–4 sentences. What changes for the user, in plain terms. -->
|
||
|
||
## Motivation
|
||
|
||
<!-- Why now. The problem being solved. -->
|
||
|
||
## Layer assignment
|
||
|
||
<!--
|
||
🔴 THIS IS THE SECTION THAT KEEPS THE ARCHITECTURE HONEST. Do not skip it, and
|
||
do NOT reframe it as "how little backend work can we get away with."
|
||
|
||
The project rule (CLAUDE.md, architecture/02-svelte-frontend.md): the Rust
|
||
backend owns ALL business logic — auth, catalog, sessions, downloads, offline,
|
||
playback, AND domain vocabulary (e.g. what Jellyfin item types the category
|
||
"Music" means). The Svelte frontend is PRESENTATION ONLY: rendering, layout,
|
||
navigation, view/order preferences, input handling.
|
||
|
||
For each distinct piece of *logic* this feature introduces, put it in the table
|
||
and name the layer it belongs to and WHY. "It's less work in the frontend" and
|
||
"the backend already accepts this parameter" are NOT reasons to place logic in
|
||
the frontend — the backend accepting a parameter does not make deciding that
|
||
parameter's value a presentation concern.
|
||
|
||
Litmus test for "does this belong in Rust?": Would this logic have to change if
|
||
Jellyfin changed its API, added an item type, or altered a business rule? If
|
||
yes, it is domain logic → Rust. Would it change if we redesigned the UI? If
|
||
yes (and only yes), it is presentation → frontend.
|
||
|
||
A past incident: scoped-search.md placed the item-type taxonomy (what "Music"
|
||
means as a set of Jellyfin types) in the frontend because the backend already
|
||
accepted an includeItemTypes filter. That was a boundary leak; see
|
||
scoped-search-boundary.md. This section exists to catch that class of mistake
|
||
at spec time, not in review three features later.
|
||
-->
|
||
|
||
| Logic / responsibility | Layer | Why it belongs there |
|
||
|------------------------|-------|----------------------|
|
||
| <!-- e.g. scope → item-types --> | Rust | <!-- domain vocabulary; changes with Jellyfin's API --> |
|
||
| <!-- e.g. group display order --> | Frontend | <!-- pure presentation; changes only if UI is redesigned --> |
|
||
|
||
<!--
|
||
If a row is genuinely borderline, say so and give the tie-breaker you used.
|
||
Borderline defaults to Rust for anything touching domain data or vocabulary.
|
||
-->
|
||
|
||
## Design
|
||
|
||
<!--
|
||
How it works. Wire shapes for anything crossing the IPC boundary. Remember:
|
||
- Command NAME must match the Rust fn name exactly.
|
||
- Top-level params auto-convert snake_case → camelCase (Tauri v2).
|
||
- Nested struct fields need #[serde(rename_all = "camelCase")].
|
||
- Events are kebab-case.
|
||
(See CLAUDE.md §IPC and architecture/04-type-sync-and-threading.md.)
|
||
|
||
Regenerate bindings.ts from Rust types; never hand-edit it.
|
||
-->
|
||
|
||
## Out of scope
|
||
|
||
<!-- What this spec deliberately does NOT do. -->
|
||
|
||
## Acceptance criteria
|
||
|
||
<!-- Checkable statements. Include the standard gates: -->
|
||
|
||
- [ ] `bun run check` and `bun run test` pass.
|
||
- [ ] `cargo fmt` clean, `cargo clippy` clean, `bun run test:rust` passes (if Rust changed).
|
||
- [ ] `bun run check:boundary` passes (no taxonomy leak into the frontend).
|
||
- [ ] New requirement-implementing code carries `// TRACES:` comments.
|
||
- [ ] `bindings.ts` regenerated if Rust types changed.
|
||
|
||
## Testing
|
||
|
||
<!-- Rust: cargo test. Frontend: vitest, src/lib/**/*.test.ts. What to cover. -->
|
||
|
||
## TRACES
|
||
|
||
<!-- Suggested tags per new/changed piece: UR-xxx | DR-yyy | tests. -->
|
||
|
||
## Notes for the implementer
|
||
|
||
<!--
|
||
- A parallel Claude session may be active in this repo — `git diff` before
|
||
"repairing" unexpected changes (see project memory / CLAUDE.md gotchas).
|
||
- Anything else non-obvious.
|
||
-->
|