initial state: muzick music player + recommendation engine
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
# 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;`
|
||||
Reference in New Issue
Block a user