feat(tags): Add database schema and tags module (v1.3.0 Phase 1)

Implements tag/category system backend following microformats2 p-category specification.

Database changes:
- Migration 008: Add tags and note_tags tables
- Normalized tag storage (case-insensitive lookup, display name preserved)
- Indexes for performance

New module:
- starpunk/tags.py: Tag management functions
  - normalize_tag: Normalize tag strings
  - get_or_create_tag: Get or create tag records
  - add_tags_to_note: Associate tags with notes (replaces existing)
  - get_note_tags: Retrieve note tags (alphabetically ordered)
  - get_tag_by_name: Lookup tag by normalized name
  - get_notes_by_tag: Get all notes with specific tag
  - parse_tag_input: Parse comma-separated tag input

Model updates:
- Note.tags property (lazy-loaded, prefer pre-loading in routes)
- Note.to_dict() add include_tags parameter

CRUD updates:
- create_note() accepts tags parameter
- update_note() accepts tags parameter (None = no change, [] = remove all)

Micropub integration:
- Pass tags to create_note() (tags already extracted by extract_tags())
- Return tags in q=source response

Per design doc: docs/design/v1.3.0/microformats-tags-design.md

Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-10 11:24:23 -07:00
parent 927db4aea0
commit f10d0679da
188 changed files with 601 additions and 945 deletions

View File

