Files
StarPunk/docs/designs/phase-5-quick-reference.md
Phil Skentelbery 6863bcae67 docs: add Phase 5 design and architectural review documentation
- Add ADR-014: RSS Feed Implementation
- Add ADR-015: Phase 5 Implementation Approach
- Add Phase 5 design documents (RSS and container)
- Add pre-implementation review
- Add RSS and container validation reports
- Add architectural approval for v0.6.0 release

Architecture reviews confirm 98/100 (RSS) and 96/100 (container) scores.
Phase 5 approved for production deployment.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-19 10:30:55 -07:00

12 KiB

Phase 5 Quick Reference Guide

Phase: 5 - RSS Feed & Production Container Version: 0.6.0 Status: Implementation Ready

Pre-Implementation Setup

Version Numbering

Decision: Go directly from 0.5.1 → 0.6.0

  • Phase 5 introduces significant new functionality (RSS feeds and container deployment)
  • Skip intermediate versions (e.g., 0.5.2) - go straight to 0.6.0
  • This follows semantic versioning for new feature additions

Git Workflow

Decision: Use feature branch feature/phase-5-rss-container

  1. Create and checkout feature branch:
    git checkout -b feature/phase-5-rss-container
    
  2. Implement all Phase 5 features on this branch
  3. Create PR to merge into main when complete
  4. This provides cleaner history and easier rollback if needed

Overview

Phase 5 implements:

  1. RSS 2.0 feed generation for syndicating published notes
  2. Production-ready container for deployment with HTTPS/IndieAuth testing

Implementation Checklist

Part 1: RSS Feed (Estimated: 3-4 hours)

Step 1: Create Feed Module

  • Create starpunk/feed.py
  • Implement generate_feed() using feedgen
  • Implement format_rfc822_date() for date formatting
  • Implement get_note_title() for title extraction
  • Implement clean_html_for_rss() for CDATA safety

Step 2: Add Feed Route

  • Update starpunk/routes/public.py
  • Add @bp.route("/feed.xml") handler
  • Implement in-memory caching (5 minutes)
  • Add ETag generation and support
  • Set proper Content-Type and Cache-Control headers

Step 3: Update Templates

  • Add RSS discovery link to templates/base.html
  • Add RSS link to navigation in templates/index.html

Step 4: Configuration

  • Update starpunk/config.py with feed settings
  • Add FEED_MAX_ITEMS (default: 50)
  • Add FEED_CACHE_SECONDS (default: 300)
  • Update .env.example with feed variables

Step 5: RSS Testing

  • Create tests/test_feed.py for unit tests
  • Create tests/test_routes_feed.py for route tests
  • Test feed generation with various note counts
  • Test caching behavior
  • Test ETag validation
  • Validate with W3C Feed Validator

Part 2: Production Container (Estimated: 3-4 hours)

Step 6: Create Container Files

  • Create Containerfile with multi-stage build
  • Create compose.yaml for orchestration
  • Create .containerignore to exclude unnecessary files
  • Create Caddyfile.example for reverse proxy
  • Create nginx.conf.example as alternative

Step 7: Add Health Check

  • Add /health endpoint to starpunk/__init__.py
  • Check database connectivity
  • Check filesystem access
  • Return JSON with status and version

Step 8: Container Configuration

  • Update .env.example with container variables
  • Add VERSION=0.6.0
  • Add WORKERS=4
  • Add WORKER_TIMEOUT=30
  • Document environment variables

Step 9: Container Testing

  • Build container with Podman
  • Build container with Docker
  • Test container startup
  • Test health endpoint
  • Test data persistence
  • Test with compose orchestration

Step 10: Production Deployment Testing

  • Deploy container to public server
  • Configure reverse proxy (Caddy or Nginx)
  • Set up HTTPS with Let's Encrypt
  • Test IndieAuth authentication flow
  • Verify callback URLs work
  • Test session creation and persistence

