Files
StarPunk/docs/design/v1.2.0/developer-qa.md
Phil Skentelbery dd822a35b5 feat: v1.2.0-rc.1 - IndieWeb Features Release Candidate
Complete implementation of v1.2.0 "IndieWeb Features" release.

## Phase 1: Custom Slugs
- Optional custom slug field in note creation form
- Auto-sanitization (lowercase, hyphens only)
- Uniqueness validation with auto-numbering
- Read-only after creation to preserve permalinks
- Matches Micropub mp-slug behavior

## Phase 2: Author Discovery + Microformats2
- Automatic h-card discovery from IndieAuth identity URL
- 24-hour caching with graceful fallback
- Never blocks login (per ADR-061)
- Complete h-entry, h-card, h-feed markup
- All required Microformats2 properties
- rel-me links for identity verification
- Passes IndieWeb validation

## Phase 3: Media Upload
- Upload up to 4 images per note (JPEG, PNG, GIF, WebP)
- Automatic optimization with Pillow
  - Auto-resize to 2048px
  - EXIF orientation correction
  - 95% quality compression
- Social media-style layout (media top, text below)
- Optional captions for accessibility
- Integration with all feed formats (RSS, ATOM, JSON Feed)
- Date-organized storage with UUID filenames
- Immutable caching (1 year)

## Database Changes
- migrations/006_add_author_profile.sql - Author discovery cache
- migrations/007_add_media_support.sql - Media storage

## New Modules
- starpunk/author_discovery.py - h-card discovery and caching
- starpunk/media.py - Image upload, validation, optimization

## Documentation
- 4 new ADRs (056, 057, 058, 061)
- Complete design specifications
- Developer Q&A with 40+ questions answered
- 3 implementation reports
- 3 architect reviews (all approved)

## Testing
- 56 new tests for v1.2.0 features
- 842 total tests in suite
- All v1.2.0 feature tests passing

## Dependencies
- Added: mf2py (Microformats2 parser)
- Added: Pillow (image processing)

Version: 1.2.0-rc.1

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 15:02:20 -07:00

303 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.