Revert "chore: status maintenance - multi-account support (#724)"

This reverts commit 53cebb1e985282fd6d287771851659cf8b8b84a5.

Changed files
+177 -188
.status_history
-171
.status_history/2025-12.md
··· 606 606 **documentation** (PR #514): 607 607 - added lexicons overview documentation at `docs/lexicons/overview.md` 608 608 - covers `fm.plyr.track`, `fm.plyr.like`, `fm.plyr.comment`, `fm.plyr.list`, `fm.plyr.actor.profile` 609 - 610 - --- 611 - 612 - ## Late December 2025 Work (Dec 17-31) 613 - 614 - ### offline mode foundation (PRs #610-611, Dec 17) 615 - 616 - **experimental offline playback**: 617 - - storage layer using Cache API for audio bytes + IndexedDB for metadata 618 - - `GET /audio/{file_id}/url` backend endpoint returns direct R2 URLs for client-side caching 619 - - "auto-download liked" toggle in experimental settings section 620 - - Player checks for cached audio before streaming from R2 621 - 622 - --- 623 - 624 - ### UX polish (PRs #604-607, #613, #615, Dec 16-18) 625 - 626 - **login improvements** (PRs #604, #613): 627 - - login page now uses "internet handle" terminology for clarity 628 - - input normalization: strips `@` and `at://` prefixes automatically 629 - 630 - **artist page fixes** (PR #615): 631 - - track pagination on artist pages now works correctly 632 - - fixed mobile album card overflow 633 - 634 - **mobile + metadata** (PRs #605-607): 635 - - Open Graph tags added to tag detail pages for link previews 636 - - mobile modals now use full screen positioning 637 - - fixed `/tag/` routes in hasPageMetadata check 638 - 639 - --- 640 - 641 - ### beartype + moderation cleanup (PRs #617-619, Dec 19) 642 - 643 - **runtime type checking** (PR #619): 644 - - enabled beartype runtime type validation across the backend 645 - - catches type errors at runtime instead of silently passing bad data 646 - - test infrastructure improvements: session-scoped TestClient fixture (5x faster tests) 647 - 648 - **moderation cleanup** (PRs #617-618): 649 - - consolidated moderation code, addressing issues #541-543 650 - - `sync_copyright_resolutions` now runs automatically via docket Perpetual task 651 - - removed dead `init_db()` from lifespan (handled by alembic migrations) 652 - 653 - --- 654 - 655 - ### end-of-year sprint (PR #626, Dec 20) 656 - 657 - **focus**: two foundational systems with experimental implementations. 658 - 659 - | track | focus | status | 660 - |-------|-------|--------| 661 - | moderation | consolidate architecture, batch review, Claude vision | shipped | 662 - | atprotofans | supporter validation, content gating | shipped | 663 - 664 - **research docs**: 665 - - [moderation architecture overhaul](docs/research/2025-12-20-moderation-architecture-overhaul.md) 666 - - [atprotofans paywall integration](docs/research/2025-12-20-atprotofans-paywall-integration.md) 667 - 668 - --- 669 - 670 - ### rate limit moderation endpoint (PR #629, Dec 21) 671 - 672 - **incident response**: detected suspicious activity - 72 requests in 17 seconds from a single IP targeting `/moderation/sensitive-images`. added `10/minute` rate limit using existing slowapi infrastructure. this was the first real probe of our moderation endpoints, validating the decision to add rate limiting before it became a problem. 673 - 674 - --- 675 - 676 - ### supporter badges (PR #627, Dec 21-22) 677 - 678 - **phase 1 of atprotofans integration**: 679 - - supporter badge displays on artist pages when logged-in viewer supports the artist 680 - - calls atprotofans `validateSupporter` API directly from frontend (public endpoint) 681 - - badge only shows when viewer is authenticated and not viewing their own profile 682 - 683 - --- 684 - 685 - ### supporter-gated content (PR #637, Dec 22-23) 686 - 687 - **atprotofans paywall integration** - artists can now mark tracks as "supporters only": 688 - - tracks with `support_gate` require atprotofans validation before playback 689 - - non-supporters see lock icon and "become a supporter" CTA linking to atprotofans 690 - - artists can always play their own gated tracks 691 - 692 - **backend architecture**: 693 - - audio endpoint validates supporter status via atprotofans API before serving gated content 694 - - HEAD requests return 200/401/402 for pre-flight auth checks (avoids CORS issues with cross-origin redirects) 695 - - gated files stored in private R2 bucket, served via presigned URLs (SigV4 signatures) 696 - - `R2Storage.move_audio()` moves files between public/private buckets when toggling gate 697 - - background task handles bucket migration asynchronously 698 - - ATProto record syncs when toggling gate (updates `supportGate` field and `audioUrl` to point at our endpoint instead of R2) 699 - 700 - **frontend**: 701 - - `playback.svelte.ts` guards queue operations with gated checks BEFORE modifying state 702 - - clicking locked track shows toast with CTA - does NOT interrupt current playback 703 - - portal shows support gate toggle in track edit UI 704 - 705 - **key decision**: gated status is resolved server-side in track listings, not client-side. this means the lock icon appears instantly without additional API calls, and prevents information leakage about which tracks are gated vs which the user simply can't access. 706 - 707 - --- 708 - 709 - ### CSS design tokens (PRs #662-664, Dec 29-30) 710 - 711 - **design system foundations**: 712 - - border-radius tokens (`--radius-sm`, `--radius-md`, etc.) 713 - - typography scale tokens 714 - - consolidated form styles 715 - - documented in `docs/frontend/design-tokens.md` 716 - 717 - --- 718 - 719 - ### self-hosted redis (PRs #674-675, Dec 30) 720 - 721 - **replaced Upstash with self-hosted Redis on Fly.io** - ~$75/month → ~$4/month: 722 - - Upstash pay-as-you-go was charging per command (37M commands = $75) - discovered when reviewing December costs 723 - - docket's heartbeat mechanism is chatty by design, making pay-per-command pricing unsuitable 724 - - self-hosted Redis on 256MB Fly VMs costs fixed ~$2/month per environment 725 - - deployed `plyr-redis` (prod) and `plyr-redis-stg` (staging) 726 - - added CI workflow for redis deployments on merge 727 - 728 - **no state migration needed** - docket stores ephemeral task queue data, job progress lives in postgres. 729 - 730 - **incident (Dec 30)**: while optimizing redis overhead, a `heartbeat_interval=30s` change broke docket task execution. likes created Dec 29-30 were missing ATProto records. reverted in PR #669, documented in `docs/backend/background-tasks.md`. filed upstream: https://github.com/chrisguidry/docket/issues/267 731 - 732 - --- 733 - 734 - ### batch review system (PR #672, Dec 30) 735 - 736 - **moderation batch review UI** - mobile-friendly interface for reviewing flagged content: 737 - - filter by flag status, paginated results 738 - - auto-resolve flags for deleted tracks (PR #681) 739 - - full URL in DM notifications (PR #678) 740 - - required auth flow fix (PR #679) - review page was accessible without login 741 - 742 - --- 743 - 744 - ### top tracks homepage (PR #684, Dec 31) 745 - 746 - **homepage now shows top tracks** - quick access to popular content for new visitors. 747 - 748 - --- 749 - 750 - ### avatar sync on login (PR #685, Dec 31) 751 - 752 - **avatars now stay fresh** - previously set once at artist creation, causing stale/broken avatars throughout the app: 753 - - on login, avatar is refreshed from Bluesky and synced to both postgres and ATProto profile record 754 - - added `avatar` field to `fm.plyr.actor.profile` lexicon (optional, URI format) 755 - - one-time backfill script (`scripts/backfill_avatars.py`) refreshed 28 stale avatars in production 756 - 757 - --- 758 - 759 - ### automated image moderation (PRs #687-690, Dec 31) 760 - 761 - **Claude vision integration** for sensitive image detection: 762 - - images analyzed on upload via Claude Sonnet 4.5 (had to fix model ID - was using wrong identifier) 763 - - flagged images trigger DM notifications to admin 764 - - non-false-positive flags sent to batch review queue 765 - - complements the batch review system built earlier in the sprint 766 - 767 - --- 768 - 769 - ### header redesign (PR #691, Dec 31) 770 - 771 - **new header layout** with UserMenu dropdown and even spacing across the top bar. 772 - 773 - --- 774 - 775 - ### UI polish (PRs #692-694, Dec 31 - Jan 1) 776 - 777 - - **feed/library toggle** (PR #692): consistent header layout with toggle between feed and library views 778 - - **shuffle button moved** (PR #693): shuffle now in queue component instead of player controls 779 - - **justfile consistency** (PR #694): standardized `just run` across frontend/backend modules
+177 -17
STATUS.md
··· 137 137 138 138 ### December 2025 139 139 140 + #### header redesign (PR #691, Dec 31) 141 + 142 + **new header layout** with UserMenu dropdown and even spacing across the top bar. 143 + 144 + --- 145 + 146 + #### automated image moderation (PRs #687-690, Dec 31) 147 + 148 + **Claude vision integration** for sensitive image detection: 149 + - images analyzed on upload via Claude Sonnet 4.5 (had to fix model ID - was using wrong identifier) 150 + - flagged images trigger DM notifications to admin 151 + - non-false-positive flags sent to batch review queue 152 + - complements the batch review system built earlier in the sprint 153 + 154 + --- 155 + 156 + #### avatar sync on login (PR #685, Dec 31) 157 + 158 + **avatars now stay fresh** - previously set once at artist creation, causing stale/broken avatars throughout the app: 159 + - on login, avatar is refreshed from Bluesky and synced to both postgres and ATProto profile record 160 + - added `avatar` field to `fm.plyr.actor.profile` lexicon (optional, URI format) 161 + - one-time backfill script (`scripts/backfill_avatars.py`) refreshed 28 stale avatars in production 162 + 163 + --- 164 + 165 + #### top tracks homepage (PR #684, Dec 31) 166 + 167 + **homepage now shows top tracks** - quick access to popular content for new visitors. 168 + 169 + --- 170 + 171 + #### batch review system (PR #672, Dec 30) 172 + 173 + **moderation batch review UI** - mobile-friendly interface for reviewing flagged content: 174 + - filter by flag status, paginated results 175 + - auto-resolve flags for deleted tracks (PR #681) 176 + - full URL in DM notifications (PR #678) 177 + - required auth flow fix (PR #679) - review page was accessible without login 178 + 179 + --- 180 + 181 + #### CSS design tokens (PRs #662-664, Dec 29-30) 182 + 183 + **design system foundations**: 184 + - border-radius tokens (`--radius-sm`, `--radius-md`, etc.) 185 + - typography scale tokens 186 + - consolidated form styles 187 + - documented in `docs/frontend/design-tokens.md` 188 + 189 + --- 190 + 191 + #### self-hosted redis (PRs #674-675, Dec 30) 192 + 193 + **replaced Upstash with self-hosted Redis on Fly.io** - ~$75/month → ~$4/month: 194 + - Upstash pay-as-you-go was charging per command (37M commands = $75) - discovered when reviewing December costs 195 + - docket's heartbeat mechanism is chatty by design, making pay-per-command pricing unsuitable 196 + - self-hosted Redis on 256MB Fly VMs costs fixed ~$2/month per environment 197 + - deployed `plyr-redis` (prod) and `plyr-redis-stg` (staging) 198 + - added CI workflow for redis deployments on merge 199 + 200 + **no state migration needed** - docket stores ephemeral task queue data, job progress lives in postgres. 201 + 202 + **incident (Dec 30)**: while optimizing redis overhead, a `heartbeat_interval=30s` change broke docket task execution. likes created Dec 29-30 were missing ATProto records. reverted in PR #669, documented in `docs/backend/background-tasks.md`. filed upstream: https://github.com/chrisguidry/docket/issues/267 203 + 204 + --- 205 + 206 + #### supporter-gated content (PR #637, Dec 22-23) 207 + 208 + **atprotofans paywall integration** - artists can now mark tracks as "supporters only": 209 + - tracks with `support_gate` require atprotofans validation before playback 210 + - non-supporters see lock icon and "become a supporter" CTA linking to atprotofans 211 + - artists can always play their own gated tracks 212 + 213 + **backend architecture**: 214 + - audio endpoint validates supporter status via atprotofans API before serving gated content 215 + - HEAD requests return 200/401/402 for pre-flight auth checks (avoids CORS issues with cross-origin redirects) 216 + - gated files stored in private R2 bucket, served via presigned URLs (SigV4 signatures) 217 + - `R2Storage.move_audio()` moves files between public/private buckets when toggling gate 218 + - background task handles bucket migration asynchronously 219 + - ATProto record syncs when toggling gate (updates `supportGate` field and `audioUrl` to point at our endpoint instead of R2) 220 + 221 + **frontend**: 222 + - `playback.svelte.ts` guards queue operations with gated checks BEFORE modifying state 223 + - clicking locked track shows toast with CTA - does NOT interrupt current playback 224 + - portal shows support gate toggle in track edit UI 225 + 226 + **key decision**: gated status is resolved server-side in track listings, not client-side. this means the lock icon appears instantly without additional API calls, and prevents information leakage about which tracks are gated vs which the user simply can't access. 227 + 228 + --- 229 + 230 + #### supporter badges (PR #627, Dec 21-22) 231 + 232 + **phase 1 of atprotofans integration**: 233 + - supporter badge displays on artist pages when logged-in viewer supports the artist 234 + - calls atprotofans `validateSupporter` API directly from frontend (public endpoint) 235 + - badge only shows when viewer is authenticated and not viewing their own profile 236 + 237 + --- 238 + 239 + #### rate limit moderation endpoint (PR #629, Dec 21) 240 + 241 + **incident response**: detected suspicious activity - 72 requests in 17 seconds from a single IP targeting `/moderation/sensitive-images`. added `10/minute` rate limit using existing slowapi infrastructure. this was the first real probe of our moderation endpoints, validating the decision to add rate limiting before it became a problem. 242 + 243 + --- 244 + 245 + #### end-of-year sprint (PR #626, Dec 20) 246 + 247 + **focus**: two foundational systems with experimental implementations. 248 + 249 + | track | focus | status | 250 + |-------|-------|--------| 251 + | moderation | consolidate architecture, batch review, Claude vision | shipped | 252 + | atprotofans | supporter validation, content gating | shipped | 253 + 254 + **research docs**: 255 + - [moderation architecture overhaul](docs/research/2025-12-20-moderation-architecture-overhaul.md) 256 + - [atprotofans paywall integration](docs/research/2025-12-20-atprotofans-paywall-integration.md) 257 + 258 + --- 259 + 260 + #### beartype + moderation cleanup (PRs #617-619, Dec 19) 261 + 262 + **runtime type checking** (PR #619): 263 + - enabled beartype runtime type validation across the backend 264 + - catches type errors at runtime instead of silently passing bad data 265 + - test infrastructure improvements: session-scoped TestClient fixture (5x faster tests) 266 + 267 + **moderation cleanup** (PRs #617-618): 268 + - consolidated moderation code, addressing issues #541-543 269 + - `sync_copyright_resolutions` now runs automatically via docket Perpetual task 270 + - removed dead `init_db()` from lifespan (handled by alembic migrations) 271 + 272 + --- 273 + 274 + #### UX polish (PRs #604-607, #613, #615, Dec 16-18) 275 + 276 + **login improvements** (PRs #604, #613): 277 + - login page now uses "internet handle" terminology for clarity 278 + - input normalization: strips `@` and `at://` prefixes automatically 279 + 280 + **artist page fixes** (PR #615): 281 + - track pagination on artist pages now works correctly 282 + - fixed mobile album card overflow 283 + 284 + **mobile + metadata** (PRs #605-607): 285 + - Open Graph tags added to tag detail pages for link previews 286 + - mobile modals now use full screen positioning 287 + - fixed `/tag/` routes in hasPageMetadata check 288 + 289 + --- 290 + 291 + #### offline mode foundation (PRs #610-611, Dec 17) 292 + 293 + **experimental offline playback**: 294 + - storage layer using Cache API for audio bytes + IndexedDB for metadata 295 + - `GET /audio/{file_id}/url` backend endpoint returns direct R2 URLs for client-side caching 296 + - "auto-download liked" toggle in experimental settings section 297 + - Player checks for cached audio before streaming from R2 298 + 299 + --- 300 + 301 + ### Earlier December 2025 302 + 140 303 See `.status_history/2025-12.md` for detailed history including: 141 - - header redesign and UI polish (PRs #691-694, Dec 31) 142 - - automated image moderation via Claude vision (PRs #687-690, Dec 31) 143 - - avatar sync on login (PR #685, Dec 31) 144 - - top tracks homepage (PR #684, Dec 31) 145 - - batch review system (PR #672, Dec 30) 146 - - CSS design tokens (PRs #662-664, Dec 29-30) 147 - - self-hosted redis migration (PRs #674-675, Dec 30) 148 - - supporter-gated content (PR #637, Dec 22-23) 149 - - supporter badges (PR #627, Dec 21-22) 150 - - end-of-year sprint: moderation + atprotofans (PR #626, Dec 20) 151 - - offline mode foundation (PRs #610-611, Dec 17) 152 - - UX polish and login improvements (PRs #604-615, Dec 16-18) 153 - - visual customization (PRs #595-596, Dec 16) 154 - - confidential OAuth client (PRs #578-582, Dec 12-13) 155 - - docket background tasks (PRs #534-546, Dec 9) 156 - - playlists and library hub (PR #499, Dec 6-7) 304 + - visual customization with custom backgrounds (PRs #595-596, Dec 16) 305 + - performance & moderation polish (PRs #586-593, Dec 14-15) 306 + - mobile UI polish & background task expansion (PRs #558-572, Dec 10-12) 307 + - confidential OAuth client for 180-day sessions (PRs #578-582, Dec 12-13) 308 + - pagination & album management (PRs #550-554, Dec 9-10) 309 + - public cost dashboard (PRs #548-549, Dec 9) 310 + - docket background tasks & concurrent exports (PRs #534-546, Dec 9) 311 + - artist support links & inline playlist editing (PRs #520-532, Dec 8) 312 + - playlist fast-follow fixes (PRs #507-519, Dec 7-8) 313 + - playlists, ATProto sync, and library hub (PR #499, Dec 6-7) 314 + - sensitive image moderation (PRs #471-488, Dec 5-6) 315 + - teal.fm scrobbling (PR #467, Dec 4) 157 316 - unified search with Cmd+K (PR #447, Dec 3) 158 317 - light/dark theme system (PR #441, Dec 2-3) 318 + - tag filtering and bufo easter egg (PRs #431-438, Dec 2) 159 319 160 320 ### November 2025 161 321 ··· 338 498 339 499 --- 340 500 341 - this is a living document. last updated 2026-01-06. 501 + this is a living document. last updated 2026-01-05.
update.wav

This is a binary file and will not be displayed.