Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 278 lines 8.8 kB view raw view rendered
1# ATProto Sync Implementation Progress 2 3## Completed Work ✅ 4 5### 1. Unified Media Module (media-atproto.mjs) 6**Status:** ✅ Complete and tested 7 8**Features:** 9- Single source of truth for all ATProto media operations 10- Support for 5 media types: paintings, moods, pieces, kidlisp, tapes 11- Proper lexicon implementation with full schemas 12- Blob generation for paintings (thumbnails via /api/pixel) 13- Recording detection for paintings (checks ZIP existence) 14- Guest/anonymous user support 15 16**Lexicons Implemented:** 17-**Paintings**: `computer.aesthetic.painting` 18 - Fields: slug, code, imageUrl, acUrl, when, ref 19 - Blob: 512x512 thumbnail (via /api/pixel :contain mode) 20 - Optional: recordingUrl (if ZIP exists) 21 22-**Moods**: `computer.aesthetic.mood` 23 - Fields: text, when, ref 24 - No blob, no anonymous support 25 26-**Pieces**: `computer.aesthetic.piece` 27 - Fields: slug, when, ref 28 - No blob, supports anonymous 29 30-**Kidlisp**: `computer.aesthetic.kidlisp` 31 - Fields: code, source, acUrl, when, ref 32 - No blob, supports anonymous 33 34-**Tapes**: `computer.aesthetic.tape` 35 - Fields: slug, code, zipUrl, acUrl, when, ref 36 - Blob: MP4 video (TODO: conversion not implemented yet) 37 - Supports anonymous 38 39**URL Formats:** 40- Paintings: `https://aesthetic.computer/#${code}` (hash symbol) 41- Kidlisp: `https://aesthetic.computer/$${code}` (dollar symbol) 42- Tapes: `https://aesthetic.computer/!${code}` (exclamation symbol) 43 44**Media URLs:** 45- Paintings image: `https://aesthetic.computer/media/paintings/${code}` 46- Paintings recording: `https://aesthetic.computer/media/paintings/${code}.zip` 47- Tapes ZIP: Direct to DigitalOcean Spaces (no short code routing yet) 48 49### 2. Sync Script Optimizations (sync-atproto.mjs) 50**Status:** ✅ Complete 51 52**Performance:** 53- Parallel user processing: 50 users at a time 54- Batch creates: 10 concurrent (reduced from 50 to avoid rate limiting) 55- Batch MongoDB updates: bulkWrite with 100 ops per batch 56 57**Admin Tools:** 58- `--wipe=handle`: Delete all ATProto records + clear MongoDB rkeys 59- `--restore=handle`: Sync MongoDB → ATProto per user 60- Content type filtering: `--paintings-only`, `--moods-only`, etc. 61- Dry run support: Test without making changes 62 63**Anonymous/Guest Support:** 64- ✅ Wipe supports art.at.aesthetic.computer 65- ✅ Restore supports art.at.aesthetic.computer 66- ✅ Anonymous content query: `{ user: { $exists: false } }` 67- ✅ User content query: `{ user: userId }` 68 69### 3. Real-Time Sync Integration 70**Status:** ✅ Complete 71 72**Netlify Functions Updated:** 73-`track-media.mjs`: Auto-syncs paintings/pieces after MongoDB insert 74-`store-kidlisp.mjs`: Auto-syncs kidlisp after MongoDB insert 75- ✅ Background sync: Fire-and-forget, doesn't block response 76- ✅ MongoDB updates: Stores rkey after successful ATProto creation 77 78### 4. Testing Completed 79**Status:** ✅ Verified with jeffrey.at.aesthetic.computer 80 81**Test Results:** 82- ✅ Moods: 226/226 synced successfully 83- ✅ Pieces: 26/26 synced successfully 84- ✅ Kidlisp: 168/2220 synced (partial test, working) 85- ✅ Paintings: 19/395 synced (partial test, working with blobs) 86- ✅ Blob generation: Confirmed working (~9KB thumbnails) 87- ✅ Lexicons: All fields present and correct 88- ✅ Rate limiting: 10/batch stable, no errors 89 90## Current Sprint 🎯 91 92### Anonymous Tape Testing 93 94**Goal:** Test MP4 blob workflow with anonymous tapes 95 96**Plan:** 971. ✅ Update wipe/restore to support art.at.aesthetic.computer 982. ✅ Add anonymous content queries (no user field) 993. ⏳ Wipe art.at.aesthetic.computer ATProto data 1004. ⏳ Restore ONLY tapes (32 anonymous tapes) 1015. ⏳ Test MP4 blob generation workflow 1026. ⏳ Verify tape records in ATProto 103 104**Anonymous Tape Data:** 105- Total: 32 tapes 106- User: undefined (no user field) 107- Bucket: art-aesthetic-computer 108- Format: ZIP with frames + timing.json + metadata.json 109 110**Sample Tapes:** 111```json 112[ 113 { 114 "code": "9Yo", 115 "slug": "OJZDQoBh", 116 "when": "2025-10-17T23:43:17.100Z", 117 "bucket": "art-aesthetic-computer" 118 }, 119 { 120 "code": "Eue", 121 "slug": "lYrrBWh5", 122 "when": "2025-10-18T05:28:11.538Z", 123 "bucket": "art-aesthetic-computer" 124 } 125] 126``` 127 128**Next Steps:** 1291. Run wipe: `node sync-atproto.mjs live --wipe=art.at.aesthetic.computer --tapes-only` 1302. Run restore: `node sync-atproto.mjs live --restore=art.at.aesthetic.computer --tapes-only` 1313. Observe MP4 blob workflow (will show TODO warning for now) 1324. Document what's needed for MP4 conversion 133 134## Pending Work 📋 135 136### 1. Tape MP4 Conversion 137**Status:** ⏳ Documented, not implemented 138 139**Plan:** See `TAPE-MP4-CONVERSION-PLAN.md` 140 141**Implementation Phases:** 142- Phase 1: ✅ Basic sync without MP4 (current state) 143- Phase 2: ⏳ Local MP4 conversion using ffmpeg 144- Phase 3: ⏳ Production deployment 145 146**Technical Requirements:** 147- Download ZIP from storage 148- Extract frames and timing.json 149- Convert to MP4 using ffmpeg 150- Upload MP4 blob to ATProto 151- Include video blob in tape record 152 153### 2. Full User Sync 154**Status:** ⏳ Ready to run after tape testing 155 156**jeffrey.at.aesthetic.computer:** 157- 395 paintings (with blobs + recordings) 158- 226 moods 159- 26 pieces 160- 2220 kidlisp 161- 0 tapes (user tapes don't exist yet) 162 163**Estimated Time:** 164- Paintings: ~40 minutes (blob generation + rate limiting) 165- Moods: ~2 minutes 166- Pieces: ~1 minute 167- Kidlisp: ~20 minutes 168- Total: ~1 hour for full sync 169 170### 3. Production Rollout 171**Status:** ⏳ After testing complete 172 173**Tasks:** 174- [ ] Commit all changes to main 175- [ ] Full sync for all 4,201 users 176- [ ] Monitor logs for errors 177- [ ] Verify data quality in ATProto 178- [ ] Deploy Netlify function updates 179 180**Files to Commit:** 181- NEW: `media-atproto.mjs` (330+ lines) 182- NEW: `ATPROTO-SYNC-CONSOLIDATION-PLAN.md` 183- NEW: `ATPROTO-SYNC-PROGRESS.md` 184- NEW: `TAPE-MP4-CONVERSION-PLAN.md` 185- MODIFIED: `sync-atproto.mjs` (refactored to use media-atproto) 186- MODIFIED: `track-media.mjs` (real-time sync) 187- MODIFIED: `store-kidlisp.mjs` (real-time sync) 188- MODIFIED: `tape-atproto.mjs` (added acUrl) 189 190### 4. Deprecation 191**Status:** ⏳ After commit 192 193**Files to Remove:** 194- `painting-atproto.mjs` (logic moved to media-atproto.mjs) 195 196## Architecture Decisions 📐 197 198### Why Unified Module? 199- **Before**: Duplicate logic in painting-atproto.mjs, sync-atproto.mjs, Netlify functions 200- **After**: Single source of truth in media-atproto.mjs 201- **Benefits**: 202 - Consistent lexicons across all entry points 203 - Easier to maintain and extend 204 - Single place to update ATProto logic 205 206### Why Short Code URLs? 207- **Permanent**: Codes don't change even if handles change 208- **Shareable**: Short, memorable codes (#abc, $def, !ghi) 209- **Routable**: Edge function handles redirects to storage 210- **ATProto-friendly**: Clean URLs for external apps 211 212### Why Separate Tape Module? 213- **Before**: Considered adding tapes to unified module 214- **After**: Tapes keep separate tape-atproto.mjs due to async MP4 workflow 215- **Rationale**: MP4 conversion is async webhook-driven, different from other media 216 217### Why Local MP4 Conversion for Sync? 218- **Flexibility**: Control quality and conversion parameters 219- **Testing**: Easier to iterate and debug locally 220- **Deployment**: Can be deployed incrementally 221- **Async**: Production can use webhook service if needed 222 223## Metrics 📊 224 225### Performance 226- Users processed: ~50/batch 227- Creates per batch: 10 concurrent 228- Throughput: ~100 records/minute 229- Rate limit avoidance: 10/batch stable 230 231### Data Quality 232- Blob sizes: 7-12KB thumbnails 233- Lexicon compliance: 100% 234- Recording detection: Working (HEAD request to ZIP) 235- URL formats: All using short codes 236 237### Coverage 238- Total users: 4,201 239- Users with ATProto accounts: TBD 240- Anonymous tapes: 32 241- Authenticated tapes: 3 (jeffrey has 0) 242 243## Known Issues 🐛 244 245### 1. MP4 Conversion Not Implemented 246**Status:** Expected, documented 247**Workaround:** Tapes sync without video blob for now 248**Fix:** Implement tape-to-mp4.mjs module (see TAPE-MP4-CONVERSION-PLAN.md) 249 250### 2. No Short Code Routing for Tape ZIPs 251**Status:** Known limitation 252**Impact:** Tape zipUrl uses direct DigitalOcean URL 253**Fix:** Add `/media/tapes/CODE` routing to edge function 254 255### 3. Rate Limiting at 50 Concurrent 256**Status:** Fixed 257**Solution:** Reduced to 10 concurrent creates 258**Result:** Stable, no more "Internal Server Error" 259 260## Next Actions 🎬 261 262**Immediate (Today):** 2631. ✅ Document progress 2642. ⏳ Wipe art.at.aesthetic.computer 2653. ⏳ Restore tapes only 2664. ⏳ Test and document MP4 workflow needs 267 268**Short Term (This Week):** 2691. Implement tape MP4 conversion 2702. Full sync for jeffrey.at.aesthetic.computer 2713. Verify all data in ATProto 2724. Commit changes to main 273 274**Long Term (Next Week):** 2751. Full sync for all 4,201 users 2762. Monitor production performance 2773. Optimize if needed 2784. Document lessons learned