# 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/`) - 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/`) - Delete notes (`/admin/delete/`) ### 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/ 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/ Edit note form POST /admin/edit/ Update note POST /admin/delete/ 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 ```bash # 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 ```bash # 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): ```html
``` **Note Page** (h-entry): ```html ``` ### Flash Messages ```python # 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 %}
{{ message }}
{% endfor %} {% endwith %} ``` --- ## CSS Architecture ### Variables ```css :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 ```css /* 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): ```python 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): ```python from starpunk.notes import ( get_all_notes, get_note_by_slug, create_note, update_note, delete_note ) ``` **database.py** (Phase 1): ```python 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 ```python 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 ```python @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 ```python # 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 ```bash # 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