# v1.2.0 Developer Q&A **Date**: 2025-11-28 **Architect**: StarPunk Architect Subagent **Purpose**: Answer critical implementation questions for v1.2.0 ## Custom Slugs Answers **Q1: Validation pattern conflict - should we apply new lowercase validation to existing slugs?** - **Answer:** Validate only new custom slugs, don't migrate existing slugs - **Rationale:** Existing slugs work, no need to change them retroactively - **Implementation:** In `validate_and_sanitize_custom_slug()`, apply lowercase enforcement only to new/edited slugs **Q2: Form field readonly behavior - how should the slug field behave on edit forms?** - **Answer:** Display as readonly input field with current value visible - **Rationale:** Users need to see the current slug but understand it cannot be changed - **Implementation:** Use `readonly` attribute, not `disabled` (disabled fields don't submit with form) **Q3: Slug uniqueness validation - where should this happen?** - **Answer:** Both client-side (for UX) and server-side (for security) - **Rationale:** Client-side prevents unnecessary submissions, server-side is authoritative - **Implementation:** Database unique constraint + Python validation in `validate_and_sanitize_custom_slug()` ## Media Upload Answers **Q4: Media upload flow - how should upload and note association work?** - **Answer:** Upload during note creation, associate via note_id after creation - **Rationale:** Simpler than pre-upload with temporary IDs - **Implementation:** Upload files in `create_note_submit()` after note is created, store associations in media table **Q5: Storage directory structure - exact path format?** - **Answer:** `data/media/YYYY/MM/filename-uuid.ext` - **Rationale:** Date organization helps with backups and management - **Implementation:** Use `os.makedirs(path, exist_ok=True)` to create directories as needed **Q6: File naming convention - how to ensure uniqueness?** - **Answer:** `{original_name_slug}-{uuid4()[:8]}.{extension}` - **Rationale:** Preserves original name for SEO while ensuring uniqueness - **Implementation:** Slugify original filename, append 8-char UUID, preserve extension **Q7: MIME type validation - which types exactly?** - **Answer:** Allow: image/jpeg, image/png, image/gif, image/webp. Reject all others - **Rationale:** Common web formats only, no SVG (XSS risk) - **Implementation:** Use python-magic for reliable MIME detection, not just file extension **Q8: Upload size limits - what's reasonable?** - **Answer:** 10MB per file, 40MB total per note (4 files × 10MB) - **Rationale:** Sufficient for high-quality images without overwhelming storage - **Implementation:** Check in both client-side JavaScript and server-side validation **Q9: Database schema for media table - exact columns?** - **Answer:** id, note_id, filename, mime_type, size_bytes, width, height, uploaded_at - **Rationale:** Minimal but sufficient metadata for display and management - **Implementation:** Use Pillow to extract image dimensions on upload **Q10: Orphaned file cleanup - how to handle?** - **Answer:** Keep orphaned files, add admin cleanup tool in future version - **Rationale:** Data preservation is priority, cleanup can be manual for v1.2.0 - **Implementation:** Log orphaned files but don't auto-delete **Q11: Upload progress indication - required for v1.2.0?** - **Answer:** No, simple form submission is sufficient for v1.2.0 - **Rationale:** Keep it simple, can enhance in future version - **Implementation:** Standard HTML form with enctype="multipart/form-data" **Q12: Image display order - how to maintain?** - **Answer:** Use upload sequence, store display_order in media table - **Rationale:** Predictable and simple - **Implementation:** Auto-increment display_order starting at 0 **Q13: Thumbnail generation - needed for v1.2.0?** - **Answer:** No, use CSS for responsive sizing - **Rationale:** Simplicity over optimization for v1 - **Implementation:** Use `max-width: 100%` and lazy loading **Q14: Edit form media handling - can users remove media?** - **Answer:** Yes, checkbox to mark for deletion - **Rationale:** Essential editing capability - **Implementation:** "Remove" checkboxes next to each image in edit form **Q15: Media URL structure - exact format?** - **Answer:** `/media/YYYY/MM/filename.ext` (matches storage path) - **Rationale:** Clean URLs, date organization visible - **Implementation:** Route in `starpunk/routes/public.py` using send_from_directory ## Author Discovery Answers **Q16: Discovery failure handling - what if profile URL is unreachable?** - **Answer:** Use defaults: name from IndieAuth me URL domain, no photo - **Rationale:** Always provide something, never break - **Implementation:** Try discovery, catch all exceptions, use defaults **Q17: h-card parsing library - which one?** - **Answer:** Use mf2py (already in requirements for Micropub) - **Rationale:** Already a dependency, well-maintained - **Implementation:** `import mf2py; result = mf2py.parse(url=profile_url)` **Q18: Multiple h-cards on profile - which to use?** - **Answer:** First h-card with url property matching the profile URL - **Rationale:** Most specific match per IndieWeb convention - **Implementation:** Loop through h-cards, check url property **Q19: Discovery caching duration - how long?** - **Answer:** 24 hours, with manual refresh button in admin - **Rationale:** Balance between freshness and performance - **Implementation:** Store discovered_at timestamp, check age **Q20: Profile update mechanism - when to refresh?** - **Answer:** On login + manual refresh button + 24hr expiry - **Rationale:** Login is natural refresh point - **Implementation:** Call discovery in auth callback **Q21: Missing properties handling - what if no name/photo?** - **Answer:** name = domain from URL, photo = None (no image) - **Rationale:** Graceful degradation - **Implementation:** Use get() with defaults on parsed properties **Q22: Database schema for author_profile - exact columns?** - **Answer:** me_url (PK), name, photo, url, discovered_at, raw_data (JSON) - **Rationale:** Cache parsed data + raw for debugging - **Implementation:** Single row table, upsert on discovery ## Microformats2 Answers **Q23: h-card placement - where exactly in templates?** - **Answer:** Only within h-entry author property (p-author h-card) - **Rationale:** Correct semantic placement per spec - **Implementation:** In note partial template, not standalone **Q24: h-feed container - which pages need it?** - **Answer:** Homepage (/) and any paginated list pages - **Rationale:** Feed pages only, not single note pages - **Implementation:** Wrap note list in div.h-feed with h1.p-name **Q25: Optional properties - which to include?** - **Answer:** Only what we have: author, name, url, published, content - **Rationale:** Don't add empty properties - **Implementation:** Use conditional template blocks **Q26: Micropub compatibility - any changes needed?** - **Answer:** No, Micropub already handles microformats correctly - **Rationale:** Micropub creates data, templates display it - **Implementation:** Ensure templates match Micropub's data model ## Feed Integration Answers **Q27: RSS/Atom changes for media - how to include images?** - **Answer:** Add as enclosures (RSS) and link rel="enclosure" (Atom) - **Rationale:** Standard podcast/media pattern - **Implementation:** Loop through note.media, add enclosure elements **Q28: JSON Feed media handling - which property?** - **Answer:** Use "attachments" array per JSON Feed 1.1 spec - **Rationale:** Designed for exactly this use case - **Implementation:** Create attachment objects with url, mime_type **Q29: Feed caching - any changes needed?** - **Answer:** No, existing cache logic is sufficient - **Rationale:** Media URLs are stable once uploaded - **Implementation:** No changes required **Q30: Author in feeds - use discovered data?** - **Answer:** Yes, use discovered name and photo in feed metadata - **Rationale:** Consistency across all outputs - **Implementation:** Pass author_profile to feed templates ## Database Migration Answers **Q31: Migration naming convention - what number?** - **Answer:** Use next sequential: 005_add_media_support.sql - **Rationale:** Continue existing pattern - **Implementation:** Check latest migration, increment **Q32: Migration rollback - needed?** - **Answer:** No, forward-only migrations per project convention - **Rationale:** Simplicity, follows existing pattern - **Implementation:** CREATE IF NOT EXISTS, never DROP **Q33: Migration testing - how to verify?** - **Answer:** Test on copy of production database - **Rationale:** Real-world data is best test - **Implementation:** Copy data/starpunk.db, run migration, verify ## Testing Strategy Answers **Q34: Test data for media - what to use?** - **Answer:** Generate 1x1 pixel PNG in tests, don't use real files - **Rationale:** Minimal, fast, no binary files in repo - **Implementation:** Use Pillow to generate test images in memory **Q35: Author discovery mocking - how to test?** - **Answer:** Mock HTTP responses with test h-card HTML - **Rationale:** Deterministic, no external dependencies - **Implementation:** Use responses library or unittest.mock **Q36: Integration test priority - which are critical?** - **Answer:** Upload → Display → Edit → Delete flow - **Rationale:** Core user journey must work - **Implementation:** Single test that exercises full lifecycle ## Error Handling Answers **Q37: Upload failure recovery - how to handle?** - **Answer:** Show error, preserve form data, allow retry - **Rationale:** Don't lose user's work - **Implementation:** Flash error, return to form with content preserved **Q38: Discovery network timeout - how long to wait?** - **Answer:** 5 second timeout for profile fetch - **Rationale:** Balance between patience and responsiveness - **Implementation:** Use requests timeout parameter ## Deployment Answers **Q39: Media directory permissions - what's needed?** - **Answer:** data/media/ needs write permission for app user - **Rationale:** Same as existing data/ directory - **Implementation:** Document in deployment guide, create in setup **Q40: Upgrade path from v1.1.2 - any special steps?** - **Answer:** Run migration, create media directory, restart app - **Rationale:** Minimal disruption - **Implementation:** Add to CHANGELOG upgrade notes **Q41: Configuration changes - any new env vars?** - **Answer:** No, all settings have sensible defaults - **Rationale:** Maintain zero-config philosophy - **Implementation:** Hardcode limits in code with constants ## Critical Path Decisions Summary These are the key decisions to unblock implementation: 1. **Media upload flow**: Upload after note creation, associate via note_id 2. **Author discovery**: Use mf2py, cache for 24hrs, graceful fallbacks 3. **h-card parsing**: First h-card with matching URL property 4. **h-card placement**: Only within h-entry as p-author 5. **Migration strategy**: Sequential numbering (005), forward-only ## Implementation Order Based on dependencies and complexity: ### Phase 1: Custom Slugs (2 hours) - Simplest feature - No database changes - Template and validation only ### Phase 2: Author Discovery (4 hours) - Build discovery module - Add author_profile table - Integrate with auth flow - Update templates ### Phase 3: Media Upload (6 hours) - Most complex feature - Media table and migration - Upload handling - Template updates - Storage management ## File Structure Key files to create/modify: ### New Files - `starpunk/discovery.py` - Author discovery module - `starpunk/media.py` - Media handling module - `migrations/005_add_media_support.sql` - Database changes - `static/js/media-upload.js` - Optional enhancement ### Modified Files - `templates/admin/new.html` - Add slug and media fields - `templates/admin/edit.html` - Add slug (readonly) and media - `templates/partials/note.html` - Add microformats markup - `templates/public/index.html` - Add h-feed container - `starpunk/routes/admin.py` - Handle slugs and uploads - `starpunk/routes/auth.py` - Trigger discovery on login - `starpunk/models/note.py` - Add media relationship ## Success Metrics Implementation is complete when: 1. ✅ Custom slug can be specified on creation 2. ✅ Images can be uploaded and displayed 3. ✅ Author info is discovered from IndieAuth profile 4. ✅ IndieWebify.me validates h-feed and h-entry 5. ✅ All tests pass 6. ✅ No regressions in existing functionality 7. ✅ Media files are tracked in database 8. ✅ Errors are handled gracefully ## Final Notes - Keep it simple - this is v1.2.0, not v2.0.0 - Data preservation over premature optimization - When uncertain, choose the more explicit option - Document any deviations from this guidance --- This Q&A document serves as the authoritative implementation guide for v1.2.0. Any questions not covered here should follow the principle of maximum simplicity.