Files
muzick/docs/architecture/06-lifecycle-spec.md
T

54 lines
2.7 KiB
Markdown

# Lifecycle & Removal Specification
This document defines the "Dislike $\rightarrow$ Delayed Deletion" lifecycle. This state machine ensures user intent is respected while preventing accidental permanent loss of music.
## 1. The Dislike State Machine
A track follows this state transition to ensure a "Grace Period" before physical deletion.
| Current State | Action | Next State | Side Effects |
| :--- | :--- | :--- | :--- |
| **LIBRARY** | User Dislikes | **PENDING_REMOVAL** | `dislikes` row created; Track becomes `HIDDEN`. |
| **PENDING_REMOVAL** | User Restores | **LIBRARY** | `dislikes` row deleted; Track becomes `VISIBLE`. |
| **PENDING_REMOVAL** | Grace Period Ends | **WARNING_SENT** | `ntfy` notification sent; `warned_at` timestamp set. |
| **WARNING_SENT** | 24h Passes | **DELETED** | File deleted from FS; Track record removed from DB. |
## 2. Detailed Transitions
### **Phase 1: The Dislike (Immediate)**
When a user triggers a dislike:
1. **DB Transaction:**
* Update `tracks.state = 'HIDDEN'`.
* Insert into `dislikes` table `{track_id, disliked_at: now}`.
* Log `feedback(action='disliked')`.
2. **UI Update:** The track immediately disappears from all "active" views (Library, Playlists, Vibe Queue, Search).
### **Phase 2: The Grace Period (The "Safety Net")**
* **Duration ($X$):** Configurable (default: 48 hours).
* **Behavior:** The track remains on disk and in the database, but is filtered out of all user-facing discovery and playback.
### **Phase 3: The Warning (The "Nudge")**
When `now > disliked_at + X`:
1. **Worker Action:** The `Cleanup/Sweep Worker` identifies the track.
2. **Notification:** Sends a message via `ntfy` (e.g., *"Are you sure? '<Track Name>' is scheduled for deletion in 24h"*).
3. **DB Update:** Set `dislikes.warned_at = now`.
### **Phase 4: The Finality (The "Cleanup")**
When `now > warned_at + 24h`:
1. **FS Action:** Delete the physical file at `tracks.path`.
2. **DB Action:**
* Cascade delete all related records (history, play_counts, etc.).
* Remove the `tracks` record.
3. **Logging:** Log `feedback(action='deleted_permanent')`.
## 2. Safety Invariants
- **No Immediate Deletion:** No user action (other than a "Hard Delete" admin command) can trigger immediate file deletion.
- **State Consistency:** A track cannot be in `PENDING_REMOVAL` and `LIBRARY` simultaneously.
- **Atomic Deletion:** The file deletion and the database removal must be treated as a single logical unit of work to prevent "Orphaned Files" (files on disk with no DB record) or "Ghost Records" (DB records with no file).
## 3. User Recovery
The "Restore" action is a simple reversal:
- `DELETE FROM dislikes WHERE track_id = X;`
- `UPDATE tracks SET state = 'LIBRARY' WHERE id = X;`