@@ -0,0 +1,223 @@
# v1.2.0 Phase 3 Architecture Review: Media Upload
**Date**: 2025-11-28
**Reviewer**: StarPunk Architect Subagent
**Phase**: v1.2.0 Phase 3 - Media Upload
**Developer**: StarPunk Developer Subagent
**Status**: REVIEWED
## Executive Summary
The Phase 3 media upload implementation has been thoroughly reviewed against the architectural specifications, ADRs, and Q&A decisions. The implementation demonstrates excellent adherence to design principles and successfully delivers the social media-style attachment model as specified.
## ✅ What Went Well
### 1. **Design Adherence**
- Perfect implementation of ADR-057 social media attachment model
- Media displays at TOP of notes exactly as specified
- Text content properly positioned BELOW media
- Clean separation between media and content
### 2. **Technical Implementation**
- Excellent use of Pillow for image validation and optimization
- UUID-based filename generation prevents collisions effectively
- Date-organized storage structure (`data/media/YYYY/MM/`) implemented correctly
- Proper EXIF orientation handling
- Security measures well-implemented (path traversal prevention, MIME validation)
### 3. **Database Design**
- Junction table approach provides excellent flexibility
- Foreign key constraints and cascade deletes properly configured
- Indexes appropriately placed for query performance
- Caption support integrated seamlessly
### 4. **Feed Integration**
- RSS: HTML embedding in CDATA blocks works perfectly
- ATOM: Dual approach (enclosures + HTML) maximizes compatibility
- JSON Feed: Native attachments array cleanly implemented
- Absolute URLs correctly generated across all feed formats
### 5. **Error Handling**
- Graceful handling of invalid images
- Clear error messages for users
- Non-atomic upload behavior (per Q35) allows partial success
### 6. **Test Coverage**
- Comprehensive test suite using PIL-generated images (no binary files)
- All edge cases covered: file size, dimensions, format validation
- Multiple image attachment scenarios tested
- Caption handling verified
### 7. **Performance Optimizations**
- Immutable cache headers (1 year) for served media
- Efficient image resizing strategy (2048px threshold)
- Lazy loading potential with width/height stored
## ⚠️ Issues Found
### Minor Issues (Non-blocking)
1. **GIF Animation Handling**
- Line 119 in `media.py`: Animated GIFs are returned unoptimized
- This is acceptable for v1.2.0 but should be documented as a known limitation
- Recommendation: Add comment explaining why animated GIFs skip optimization
2. **Missing Input Validation in Route**
- `admin.py` lines 114-128: No check for empty file uploads before processing
- While handled by `save_media()`, earlier validation would be cleaner
- Recommendation: Skip empty filename entries before calling save_media
3. **Preview JavaScript Accessibility**
- `new.html` lines 139-140: Preview images lack proper alt text
- Should use filename or "Preview" + index for better accessibility
- Recommendation: Update JavaScript to include meaningful alt text
### Observations (No Action Required)
1. **No Thumbnail Generation**: As per design, relying on CSS for responsive sizing
2. **No Drag-and-Drop Reordering**: Display order = upload order, as specified
3. **No Micropub Media Endpoint**: Correctly scoped out for v1.2.0
## 🎯 Design Adherence
### Specification Compliance: 100%
All acceptance criteria from the feature specification are met:
- ✅ Multiple file upload field implemented
- ✅ Images saved to data/media/ with optimization
- ✅ Media-note associations tracked with captions
- ✅ Media displays at TOP of notes
- ✅ Text content displays BELOW media
- ✅ Media served at /media/YYYY/MM/filename
- ✅ All validation rules enforced
- ✅ Auto-resize working correctly
- ✅ EXIF orientation corrected
- ✅ 4-image limit enforced
- ✅ Captions supported
- ✅ Feed integration complete
### ADR Compliance
**ADR-057 (Media Attachment Model)**: ✅ Fully Compliant
- Social media style attachment model implemented exactly
- Junction table design provides required flexibility
- Display order maintained correctly
**ADR-058 (Image Optimization Strategy)**: ✅ Fully Compliant
- All limits enforced (10MB, 4096px, 4 images)
- Auto-resize to 2048px working
- Pillow integration clean and efficient
- 95% quality setting applied
### Q&A Answer Compliance
All relevant Q&A answers (Q4-Q12, Q24-Q27, Q31, Q35) have been correctly implemented:
- Q4: Upload after note creation ✅
- Q5: UUID-based filenames ✅
- Q6: Size/dimension limits ✅
- Q7: Optional captions ✅
- Q11: Pillow validation ✅
- Q12: GIF animation preservation attempted ✅
- Q24-Q27: Feed strategies implemented correctly ✅
- Q31: PIL-generated test images ✅
- Q35: Non-atomic error handling ✅
## 🧪 Test Coverage Assessment
**Coverage Quality: Excellent**
The test suite is comprehensive and well-structured:
- Format validation tests for all supported types
- Boundary testing for size and dimension limits
- Optimization verification
- Database operation testing
- Error condition handling
- No missing critical test scenarios identified
## 📊 Code Quality
### Structure and Organization: A+
- Clean separation of concerns in `media.py`
- Functions have single responsibilities
- Well-documented with clear docstrings
- Constants properly defined
### Pillow Library Usage: A
- Correct use of Image.verify() for validation
- Proper EXIF handling with ImageOps
- Efficient thumbnail generation with LANCZOS
- Format-specific save parameters
### Error Handling: A
- Comprehensive validation with clear error messages
- Graceful degradation for partial failures
- Proper exception catching and re-raising
### Maintainability: A
- Code is self-documenting
- Clear variable names
- Logical flow easy to follow
- Good separation between validation, optimization, and storage
## 🔒 Security Assessment
**Security Grade: A**
1. **Path Traversal Prevention**: ✅
- Proper path resolution and validation in media serving route
- UUID filenames prevent directory escaping
2. **MIME Type Validation**: ✅
- Server-side validation using Pillow
- Not relying on client-provided MIME types
3. **Resource Limits**: ✅
- File size checked before processing
- Dimension limits prevent memory exhaustion
- Max file count enforced
4. **File Integrity**: ✅
- Pillow verify() ensures valid image data
- Corrupted files properly rejected
No significant security vulnerabilities identified.
## 🚀 Recommendation
### **APPROVE** - Ready for Release
The v1.2.0 Phase 3 media upload implementation is **production-ready** and can be released immediately.
### Rationale for Approval
1. **Complete Feature Implementation**: All specified functionality is working correctly
2. **Excellent Code Quality**: Clean, maintainable, well-tested code
3. **Security**: No critical vulnerabilities, all best practices followed
4. **Performance**: Appropriate optimizations in place
5. **User Experience**: Intuitive upload interface with preview and captions
### Minor Improvements for Future Consideration
While not blocking release, these could be addressed in future patches:
1. **v1.2.1**: Improve animated GIF handling (document current limitations clearly)
2. **v1.2.1**: Add progress indicators for large file uploads
3. **v1.3.0**: Consider thumbnail generation for gallery views
4. **v1.3.0**: Add Micropub media endpoint support
## Final Assessment
The developer has delivered an exemplary implementation that:
- Strictly follows all architectural decisions
- Implements the social media attachment model perfectly
- Handles edge cases gracefully
- Maintains high code quality standards
- Prioritizes security and performance
The implementation shows excellent judgment in balancing completeness with simplicity, staying true to the StarPunk philosophy of "Every line of code must justify its existence."
**Architectural Sign-off**: ✅ APPROVED
---
*This implementation represents a significant enhancement to StarPunk's capabilities while maintaining its minimalist principles. The social media-style attachment model will provide users with a familiar and effective way to share visual content alongside their notes.*