Files
StarPunk/docs/decisions/ADR-057-media-attachment-model.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

3.9 KiB

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 ![alt](url).

  • 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