music on atproto
plyr.fm
Offboarding & Data Export#
Plyr.fm provides tools for users to export their data and manage their presence on the platform. This document outlines the architecture and workflows for these features.
Data Export#
Users can download a ZIP archive containing all their uploaded tracks in their original format.
Workflow#
-
Initiation:
- User clicks "Export" in the portal.
- Frontend calls
POST /exports/media. - Backend creates a
Jobrecord (type:export) and starts a background task. - Returns an
export_id.
-
Processing:
- Backend queries all tracks for the user.
- Backend streams files from R2 storage into a ZIP archive in memory (using a stream buffer to minimize memory usage).
- As tracks are processed, the job progress is updated in the database.
- The final ZIP file is uploaded to R2 under the
exports/prefix. - The R2 object is tagged with
Content-Dispositionto ensure a friendly filename (e.g.,plyr-tracks-2024-03-20.zip) upon download.
-
Completion & Download:
- Frontend polls the job status via SSE at
/exports/{export_id}/progress. - Once completed, the job result contains a direct
download_urlto the R2 object. - Frontend triggers a browser download using this URL.
- Frontend polls the job status via SSE at
Storage & Cleanup#
- Location: Exports are stored in the
audiobucket under theexports/prefix. - Retention: These files are temporary. An R2 Lifecycle Rule is configured to automatically delete files in
exports/after 24 hours.- This ensures we don't pay for indefinite storage of duplicate data.
- Users must download their export within this window.
Account Deletion#
Users can permanently delete their account and all associated data. This is a synchronous, interactive process.
What Gets Deleted#
Always Deleted (plyr.fm infrastructure)#
| Location | Data |
|---|---|
| PostgreSQL | tracks, albums, likes (given), comments (made), preferences, sessions, queue entries, jobs |
| R2 Storage | audio files, track cover images, album cover images |
Optionally Deleted (user's ATProto PDS)#
If the user opts in, we delete records from their Personal Data Server:
| Collection | Description |
|---|---|
fm.plyr.track / fm.plyr.dev.track |
track metadata records |
fm.plyr.like / fm.plyr.dev.like |
like records |
fm.plyr.comment / fm.plyr.dev.comment |
comment records |
Note: ATProto deletion requires a valid authenticated session. If the session has expired or lacks required scopes, ATProto records will remain on the user's PDS but all plyr.fm data will still be deleted.
Workflow#
- Confirmation: User types their handle to confirm intent
- ATProto Option: Checkbox to opt into deleting ATProto records
- Processing:
- Delete R2 objects (audio, images)
- Delete database records in dependency order
- If opted in: delete ATProto records via PDS API
- Session Cleanup: All sessions invalidated, user logged out
API#
DELETE /account/
Request Body:
{
"confirmation": "handle.bsky.social",
"delete_atproto_records": true
}
Response (success):
{
"deleted": {
"tracks": 5,
"albums": 1,
"likes": 12,
"comments": 3,
"r2_objects": 11,
"atproto_records": 20
}
}
Important Notes#
- Irreversible: There is no undo. Export data first if needed.
- Likes received: Likes from other users on your tracks are deleted when your tracks are deleted.
- Comments received: Comments from other users on your tracks are deleted when your tracks are deleted.
- ATProto propagation: Even after deletion from your PDS, cached copies may exist on relay servers temporarily.