Part 3: Documentation (Estimated: 1-2 hours)

Step 11: Update Documentation

  • Update CHANGELOG.md for v0.6.0
  • Increment version in starpunk/__init__.py from 0.5.1 to 0.6.0
  • Create deployment guide
  • Document RSS feed usage
  • Document container deployment
  • Document IndieAuth testing with HTTPS

File Locations

New Files

starpunk/feed.py                          # RSS generation module
Containerfile                             # Container build definition
compose.yaml                              # Container orchestration
.containerignore                          # Container build exclusions
Caddyfile.example                         # Caddy reverse proxy config
nginx.conf.example                        # Nginx reverse proxy config
tests/test_feed.py                        # Feed unit tests
tests/test_routes_feed.py                 # Feed route tests
docs/designs/phase-5-rss-and-container.md # This phase design
docs/designs/phase-5-quick-reference.md   # This guide
docs/decisions/ADR-014-rss-feed-implementation.md # RSS ADR

Modified Files

starpunk/routes/public.py                 # Add /feed.xml route
starpunk/__init__.py                      # Add /health endpoint
starpunk/config.py                        # Add feed configuration
templates/base.html                       # Add RSS discovery link
templates/index.html                      # Add RSS nav link
.env.example                              # Add feed/container vars
CHANGELOG.md                              # Document v0.6.0

Key Implementation Details

RSS Feed Module

File: starpunk/feed.py

Core Function:

from feedgen.feed import FeedGenerator
from starpunk.notes import list_notes

def generate_feed(site_url, site_name, site_description, notes, limit=50):
    """Generate RSS 2.0 XML feed"""
    fg = FeedGenerator()

    # Set channel metadata
    fg.title(site_name)
    fg.link(href=site_url, rel='alternate')
    fg.description(site_description)
    fg.language('en')
    fg.link(href=f'{site_url}/feed.xml', rel='self')

    # Add items
    for note in notes[:limit]:
        fe = fg.add_entry()
        fe.title(get_note_title(note))
        fe.link(href=f'{site_url}/note/{note.slug}')
        fe.guid(f'{site_url}/note/{note.slug}', permalink=True)
        fe.pubDate(note.created_at.replace(tzinfo=timezone.utc))
        fe.description(note.html)  # HTML content

    return fg.rss_str(pretty=True).decode('utf-8')

Feed Route

File: starpunk/routes/public.py

Add to existing blueprint:

@bp.route("/feed.xml")
def feed():
    """RSS 2.0 feed endpoint with caching"""
    # Check cache (implementation in design doc)
    # Generate feed if cache expired
    # Return XML with proper headers
    pass

Health Check Endpoint

File: starpunk/__init__.py

Add before return app:

@app.route('/health')
def health_check():
    """Container health check"""
    try:
        # Check database and filesystem
        return jsonify({'status': 'healthy', 'version': '0.6.0'}), 200
    except Exception as e:
        return jsonify({'status': 'unhealthy', 'error': str(e)}), 500

Containerfile

Key Sections:

# Multi-stage build for smaller image
FROM python:3.11-slim AS builder
# ... install dependencies in venv ...

FROM python:3.11-slim
# ... copy venv, run as non-root ...

CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "4", "app:app"]

Testing Commands

RSS Feed Testing

# Unit tests
uv run pytest tests/test_feed.py -v

# Route tests
uv run pytest tests/test_routes_feed.py -v

# Manual test
curl http://localhost:5000/feed.xml

# Validate XML
curl http://localhost:5000/feed.xml | xmllint --noout -

# W3C Validation (manual)
# Visit: https://validator.w3.org/feed/
# Enter: http://your-domain.com/feed.xml

Container Testing

# Build with Podman
podman build -t starpunk:0.6.0 -f Containerfile .

# Build with Docker
docker build -t starpunk:0.6.0 -f Containerfile .

