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>
110 lines
3.9 KiB
Markdown
110 lines
3.9 KiB
Markdown
# ADR-057: Media Attachment Model
|
|
|
|
## Status
|
|
Accepted
|
|
|
|
## Context
|
|
The v1.2.0 media upload feature needed a clear model for how media relates to notes. Initial design assumed inline markdown image insertion (like a blog editor), but user feedback clarified that notes are more like social media posts (tweets, Mastodon toots) where media is attached rather than inline.
|
|
|
|
Key insights from user:
|
|
- "Notes are more like tweets, thread posts, mastodon posts etc. where the media is inserted is kind of irrelevant"
|
|
- Media should appear at the TOP of notes when displayed
|
|
- Text content should appear BELOW media
|
|
- Multiple images per note should be supported
|
|
|
|
## Decision
|
|
We will implement a social media-style attachment model for media:
|
|
|
|
1. **Database Design**: Use a junction table (`note_media`) to associate media files with notes, allowing:
|
|
- Multiple media per note (max 4)
|
|
- Explicit ordering via `display_order` column
|
|
- Per-attachment metadata (captions)
|
|
- Future reuse of media across notes
|
|
|
|
2. **Display Model**: Media attachments appear at the TOP of notes:
|
|
- 1 image: Full width display
|
|
- 2 images: Side-by-side layout
|
|
- 3-4 images: Grid layout
|
|
- Text content always appears below media
|
|
|
|
3. **Syndication Strategy**:
|
|
- RSS: Embed media as HTML in description (universal support)
|
|
- ATOM: Use both `<link rel="enclosure">` and HTML content
|
|
- JSON Feed: Use native `attachments` array (cleanest)
|
|
|
|
4. **Microformats2**: Multiple `u-photo` properties for multi-photo posts
|
|
|
|
## Rationale
|
|
**Why attachment model over inline markdown?**
|
|
- Matches user mental model (social media posts)
|
|
- Simplifies UI/UX (no cursor tracking needed)
|
|
- Better syndication support (especially JSON Feed)
|
|
- Cleaner Microformats2 markup
|
|
- Consistent display across all contexts
|
|
|
|
**Why junction table over array column?**
|
|
- Better query performance for feeds
|
|
- Supports future media reuse
|
|
- Per-attachment metadata
|
|
- Explicit ordering control
|
|
- Standard relational design
|
|
|
|
**Why limit to 4 images?**
|
|
- Twitter limit is 4 images
|
|
- Mastodon limit is 4 images
|
|
- Prevents performance issues
|
|
- Maintains clean grid layouts
|
|
- Sufficient for microblogging use case
|
|
|
|
## Consequences
|
|
|
|
### Positive
|
|
- Clean separation of media and text content
|
|
- Familiar social media UX pattern
|
|
- Excellent syndication feed support
|
|
- Future-proof for media galleries
|
|
- Supports accessibility via captions
|
|
- Efficient database queries
|
|
|
|
### Negative
|
|
- No inline images in markdown content
|
|
- All media must appear at top
|
|
- Cannot mix text and images
|
|
- More complex database schema
|
|
- Additional JOIN queries needed
|
|
|
|
### Neutral
|
|
- Different from traditional blog CMSs
|
|
- Requires grid layout CSS
|
|
- Media upload is separate from text editing
|
|
|
|
## Alternatives Considered
|
|
|
|
### Alternative 1: Inline Markdown Images
|
|
Store media URLs in markdown content as ``.
|
|
- **Pros**: Traditional blog approach, flexible positioning
|
|
- **Cons**: Poor syndication, complex editing UX, inconsistent display
|
|
|
|
### Alternative 2: JSON Array in Notes Table
|
|
Store media IDs as JSON array column in notes table.
|
|
- **Pros**: Simpler schema, fewer tables
|
|
- **Cons**: Poor query performance, no per-media metadata, violates 1NF
|
|
|
|
### Alternative 3: Single Media Per Note
|
|
Restrict to one image per note.
|
|
- **Pros**: Simplest implementation
|
|
- **Cons**: Too limiting, doesn't match social media patterns
|
|
|
|
## Implementation Notes
|
|
|
|
1. Migration will create both `media` and `note_media` tables
|
|
2. Feed generators must query media via JOIN
|
|
3. Template must render media before content
|
|
4. Upload UI shows thumbnails, not markdown insertion
|
|
5. Consider lazy loading for performance
|
|
|
|
## References
|
|
- [IndieWeb multi-photo posts](https://indieweb.org/multi-photo)
|
|
- [Microformats2 u-photo property](https://microformats.org/wiki/h-entry#u-photo)
|
|
- [JSON Feed attachments](https://jsonfeed.org/version/1.1#attachments)
|
|
- [Twitter photo upload limits](https://help.twitter.com/en/using-twitter/tweeting-gifs-and-pictures) |