Files
StarPunk/docs/design/phase-4-quick-reference.md
Phil Skentelbery 0cca8169ce feat: Implement Phase 4 Web Interface with bugfixes (v0.5.2)
## Phase 4: Web Interface Implementation

Implemented complete web interface with public and admin routes,
templates, CSS, and development authentication.

### Core Features

**Public Routes**:
- Homepage with recent published notes
- Note permalinks with microformats2
- Server-side rendering (Jinja2)

**Admin Routes**:
- Login via IndieLogin
- Dashboard with note management
- Create, edit, delete notes
- Protected with @require_auth decorator

**Development Authentication**:
- Dev login bypass for local testing (DEV_MODE only)
- Security safeguards per ADR-011
- Returns 404 when disabled

**Templates & Frontend**:
- Base layouts (public + admin)
- 8 HTML templates with microformats2
- Custom responsive CSS (114 lines)
- Error pages (404, 500)

### Bugfixes (v0.5.1 → v0.5.2)

1. **Cookie collision fix (v0.5.1)**:
   - Renamed auth cookie from "session" to "starpunk_session"
   - Fixed redirect loop between dev login and admin dashboard
   - Flask's session cookie no longer conflicts with auth

2. **HTTP 404 error handling (v0.5.1)**:
   - Update route now returns 404 for nonexistent notes
   - Delete route now returns 404 for nonexistent notes
   - Follows ADR-012 HTTP Error Handling Policy
   - Pattern consistency across all admin routes

3. **Note model enhancement (v0.5.2)**:
   - Exposed deleted_at field from database schema
   - Enables soft deletion verification in tests
   - Follows ADR-013 transparency principle

### Architecture

**New ADRs**:
- ADR-011: Development Authentication Mechanism
- ADR-012: HTTP Error Handling Policy
- ADR-013: Expose deleted_at Field in Note Model

**Standards Compliance**:
- Uses uv for Python environment
- Black formatted, Flake8 clean
- Follows git branching strategy
- Version incremented per versioning strategy

### Test Results

- 405/406 tests passing (99.75%)
- 87% code coverage
- All security tests passing
- Manual testing confirmed working

### Documentation

- Complete implementation reports in docs/reports/
- Architecture reviews in docs/reviews/
- Design documents in docs/design/
- CHANGELOG updated for v0.5.2

### Files Changed

**New Modules**:
- starpunk/dev_auth.py
- starpunk/routes/ (public, admin, auth, dev_auth)

**Templates**: 10 files (base, pages, admin, errors)
**Static**: CSS and optional JavaScript
**Tests**: 4 test files for routes and templates
**Docs**: 20+ architectural and implementation documents

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-18 23:01:53 -07:00

11 KiB

Phase 4: Quick Reference

Phase: Web Interface Version: 0.5.0 Status: Design Complete Dependencies: Phase 3 (Authentication) ✓

Critical Decision: Development Authentication

Question: Should we implement a dev auth mechanism for local testing?

Answer: ✓ YES - Implement with strict safeguards

Why: Enable local testing without deploying to IndieLogin.com

How: Separate /dev/login route that only works when DEV_MODE=true

Safety: Returns 404 when disabled, visual warnings, config validation

Details: See ADR-011


What Phase 4 Delivers

Public Interface

  • Homepage with recent notes (/)
  • Note permalinks (/note/<slug>)
  • Microformats2 markup (h-feed, h-entry)

Admin Interface

  • Login via IndieLogin (/admin/login)
  • Dashboard with note list (/admin)
  • Create notes (/admin/new)
  • Edit notes (/admin/edit/<id>)
  • Delete notes (/admin/delete/<id>)

Development Tools

  • Dev auth for local testing (/dev/login)
  • Configuration validation
  • Dev mode warnings

Routes Summary

Public (No Auth)

GET  /              Homepage (note list)
GET  /note/<slug>   Note permalink

Auth Flow

GET  /admin/login   Login form
POST /admin/login   Start IndieLogin flow
GET  /auth/callback IndieLogin callback
POST /admin/logout  Logout

Admin (Auth Required)

GET  /admin              Dashboard
GET  /admin/new          Create note form
POST /admin/new          Save new note
GET  /admin/edit/<id>    Edit note form
POST /admin/edit/<id>    Update note
POST /admin/delete/<id>  Delete note

Dev (DEV_MODE Only)

GET  /dev/login     Instant login (bypasses IndieLogin)

File Structure

New Files (~2,770 lines total)

starpunk/routes/          # Route handlers
  ├── public.py           # Public routes
  ├── admin.py            # Admin routes
  ├── auth.py             # Auth routes
  └── dev_auth.py         # Dev routes

starpunk/dev_auth.py      # Dev auth module

