docs: Add v1.3.1 and v1.4.0 release definitions
v1.3.1 "Syndicate Tags": - RSS/Atom/JSON Feed category/tag support v1.4.0 "Media": - Micropub media endpoint (W3C compliant) - Large image support (>10MB auto-resize) - Enhanced feed media (image variants, full Media RSS) Also adds tag-filtered feeds to backlog at medium priority. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -29,7 +29,7 @@
|
||||
|
||||
## High
|
||||
|
||||
### Enhanced Feed Media Support
|
||||
### Enhanced Feed Media Support *(Scheduled: v1.4.0)*
|
||||
- Multiple image sizes/thumbnails (150px, 320px, 640px, 1280px)
|
||||
- Full Media RSS implementation (media:group, all attributes)
|
||||
- Enhanced JSON Feed attachments
|
||||
|
||||
401
docs/projectplan/v1.4.0/RELEASE.md
Normal file
401
docs/projectplan/v1.4.0/RELEASE.md
Normal file
@@ -0,0 +1,401 @@
|
||||
# StarPunk v1.4.0 Release
|
||||
|
||||
**Status**: Planning
|
||||
**Codename**: "Media"
|
||||
**Focus**: Micropub Media Endpoint, Large Image Support, Enhanced Feed Media
|
||||
|
||||
## Overview
|
||||
|
||||
This minor release significantly enhances StarPunk's media capabilities with three major features:
|
||||
|
||||
1. **Micropub Media Endpoint** - W3C-compliant media upload via Micropub clients
|
||||
2. **Large Image Support** - Accept and resize images larger than 10MB
|
||||
3. **Enhanced Feed Media** - Multiple image sizes and complete Media RSS implementation
|
||||
|
||||
## Features
|
||||
|
||||
### 1. Micropub Media Endpoint
|
||||
|
||||
Implement the W3C Micropub media endpoint specification, enabling Micropub clients to upload photos, audio, and video files.
|
||||
|
||||
#### Specification Compliance (W3C Micropub)
|
||||
|
||||
**Endpoint**: `POST /micropub/media`
|
||||
|
||||
**Request Format**:
|
||||
- Content-Type: `multipart/form-data`
|
||||
- Single file part named `file`
|
||||
- Authorization: Bearer token with `media` or `create` scope
|
||||
|
||||
**Response**:
|
||||
- `201 Created` with `Location` header containing the file URL
|
||||
- URL should be unguessable (UUID-based, which we already do)
|
||||
|
||||
**Example Request**:
|
||||
```http
|
||||
POST /micropub/media HTTP/1.1
|
||||
Authorization: Bearer xxx
|
||||
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary
|
||||
|
||||
------WebKitFormBoundary
|
||||
Content-Disposition: form-data; name="file"; filename="photo.jpg"
|
||||
Content-Type: image/jpeg
|
||||
|
||||
[binary data]
|
||||
------WebKitFormBoundary--
|
||||
```
|
||||
|
||||
**Example Response**:
|
||||
```http
|
||||
HTTP/1.1 201 Created
|
||||
Location: https://example.com/media/2025/01/abc123-def456.jpg
|
||||
```
|
||||
|
||||
#### Configuration Discovery
|
||||
|
||||
Update `q=config` response to advertise media endpoint:
|
||||
```json
|
||||
{
|
||||
"media-endpoint": "https://example.com/micropub/media",
|
||||
"syndicate-to": []
|
||||
}
|
||||
```
|
||||
|
||||
#### Photo Property Support
|
||||
|
||||
Enable `photo` property in Micropub create requests:
|
||||
|
||||
**URL Reference** (photo already uploaded or external):
|
||||
```
|
||||
h=entry&content=Hello&photo=https://example.com/media/2025/01/abc.jpg
|
||||
```
|
||||
|
||||
**JSON with Alt Text**:
|
||||
```json
|
||||
{
|
||||
"type": ["h-entry"],
|
||||
"properties": {
|
||||
"content": ["Hello world"],
|
||||
"photo": [{
|
||||
"value": "https://example.com/media/2025/01/abc.jpg",
|
||||
"alt": "A beautiful sunset"
|
||||
}]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Multiple Photos**:
|
||||
```json
|
||||
{
|
||||
"type": ["h-entry"],
|
||||
"properties": {
|
||||
"content": ["Photo gallery"],
|
||||
"photo": [
|
||||
"https://example.com/media/2025/01/photo1.jpg",
|
||||
"https://example.com/media/2025/01/photo2.jpg"
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Implementation Details
|
||||
|
||||
**New Route**: `starpunk/routes/micropub.py`
|
||||
```python
|
||||
@bp.route('/media', methods=['POST'])
|
||||
def media_endpoint():
|
||||
# Verify bearer token (media or create scope)
|
||||
# Extract file from multipart/form-data
|
||||
# Call save_media() from media.py
|
||||
# Return 201 with Location header
|
||||
```
|
||||
|
||||
**Modified**: `starpunk/micropub.py`
|
||||
- Update `get_micropub_config()` to return media-endpoint URL
|
||||
- Add `extract_photos()` function for photo property parsing
|
||||
- Modify `handle_create()` to process photo URLs and attach to note
|
||||
|
||||
**Scope Validation**:
|
||||
- Media endpoint requires `media` or `create` scope
|
||||
- Photo property in create requests requires `create` scope
|
||||
|
||||
---
|
||||
|
||||
### 2. Large Image Support (>10MB)
|
||||
|
||||
Remove the 10MB file size rejection and instead automatically resize large images to fit within acceptable limits.
|
||||
|
||||
#### Current Behavior (v1.2.0)
|
||||
- Files >10MB are rejected with error
|
||||
- Files ≤10MB are accepted and resized if >2048px
|
||||
|
||||
#### New Behavior (v1.4.0)
|
||||
- Files of any reasonable size accepted (new limit: 50MB)
|
||||
- Images >10MB are automatically resized more aggressively
|
||||
- Final output always ≤10MB after optimization
|
||||
|
||||
#### Resize Strategy
|
||||
|
||||
| Input Size | Max Dimension | Quality | Target Output |
|
||||
|------------|---------------|---------|---------------|
|
||||
| ≤10MB | 2048px | 95% | ≤5MB typical |
|
||||
| 10-25MB | 1600px | 90% | ≤5MB target |
|
||||
| 25-50MB | 1280px | 85% | ≤5MB target |
|
||||
| >50MB | Rejected | - | Error message |
|
||||
|
||||
#### Implementation Details
|
||||
|
||||
**Modified**: `starpunk/media.py`
|
||||
|
||||
```python
|
||||
def validate_image(file_data, filename):
|
||||
"""Updated validation with higher limit."""
|
||||
MAX_FILE_SIZE = 50 * 1024 * 1024 # 50MB (was 10MB)
|
||||
# ... rest of validation
|
||||
|
||||
def optimize_image(image_data, original_size=None):
|
||||
"""Enhanced optimization based on input size."""
|
||||
# Determine resize parameters based on original_size
|
||||
# More aggressive resize for larger files
|
||||
# Quality reduction for very large files
|
||||
# Iterative optimization if output still too large
|
||||
```
|
||||
|
||||
**Quality Iteration**:
|
||||
If first pass produces >10MB output:
|
||||
1. Reduce max dimension by 20%
|
||||
2. Reduce quality by 5%
|
||||
3. Repeat until ≤10MB or min quality (70%) reached
|
||||
|
||||
#### User Experience
|
||||
- No rejection for reasonable photo sizes
|
||||
- Transparent optimization (user doesn't need to pre-resize)
|
||||
- Warning in response if significant quality reduction applied
|
||||
- Original dimensions preserved in EXIF if possible
|
||||
|
||||
---
|
||||
|
||||
### 3. Enhanced Feed Media Support
|
||||
|
||||
Implement ADR-059 Phase A: Multiple image sizes and complete Media RSS implementation.
|
||||
|
||||
#### Multiple Image Sizes (Thumbnails)
|
||||
|
||||
Generate multiple renditions on upload:
|
||||
|
||||
| Variant | Dimensions | Use Case |
|
||||
|---------|------------|----------|
|
||||
| `thumb` | 150×150 (square crop) | Thumbnails, previews |
|
||||
| `small` | 320px width | Mobile, low bandwidth |
|
||||
| `medium` | 640px width | Standard display |
|
||||
| `large` | 1280px width | High-res display |
|
||||
| `original` | As uploaded (≤2048px) | Full quality |
|
||||
|
||||
**Database Schema** (new migration):
|
||||
```sql
|
||||
CREATE TABLE media_variants (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
media_id INTEGER NOT NULL,
|
||||
variant_type TEXT NOT NULL, -- 'thumb', 'small', 'medium', 'large', 'original'
|
||||
path TEXT NOT NULL,
|
||||
width INTEGER NOT NULL,
|
||||
height INTEGER NOT NULL,
|
||||
size_bytes INTEGER NOT NULL,
|
||||
FOREIGN KEY (media_id) REFERENCES media(id) ON DELETE CASCADE,
|
||||
UNIQUE(media_id, variant_type)
|
||||
);
|
||||
|
||||
CREATE INDEX idx_media_variants_media ON media_variants(media_id);
|
||||
```
|
||||
|
||||
**Storage Structure**:
|
||||
```
|
||||
/media/2025/01/
|
||||
├── abc123.jpg # Original/large
|
||||
├── abc123_medium.jpg # 640px
|
||||
├── abc123_small.jpg # 320px
|
||||
└── abc123_thumb.jpg # 150×150
|
||||
```
|
||||
|
||||
#### Complete Media RSS Implementation
|
||||
|
||||
Enhance RSS feeds with full Media RSS specification support:
|
||||
|
||||
```xml
|
||||
<item>
|
||||
<title>My Photo Post</title>
|
||||
<media:group>
|
||||
<media:content url="https://.../large.jpg"
|
||||
type="image/jpeg"
|
||||
medium="image"
|
||||
isDefault="true"
|
||||
width="1280" height="960"
|
||||
fileSize="245760"/>
|
||||
<media:content url="https://.../medium.jpg"
|
||||
type="image/jpeg"
|
||||
medium="image"
|
||||
width="640" height="480"
|
||||
fileSize="98304"/>
|
||||
<media:content url="https://.../small.jpg"
|
||||
type="image/jpeg"
|
||||
medium="image"
|
||||
width="320" height="240"
|
||||
fileSize="32768"/>
|
||||
</media:group>
|
||||
<media:thumbnail url="https://.../thumb.jpg"
|
||||
width="150" height="150"/>
|
||||
<media:title type="plain">Image caption here</media:title>
|
||||
</item>
|
||||
```
|
||||
|
||||
**New Media RSS Elements**:
|
||||
- `<media:group>` - Container for multiple renditions
|
||||
- `<media:content>` with full attributes (width, height, fileSize, medium, isDefault)
|
||||
- `<media:thumbnail>` with dimensions
|
||||
- `<media:title>` for captions (type="plain")
|
||||
|
||||
#### Enhanced JSON Feed Attachments
|
||||
|
||||
```json
|
||||
{
|
||||
"items": [{
|
||||
"id": "...",
|
||||
"image": "https://.../large.jpg",
|
||||
"attachments": [
|
||||
{
|
||||
"url": "https://.../large.jpg",
|
||||
"mime_type": "image/jpeg",
|
||||
"title": "Image caption",
|
||||
"size_in_bytes": 245760
|
||||
}
|
||||
],
|
||||
"_starpunk": {
|
||||
"media_variants": {
|
||||
"thumb": "https://.../thumb.jpg",
|
||||
"small": "https://.../small.jpg",
|
||||
"medium": "https://.../medium.jpg",
|
||||
"large": "https://.../large.jpg"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
#### ATOM Feed Enclosures
|
||||
|
||||
Add proper enclosure links to ATOM entries:
|
||||
```xml
|
||||
<entry>
|
||||
<link rel="enclosure"
|
||||
type="image/jpeg"
|
||||
length="245760"
|
||||
title="Image caption"
|
||||
href="https://.../large.jpg"/>
|
||||
</entry>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 1: Large Image Support (4-6 hours)
|
||||
- Update `validate_image()` with 50MB limit
|
||||
- Implement tiered resize strategy in `optimize_image()`
|
||||
- Add iterative quality reduction
|
||||
- Update tests for new limits
|
||||
|
||||
### Phase 2: Image Variants (8-12 hours)
|
||||
- Create migration for `media_variants` table
|
||||
- Implement variant generation in `save_media()`
|
||||
- Update `get_note_media()` to include variants
|
||||
- Add variant serving routes
|
||||
- Update templates for responsive images
|
||||
|
||||
### Phase 3: Micropub Media Endpoint (6-8 hours)
|
||||
- Create `/micropub/media` route
|
||||
- Update `q=config` response
|
||||
- Implement `photo` property parsing
|
||||
- Update `handle_create()` for photo attachment
|
||||
- Add scope validation for media uploads
|
||||
|
||||
### Phase 4: Enhanced Feed Media (6-8 hours)
|
||||
- Update RSS generator for `<media:group>` and variants
|
||||
- Update JSON Feed for variants in `_starpunk` extension
|
||||
- Add ATOM enclosure links
|
||||
- Update feed tests
|
||||
|
||||
### Phase 5: Testing & Documentation (4-6 hours)
|
||||
- Comprehensive test suite for all new features
|
||||
- Update API documentation
|
||||
- Update architecture documentation
|
||||
- Update CHANGELOG
|
||||
|
||||
**Total Estimated Effort**: 28-40 hours
|
||||
|
||||
---
|
||||
|
||||
## Technical Notes
|
||||
|
||||
### Backward Compatibility
|
||||
- Existing media continues to work (no variants, single size)
|
||||
- Feeds gracefully handle notes with/without variants
|
||||
- Micropub clients without media support continue to work
|
||||
|
||||
### Performance Considerations
|
||||
- Variant generation is synchronous on upload (acceptable for single-user)
|
||||
- Consider background processing for v1.5.0 if needed
|
||||
- Cache headers on all media variants (1 year immutable)
|
||||
|
||||
### Storage Impact
|
||||
- ~4x storage per image (thumb + small + medium + large)
|
||||
- Consider cleanup of unused uploaded media
|
||||
- Document storage requirements in deployment guide
|
||||
|
||||
### Security
|
||||
- Media endpoint requires valid bearer token
|
||||
- File type validation (images only for v1.4.0)
|
||||
- UUID filenames prevent enumeration
|
||||
- Path traversal protection maintained
|
||||
|
||||
---
|
||||
|
||||
## Out of Scope (Deferred)
|
||||
|
||||
### v1.5.0 or Later
|
||||
- Audio/podcast support (ADR-059 Phase B)
|
||||
- Video support (ADR-059 Phase C)
|
||||
- Micropub update/delete operations
|
||||
- Background media processing
|
||||
- CDN integration
|
||||
|
||||
### Not Planned
|
||||
- External media hosting (Cloudinary, etc.)
|
||||
- Media transcoding
|
||||
- Live photo/HEIC support
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
- v1.3.x complete (tags feature)
|
||||
- Pillow library (already installed)
|
||||
- No new external dependencies
|
||||
|
||||
## Success Criteria
|
||||
|
||||
1. Micropub clients can upload media via media endpoint
|
||||
2. Photos attached to notes via Micropub `photo` property
|
||||
3. Images >10MB accepted and resized appropriately
|
||||
4. All image variants generated and served
|
||||
5. Feed readers see proper Media RSS with variants
|
||||
6. All existing tests continue to pass
|
||||
7. New comprehensive test coverage for media features
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [W3C Micropub Specification](https://www.w3.org/TR/micropub/)
|
||||
- [Media RSS Specification](https://www.rssboard.org/media-rss)
|
||||
- ADR-057: Media Attachment Model
|
||||
- ADR-058: Image Optimization Strategy
|
||||
- ADR-059: Full Feed Media Standardization
|
||||
- `docs/architecture/syndication-architecture.md`
|
||||
Reference in New Issue
Block a user