feat: add /deploy claude command (#493)

* feat: add /deploy claude command

automates production deployment with preflight checks:
- verifies clean working tree, on main, up to date
- analyzes changes to determine frontend vs backend
- runs appropriate just target
- pushes to tangled remote

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* docs: add bluesky thread link to bufo section in STATUS.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>

authored by zzstoatzz.io Claude and committed by GitHub 2f59f9e7 2634ed2c

Changed files
+73 -2
.claude
commands
+51
.claude/commands/deploy.md
···
··· 1 + # deploy 2 + 3 + deploy to production with preflight checks. 4 + 5 + ## preflight checks 6 + 7 + run these checks and report any issues before proceeding: 8 + 9 + 1. **clean working tree** - `git status` should show nothing to commit 10 + 2. **on main branch** - `git branch --show-current` should be `main` 11 + 3. **up to date with origin** - `git fetch origin && git status` should not be behind 12 + 4. **no open PRs from your branch** - check for any unmerged work 13 + 14 + ## analyze changes 15 + 16 + determine what changed since last release: 17 + 18 + ```bash 19 + just changelog 20 + ``` 21 + 22 + categorize changes: 23 + - **backend changes**: anything in `backend/`, `scripts/`, root config files 24 + - **frontend changes**: anything in `frontend/` 25 + - **docs only**: only changes to `docs/`, `STATUS.md`, `*.md` files 26 + 27 + report the change summary to the user. 28 + 29 + ## deployment decision 30 + 31 + based on the changes: 32 + - if **backend changes**: full release needed (`just release`) 33 + - if **frontend only**: can use `just release-frontend-only` (faster) 34 + - if **docs only**: no deployment needed, but can release if desired 35 + 36 + ask for confirmation before proceeding. 37 + 38 + ## execute deployment 39 + 40 + if confirmed: 41 + 42 + 1. run `just release` (or `just release-frontend-only` if applicable) 43 + 2. push to tangled remote: `git push tangled main --tags` 44 + 3. report the release tag and deployment status 45 + 46 + ## post-deployment 47 + 48 + remind the user to: 49 + - verify staging at https://stg.plyr.fm (frontend auto-deploys) 50 + - monitor fly.io dashboard for backend deployment status 51 + - check https://plyr.fm once deployment completes
+22 -2
STATUS.md
··· 47 48 ### December 2025 49 50 #### mobile artwork upload fix (PR #489, Dec 6) 51 52 **problem**: artwork uploads from iOS Photos library silently failed - track uploaded successfully but without artwork. ··· 201 - album detail endpoint (`/albums/{handle}/{slug}`) now returns tags for all tracks 202 - track detail page displays clickable tag badges 203 204 - **bufo easter egg** (PR #438): 205 - tracks tagged with `bufo` trigger animated toad GIFs on the detail page 206 - uses track title as semantic search query against [find-bufo API](https://find-bufo.fly.dev/) 207 - toads are semantically matched to the song's vibe (e.g., "Happy Vibes" gets happy toads) 208 - results cached in localStorage (1 week TTL) to minimize API calls 209 - `TagEffects` wrapper component provides extensibility for future tag-based plugins 210 - respects `prefers-reduced-motion`; fails gracefully if API unavailable 211 212 --- 213 ··· 557 558 --- 559 560 - this is a living document. last updated 2025-12-06.
··· 47 48 ### December 2025 49 50 + #### bufo easter egg improvements (PRs #491-492, Dec 6) 51 + 52 + **what shipped**: 53 + - configurable exclude/include patterns via env vars for bufo easter egg 54 + - `BUFO_EXCLUDE_PATTERNS`: regex patterns to filter out (default: `^bigbufo_`) 55 + - `BUFO_INCLUDE_PATTERNS`: allowlist that overrides exclude (default: `bigbufo_0_0`, `bigbufo_2_1`) 56 + - cache key now includes patterns so config changes take effect immediately 57 + 58 + **reusable type**: 59 + - added `CommaSeparatedStringSet` type for parsing comma-delimited env vars into sets 60 + - uses pydantic `BeforeValidator` with `Annotated` pattern (not class-coupled validators) 61 + - handles: `VAR=a,b,c` → `{"a", "b", "c"}` 62 + 63 + **context**: bigbufo tiles are 4x4 grid fragments that looked weird floating individually. now excluded by default, with two specific tiles allowed through. 64 + 65 + **thread**: https://bsky.app/profile/zzstoatzzdevlog.bsky.social/post/3m7e3ndmgwl2m 66 + 67 + --- 68 + 69 #### mobile artwork upload fix (PR #489, Dec 6) 70 71 **problem**: artwork uploads from iOS Photos library silently failed - track uploaded successfully but without artwork. ··· 220 - album detail endpoint (`/albums/{handle}/{slug}`) now returns tags for all tracks 221 - track detail page displays clickable tag badges 222 223 + **bufo easter egg** (PR #438, improved in #491-492): 224 - tracks tagged with `bufo` trigger animated toad GIFs on the detail page 225 - uses track title as semantic search query against [find-bufo API](https://find-bufo.fly.dev/) 226 - toads are semantically matched to the song's vibe (e.g., "Happy Vibes" gets happy toads) 227 - results cached in localStorage (1 week TTL) to minimize API calls 228 - `TagEffects` wrapper component provides extensibility for future tag-based plugins 229 - respects `prefers-reduced-motion`; fails gracefully if API unavailable 230 + - configurable exclude/include patterns via env vars (see Dec 6 entry above) 231 232 --- 233 ··· 577 578 --- 579 580 + this is a living document. last updated 2025-12-06 (release 2025.1206.222902).