templates/                # Jinja2 templates
  ├── base.html
  ├── index.html
  ├── note.html
  └── admin/
      ├── base.html
      ├── login.html
      ├── dashboard.html
      ├── new.html
      └── edit.html

static/css/style.css      # ~350 lines
static/js/preview.js      # Optional markdown preview

tests/
  ├── test_routes_public.py
  ├── test_routes_admin.py
  └── test_dev_auth.py

Modified Files

starpunk/config.py        # Add DEV_MODE, DEV_ADMIN_ME, VERSION
app.py                    # Register routes, validate config
CHANGELOG.md              # Add v0.5.0 entry

Configuration

New Environment Variables

# Development Mode (default: false)
DEV_MODE=false              # Set to 'true' for local dev
DEV_ADMIN_ME=               # Your identity URL for dev mode

# Version (for display)
VERSION=0.5.0

Development Setup

# For local development
DEV_MODE=true
DEV_ADMIN_ME=https://yoursite.com

# For production (or leave unset)
DEV_MODE=false
ADMIN_ME=https://yoursite.com

Security Measures

Dev Auth Safeguards

  1. Explicit Configuration: Requires DEV_MODE=true
  2. Separate Routes: /dev/login (not /admin/login)
  3. Route Protection: Returns 404 if DEV_MODE=false
  4. Config Validation: Prevents DEV_MODE + production URL
  5. Visual Warnings: Red banner when dev mode active
  6. Logging: All dev auth logged with warnings

Production Security

  • All admin routes use @require_auth
  • HttpOnly, Secure, SameSite cookies
  • CSRF state tokens
  • Session expiry (30 days)
  • Jinja2 auto-escaping (XSS prevention)

Template Architecture

Microformats

Homepage (h-feed):

<div class="h-feed">
  <article class="h-entry">
    <div class="e-content">...</div>
    <time class="dt-published">...</time>
    <a class="u-url" href="...">permalink</a>
  </article>
</div>

Note Page (h-entry):

<article class="h-entry">
  <div class="e-content">{{ note.html|safe }}</div>
  <a class="u-url" href="{{ url_for('public.note', slug=note.slug) }}">
    <time class="dt-published" datetime="{{ note.created_at.isoformat() }}">
      {{ note.created_at.strftime('%B %d, %Y') }}
    </time>
  </a>
</article>

Flash Messages

# In routes
flash('Note created successfully', 'success')
flash('Error: Note not found', 'error')

# In templates
{% with messages = get_flashed_messages(with_categories=true) %}
  {% for category, message in messages %}
    <div class="flash flash-{{ category }}">{{ message }}</div>
  {% endfor %}
{% endwith %}

CSS Architecture

Variables

:root {
  /* Colors */
  --color-text: #333;
  --color-bg: #fff;
  --color-link: #0066cc;
  --color-success: #28a745;
  --color-error: #dc3545;
  --color-warning: #ffc107;

  /* Typography */
  --font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'SF Mono', Monaco, monospace;

  /* Spacing */
  --spacing-md: 1rem;
  --spacing-lg: 2rem;

  /* Layout */
  --max-width: 42rem;
}

Mobile-First

/* Base: Mobile */
body { padding: 1rem; }

/* Tablet and up */
@media (min-width: 768px) {
  body { padding: 2rem; }
}

Testing Strategy

Coverage Target: >90%

Unit Tests

  • Public routes (homepage, note permalink)
  • Admin routes (dashboard, create, edit, delete)
  • Dev auth (login, validation, route protection)

Integration Tests

  • Full auth flow (mocked IndieLogin)
  • Create note end-to-end
  • Edit note end-to-end
  • Delete note end-to-end

Manual Tests

  • Browser testing (Chrome, Firefox, Safari)
  • Mobile responsive
  • Microformats validation (indiewebify.me)
  • HTML5 validation (W3C)
  • Real IndieLogin authentication

Implementation Checklist

Phase 4.1: Routes (8 hours)

  • Create routes package
  • Implement public routes
  • Implement auth routes
  • Implement admin routes

Phase 4.2: Templates (6 hours)

  • Base templates
  • Public templates
  • Admin templates

Phase 4.3: Dev Auth (4 hours)

  • dev_auth.py module
  • Config validation
  • Visual warnings

Phase 4.4: CSS (4 hours)

  • style.css
  • Responsive design

Phase 4.5: JS (Optional, 2 hours)

  • preview.js
  • Progressive enhancement

Phase 4.6: Testing (8 hours)

  • Route tests
  • Integration tests
  • >90% coverage

Phase 4.7: Documentation (2 hours)

  • Update CHANGELOG
  • Document routes
  • Version to 0.5.0

Total: ~34 hours


Acceptance Criteria