# Run with Podman
mkdir -p container-data/notes
podman run -d --name starpunk \
  -p 127.0.0.1:8000:8000 \
  -v $(pwd)/container-data:/data:rw,Z \
  --env-file .env \
  starpunk:0.6.0

# Check health
curl http://localhost:8000/health

# Check feed
curl http://localhost:8000/feed.xml

# View logs
podman logs starpunk

# Test with compose
podman-compose up -d
podman-compose logs -f

Configuration Examples

.env for Container

# Required
SITE_URL=https://your-domain.com
SITE_NAME=My StarPunk Site
ADMIN_ME=https://your-identity.com
SESSION_SECRET=<random-secret>

# Feed configuration
FEED_MAX_ITEMS=50
FEED_CACHE_SECONDS=300

# Container configuration
VERSION=0.6.0
ENVIRONMENT=production
WORKERS=4
FLASK_ENV=production
FLASK_DEBUG=0

Caddy Reverse Proxy

your-domain.com {
    reverse_proxy localhost:8000

    log {
        output file /var/log/caddy/starpunk.log
    }

    encode gzip zstd
}

Nginx Reverse Proxy

upstream starpunk {
    server localhost:8000;
}

server {
    listen 443 ssl http2;
    server_name your-domain.com;

    ssl_certificate /etc/letsencrypt/live/your-domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your-domain.com/privkey.pem;

    location / {
        proxy_pass http://starpunk;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Common Issues & Solutions

Issue: Feed not updating

Solution: Check cache duration (5 minutes default), force refresh by restarting

Issue: Container won't start

Solution: Check logs (podman logs starpunk), verify .env file exists

Issue: IndieAuth callback fails

Solution: Verify SITE_URL matches public URL exactly (no trailing slash)

Issue: Data not persisting

Solution: Check volume mount is correct, verify permissions

Issue: RSS validation errors

Solution: Check date formatting (RFC-822), verify XML structure

Deployment Workflow

1. Local Testing

# Test feed locally
uv run flask --app app.py run --debug
curl http://localhost:5000/feed.xml

2. Container Testing

# Build and test container
podman build -t starpunk:0.6.0 .
podman run -d -p 8000:8000 --name starpunk-test starpunk:0.6.0
curl http://localhost:8000/health

3. Production Deployment

# On server
git clone <repo>
cd starpunk
cp .env.example .env
# Edit .env with production values

# Build and run
podman-compose up -d

# Configure reverse proxy (Caddy or Nginx)
# Set up HTTPS with certbot or Caddy auto-HTTPS

# Test IndieAuth
# Visit https://your-domain.com/admin/login

Success Criteria

Phase 5 complete when:

  • RSS feed validates with W3C validator
  • Feed appears correctly in RSS readers
  • Container builds and runs successfully
  • Health check endpoint responds
  • Data persists across container restarts
  • IndieAuth works with public HTTPS URL
  • All tests pass (>90% coverage)
  • Documentation complete
  • Version incremented from 0.5.1 to 0.6.0 in starpunk/__init__.py
  • Feature branch feature/phase-5-rss-container merged to main

Time Estimate

  • RSS Feed Implementation: 3-4 hours
  • Container Implementation: 3-4 hours
  • Testing: 2-3 hours
  • Documentation: 1-2 hours

Total: 9-13 hours

Next Steps After Completion

  1. Ensure all changes committed on feature branch:
    git add .
    git commit -m "feat: implement RSS feed and production container (v0.6.0)"
    
  2. Create PR to merge feature/phase-5-rss-container into main
  3. After merge, tag release on main:
    git checkout main
    git pull
    git tag -a v0.6.0 -m "Release 0.6.0: RSS feed and production container"
    git push --tags
    
  4. Create implementation report in docs/reports/
  5. Begin Phase 6 planning (Micropub implementation)

Reference Documents


Phase: 5 Version: 0.6.0 Date: 2025-11-18 Status: Ready for Implementation