Must Pass

  • All routes work correctly
  • Authentication enforced on admin routes
  • Dev auth blocked when DEV_MODE=false
  • Templates render with microformats
  • Flash messages work
  • Test coverage >90%
  • No security vulnerabilities
  • Dev mode warnings display
  • Mobile responsive

Performance Targets

  • Homepage: < 200ms
  • Note page: < 200ms
  • Admin pages: < 200ms
  • Form submit: < 100ms

Key Integrations

With Existing Modules

auth.py (Phase 3):

from starpunk.auth import require_auth, verify_session, destroy_session

@require_auth
def dashboard():
    # User info in g.user_me
    pass

notes.py (Phase 2):

from starpunk.notes import (
    get_all_notes,
    get_note_by_slug,
    create_note,
    update_note,
    delete_note
)

database.py (Phase 1):

from starpunk.database import get_db

Risk Mitigation

Dev Auth Accidentally Enabled

Risk: Critical Mitigation:

  • Config validation
  • Startup warnings
  • Visual indicators
  • Deployment checklist
  • Documentation

XSS Vulnerabilities

Risk: High Mitigation:

  • Jinja2 auto-escaping
  • No user HTML
  • Code review
  • Security testing

Session Theft

Risk: Medium Mitigation:

  • HttpOnly cookies
  • Secure flag (production)
  • SameSite=Lax
  • HTTPS required

Common Patterns

Protected Route

from starpunk.auth import require_auth

@app.route('/admin/dashboard')
@require_auth
def dashboard():
    # g.user_me is set by require_auth
    notes = get_all_notes()
    return render_template('admin/dashboard.html', notes=notes)

Creating a Note

@app.route('/admin/new', methods=['POST'])
@require_auth
def create_note_submit():
    content = request.form.get('content')
    published = 'published' in request.form

    try:
        note = create_note(content, published)
        flash(f'Note created: {note.slug}', 'success')
        return redirect(url_for('admin.dashboard'))
    except ValueError as e:
        flash(f'Error: {e}', 'error')
        return redirect(url_for('admin.new_note_form'))

Dev Mode Check

# In dev_auth.py
def dev_login():
    if not current_app.config.get('DEV_MODE'):
        abort(404)  # Route doesn't exist

    me = current_app.config.get('DEV_ADMIN_ME')
    session_token = create_session(me)

    current_app.logger.warning(
        f"DEV MODE: Session created for {me} without authentication"
    )

    # Set cookie and redirect
    response = redirect(url_for('admin.dashboard'))
    response.set_cookie('session', session_token, httponly=True)
    return response

Troubleshooting

Dev Auth Not Working

  1. Check DEV_MODE=true in .env
  2. Check DEV_ADMIN_ME is set
  3. Restart Flask server
  4. Check logs for warnings

Templates Not Found

  1. Check templates/ directory exists
  2. Check template paths in render_template()
  3. Restart Flask server

CSS Not Loading

  1. Check static/css/style.css exists
  2. Check url_for('static', filename='css/style.css')
  3. Clear browser cache

Authentication Not Working

  1. Check ADMIN_ME is set correctly
  2. Check SESSION_SECRET is set
  3. Check IndieLogin callback URL matches
  4. Check browser cookies enabled

Next Steps After Phase 4

Phase 5: RSS Feed

  • Generate /feed.xml
  • Valid RSS 2.0
  • Published notes only

Phase 6: Micropub

  • /api/micropub endpoint
  • Accept h-entry posts
  • IndieAuth token verification

V1.0.0

  • Complete V1 features
  • Security audit
  • Performance optimization
  • Production deployment

Documentation References

  • ADR-011: Development Auth Decision
  • Phase 4 Design: Complete specification
  • Assessment Report: Architectural review
  • Phase 3 Report: Authentication implementation
  • ADR-003: Frontend Technology
  • ADR-005: IndieLogin Authentication
  • ADR-010: Authentication Module Design

Git Workflow

# Create feature branch
git checkout -b feature/phase-4-web-interface main

# Implement, test, commit frequently
git commit -m "Add public routes"
git commit -m "Add admin routes"
git commit -m "Add templates"
git commit -m "Add dev auth"
git commit -m "Add CSS"
git commit -m "Add tests"

# Update version
# Edit starpunk/__init__.py: __version__ = "0.5.0"
# Edit CHANGELOG.md

git commit -m "Bump version to 0.5.0"

# Merge to main
git checkout main
git merge feature/phase-4-web-interface

# Tag
git tag -a v0.5.0 -m "Release 0.5.0: Web Interface complete"

# Push
git push origin main v0.5.0

Status: Ready for Implementation Estimated Effort: 34 hours Target Version: 0.5.0 Developer: Use with Phase 4 Design Document