# StarPunk Technology Stack ## Project Summary StarPunk is a minimal, single-user IndieWeb CMS for publishing notes with RSS syndication. The project emphasizes radical simplicity, standards compliance, and user data ownership. Every technology choice is driven by the principle: "Every line of code must justify its existence. When in doubt, leave it out." ### Core Requirements - Publish IndieWeb-compatible notes (https://indieweb.org/note) - IndieAuth authentication using external provider (indielogin.com) - Micropub server endpoint for publishing from any client - RSS feed generation for syndication - File-based note storage for maximum portability - SQLite for metadata and structured data - Self-hostable single-user system - API-first architecture - Markdown support ## Complete Technology Stack ### Backend Stack #### Web Framework: Flask 3.0+ **Purpose**: HTTP server, routing, templating **Justification**: - Minimal micro-framework (< 1000 lines core code) - Perfect for single-user applications - Native support for both JSON APIs and HTML rendering - Mature, stable, well-documented (13+ years) - Built-in Jinja2 templating for server-side rendering - Standard WSGI interface for deployment flexibility **Alternatives Rejected**: - FastAPI: Async complexity unnecessary for single-user CMS - Django: Massive framework with ORM, admin, multi-user features we don't need - Bottle: Too minimal, smaller ecosystem **Reference**: ADR-001 #### Python Version: 3.11+ **Purpose**: Programming language **Justification**: - User's preferred language - Excellent standard library (sqlite3, hashlib, secrets, etc.) - Rich ecosystem for web development - Strong typing support (type hints) - Mature dependency management (pip, venv) #### Data Persistence: Hybrid File + Database ##### Note Storage: Markdown Files on Disk **Purpose**: Store note content **Format**: Plain markdown files (.md) **Structure**: ``` data/notes/ ├── 2024/ │ ├── 11/ │ │ ├── my-first-note.md │ │ └── another-note.md │ └── 12/ │ └── december-note.md └── 2025/ └── 01/ └── new-year-note.md ``` **Naming Convention**: `{slug}.md` **Organization**: Year/Month subdirectories (`YYYY/MM/`) **File Format**: Pure markdown, no frontmatter **Justification**: - Maximum portability (user requirement) - Human-readable, editable in any text editor - Easy backup (cp, rsync, git) - User owns data directly - No vendor lock-in - Future-proof format **Reference**: ADR-004 ##### Metadata Storage: SQLite **Purpose**: Store note metadata, sessions, tokens **Database**: `data/starpunk.db` **Schema**: ```sql -- Note metadata (NOT content) CREATE TABLE notes ( id INTEGER PRIMARY KEY AUTOINCREMENT, slug TEXT UNIQUE NOT NULL, file_path TEXT UNIQUE NOT NULL, published BOOLEAN DEFAULT 0, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, content_hash TEXT ); -- Authentication sessions (IndieLogin) CREATE TABLE sessions ( id INTEGER PRIMARY KEY AUTOINCREMENT, session_token TEXT UNIQUE NOT NULL, me TEXT NOT NULL, created_at TIMESTAMP NOT NULL, expires_at TIMESTAMP NOT NULL, last_used_at TIMESTAMP ); -- Micropub access tokens CREATE TABLE tokens ( token TEXT PRIMARY KEY, me TEXT NOT NULL, client_id TEXT, scope TEXT, created_at TIMESTAMP NOT NULL, expires_at TIMESTAMP ); -- CSRF state tokens CREATE TABLE auth_state ( state TEXT PRIMARY KEY, created_at TIMESTAMP NOT NULL, expires_at TIMESTAMP NOT NULL ); ``` **Justification**: - Single file, perfect for single-user - No separate server process - Excellent for read-heavy workloads (blog) - Fast indexing and querying - Built into Python standard library - Enables efficient metadata queries without parsing files - Atomic transactions for data integrity **Hybrid Strategy**: Files are authoritative for content; database is authoritative for metadata. This gives us portability AND performance. **Reference**: ADR-004 #### Core Dependencies ##### markdown (3.5+) **Purpose**: Convert markdown to HTML **Usage**: Render note content for display and RSS feed **Justification**: - Pure Python, standard markdown implementation - Simple API: `markdown.markdown(text)` - Sufficient performance for single-user system - More standard than alternatives (mistune) ##### feedgen (1.0+) **Purpose**: Generate RSS 2.0 feeds **Usage**: Create valid RSS feed from published notes **Justification**: - High-level API ensures RSS 2.0 compliance - Handles date formatting (RFC-822) automatically - CDATA wrapping for HTML content - Better than manual XML generation (error-prone) ##### httpx (0.27+) **Purpose**: HTTP client library **Usage**: - Communication with indielogin.com API - Verify Micropub client metadata - Fetch remote URLs for verification **Justification**: - Modern, clean API - Synchronous and async support - Better than requests (async capability) and urllib (too low-level) - Proper timeout handling - SSL verification built-in ##### python-dotenv (1.0+) **Purpose**: Environment configuration **Usage**: Load settings from `.env` file **Justification**: - Industry standard for configuration - Keeps secrets out of code - Simple API: `load_dotenv()` - Minimal overhead ##### pytest (8.0+) **Purpose**: Testing framework **Usage**: Unit and integration tests **Justification**: - Current Python testing standard - Minimal boilerplate - Clear assertions - Built-in fixtures - Better than unittest (verbose) and nose2 (unmaintained) **Reference**: ADR-002 #### Dependencies Explicitly REJECTED - **Flask-SQLAlchemy**: ORM abstraction unnecessary, adds complexity - **Flask-Login**: Session-based auth, we need token-based for Micropub - **Flask-CORS**: Single decorator, don't need full extension (5 lines of code) - **Flask-WTF**: Form library overkill for simple note creation - **Flask-Limiter**: Rate limiting deferred to V2 or reverse proxy **Decision**: Use Python standard library and explicit code instead of extensions where possible. Each dependency must justify its existence. **Reference**: ADR-002 ### Frontend Stack #### Template Engine: Jinja2 **Purpose**: Server-side HTML rendering **Included With**: Flask (no additional dependency) **Usage**: - Public interface (homepage, note permalinks) - Admin interface (dashboard, note editor) - Microformats markup (h-entry, h-card) **Justification**: - Zero build process - Server-side rendering for better performance - Works without JavaScript (progressive enhancement) - Easy microformats implementation - Familiar syntax - Stable and mature **Reference**: ADR-003 #### CSS: Custom Stylesheet **Purpose**: Visual styling **Approach**: Single custom CSS file, no framework **File**: `static/css/style.css` **Size**: ~200 lines for entire site **Features**: - CSS custom properties (variables) for theming - Mobile-first responsive design - Simple media queries for tablet/desktop - Semantic HTML5 + minimal classes **Justification**: - No framework overhead (Bootstrap, Tailwind, etc.) - No build tools required - Full control over appearance - Minimal single theme fits project scope - Faster than loading framework CSS **Example**: ```css :root { --color-text: #333; --color-bg: #fff; --max-width: 42rem; --spacing: 1rem; } ``` **Frameworks Rejected**: - Tailwind: Requires build process, utility-first doesn't fit - Bootstrap/Bulma: Too many unused features - PicoCSS: Good but custom CSS gives more control **Reference**: ADR-003 #### JavaScript: Minimal Vanilla JS **Purpose**: Markdown preview in admin (optional enhancement) **Approach**: Single vanilla JavaScript file, no framework **File**: `static/js/preview.js` **Dependency**: marked.js via CDN (client-side markdown) **Usage**: - Optional real-time markdown preview in note editor - Progressive enhancement (works without JS) **Justification**: - Core functionality works without JavaScript - Single optional feature doesn't justify framework - Vanilla JS sufficient for simple preview - Modern browser APIs (fetch, DOM manipulation) are enough - No build tools required **Frameworks Rejected**: - React/Vue/Svelte: Massive overkill for one preview feature - htmx: Interesting but not needed for V1 - Alpine.js: Too much for minimal JS needs **Reference**: ADR-003 #### Build Tools: NONE **Decision**: No build process whatsoever **Justification**: - Server-side rendering eliminates need for bundling - Custom CSS served directly - Vanilla JS served directly - Modern browsers support ES6+ natively - Zero npm dependencies - Instant development setup **This means**: - No webpack, Vite, Rollup, esbuild - No Babel transpilation - No PostCSS processing - No minification (premature optimization) - No asset pipeline **Reference**: ADR-003 ### Authentication Stack #### Admin Authentication: IndieLogin.com **Purpose**: Authenticate the admin user via their personal website **Provider**: External service at https://indielogin.com **API**: https://indielogin.com/api **Protocol**: OAuth 2.0 / IndieAuth **Flow**: 1. User enters their website URL 2. StarPunk redirects to indielogin.com with state token 3. indielogin.com verifies user's identity (RelMeAuth, email, etc.) 4. indielogin.com redirects back with authorization code 5. StarPunk exchanges code for verified identity 6. StarPunk creates session cookie **Session Management**: - HttpOnly, Secure cookies - 30-day expiry - Stored in SQLite sessions table - CSRF protection via state tokens **Configuration**: ```bash ADMIN_ME=https://your-website.com # Only this URL can authenticate SESSION_SECRET=random-secret-key ``` **Justification**: - Extremely simple (< 100 lines of code) - No authentication code to maintain - No password management needed - True IndieWeb authentication (user owns identity) - Secure by default (delegated to trusted service) - Community-maintained, stable service **Alternatives Rejected**: - Self-hosted IndieAuth: Too complex for V1 - Password auth: Not IndieWeb-compatible, security burden - OAuth (GitHub/Google): User doesn't own identity **Reference**: ADR-005 #### Micropub Authentication: IndieAuth Tokens **Purpose**: Authenticate Micropub API clients **Protocol**: IndieAuth bearer tokens **Flow**: Standard IndieAuth authorization code grant **Storage**: Tokens table in SQLite **Note**: Micropub token endpoint is separate from admin authentication. Users authenticate their Micropub clients (e.g., mobile apps) separately via IndieAuth flow. This will be detailed in a future ADR for Micropub implementation. ### Development Tools #### Code Quality ``` pytest-cov # Test coverage reporting black # Code formatting (standard: 88 char line length) flake8 # Linting mypy # Type checking (optional but recommended) ``` **Justification**: - Automated formatting prevents style debates - Linting catches common errors - Test coverage ensures quality - Type hints improve maintainability #### Development Workflow ```bash # Setup python -m venv venv source venv/bin/activate pip install -r requirements.txt # Run flask run # Test pytest # Format black . flake8 . ``` **No additional tools required**: No npm, no build scripts, no containers (optional for deployment). ### Deployment Stack #### WSGI Server: Gunicorn (Production) **Purpose**: Production HTTP server **Justification**: - Standard Python WSGI server - Production-ready - Better performance than Flask dev server - Simple configuration **Alternative**: uWSGI (more complex, not needed for single-user) #### Reverse Proxy: Nginx or Caddy (Recommended) **Purpose**: HTTPS termination, static file serving **Justification**: - Handle SSL/TLS certificates - Serve static files efficiently - Rate limiting (optional) - Proven deployment pattern #### Process Manager: systemd (Recommended) **Purpose**: Keep application running **Justification**: - Standard on modern Linux - Auto-restart on failure - Log management #### Deployment Package: Single Unit **Structure**: ``` starpunk/ ├── app.py # Main application ├── requirements.txt # Dependencies ├── .env.example # Configuration template ├── static/ # CSS, JS ├── templates/ # Jinja2 templates ├── data/ # Notes + SQLite (persistent) │ ├── notes/ │ └── starpunk.db └── README.md # Setup instructions ``` **Deployment**: - Clone repository - Create virtual environment - Install dependencies - Configure .env file - Run with Gunicorn + systemd - (Optional) Nginx for HTTPS **Justification**: Single self-contained package, easy to deploy and backup. ## File Organization ### Project Structure ``` starpunk/ ├── app.py # Main Flask application ├── requirements.txt # Python dependencies ├── .env # Environment configuration (gitignored) ├── .env.example # Configuration template ├── README.md # Setup documentation ├── CLAUDE.MD # Project requirements │ ├── starpunk/ # Application package │ ├── __init__.py │ ├── config.py # Configuration loading │ ├── database.py # SQLite operations │ ├── models.py # Data models │ ├── auth.py # Authentication logic │ ├── micropub.py # Micropub endpoint │ ├── feed.py # RSS generation │ └── utils.py # Helper functions │ ├── static/ # Static assets │ ├── css/ │ │ └── style.css # Single stylesheet │ └── js/ │ └── preview.js # Optional markdown preview │ ├── templates/ # Jinja2 templates │ ├── base.html # Base layout │ ├── index.html # Homepage (note list) │ ├── note.html # Single note │ ├── feed.xml # RSS template │ └── admin/ │ ├── base.html # Admin layout │ ├── login.html # Login form │ ├── dashboard.html # Admin dashboard │ ├── new.html # Create note │ └── edit.html # Edit note │ ├── data/ # Persistent data (gitignored) │ ├── notes/ # Markdown files │ │ └── YYYY/MM/ │ │ └── slug.md │ └── starpunk.db # SQLite database │ ├── tests/ # Test suite │ ├── test_auth.py │ ├── test_database.py │ ├── test_micropub.py │ ├── test_feed.py │ └── test_notes.py │ └── docs/ # Architecture documentation ├── architecture/ │ ├── overview.md │ ├── components.md │ ├── data-flow.md │ ├── security.md │ └── technology-stack.md └── decisions/ ├── ADR-001-python-web-framework.md ├── ADR-002-flask-extensions.md ├── ADR-003-frontend-technology.md ├── ADR-004-file-based-note-storage.md └── ADR-005-indielogin-authentication.md ``` ## Architecture Patterns ### API-First Design **Pattern**: All functionality exposed via API, web interface consumes API **Routes**: ``` # Public API GET /api/notes # List published notes GET /api/notes/{slug} # Get single note GET /feed.xml # RSS feed # Admin API (session auth) POST /api/notes # Create note PUT /api/notes/{id} # Update note DELETE /api/notes/{id} # Delete note # Micropub API (token auth) POST /api/micropub # Create via Micropub GET /api/micropub?q=config # Query config # Auth API GET /admin/login # Login form POST /admin/login # Initiate IndieLogin GET /auth/callback # IndieLogin callback POST /admin/logout # Logout ``` ### Data Flow: File + Database Sync #### Creating a Note ``` User submits note ↓ Generate slug ↓ Create file: data/notes/YYYY/MM/{slug}.md ↓ Calculate content hash ↓ Insert database record (slug, file_path, hash, timestamps) ↓ If database insert fails: delete file, return error ↓ Return success ``` #### Reading a Note ``` Request note by slug ↓ Query database for file_path ↓ Read markdown from file ↓ Render to HTML (if needed) ↓ Return content + metadata ``` #### Updating a Note ``` User submits changes ↓ Atomic write: new content to temp file ↓ Calculate new hash ↓ Update database (timestamp, hash) ↓ If database update succeeds: atomic rename temp → actual ↓ If database update fails: delete temp, return error ↓ Return success ``` **Benefits**: - Files provide portability - Database provides fast queries - Content hash detects external changes - Atomic operations prevent corruption **Reference**: ADR-004 ### IndieLogin Authentication Flow ``` ┌─────────┐ ┌──────────┐ ┌─────────────┐ │ User │ │ StarPunk │ │ IndieLogin │ └────┬────┘ └────┬─────┘ └──────┬──────┘ │ │ │ │ 1. Click "Login" │ │ ├─────────────────────────>│ │ │ │ │ │ 2. Enter website URL │ │ ├─────────────────────────>│ │ │ │ │ │ 3. Generate state token │ │ │ │ │ 4. Redirect to IndieLogin with: │ │ - me=user_website │ │ - client_id=starpunk_url │ │ - redirect_uri=starpunk/callback │ │ - state=random_token │ │ ├──────────────────────────>│ │ │ │ │ │ 5. Verify user's │ │ │ identity │ │ <────────────────────────────────────────────────── │ │ (User authenticates via │ │ chosen method) │ │ ──────────────────────────────────────────────────> │ │ │ │ │ 6. Redirect back with code + state │ │ <──────────────────────────────────────────────────│ ├─────────────────────────>│ │ │ │ │ │ 7. Verify state │ │ │ │ │ 8. POST to IndieLogin: │ │ - code │ │ - client_id │ │ - redirect_uri │ │ ├──────────────────────────>│ │ │ │ │ │ 9. Return verified "me" │ │ │<──────────────────────────│ │ │ │ │ 10. Verify me == ADMIN_ME │ │ │ │ │ 11. Create session │ │ │ │ │ 12. Set session cookie │ │ │ <───────────────────────│ │ │ │ │ │ 13. Redirect to admin │ │ │ <───────────────────────│ │ │ │ │ ``` **Security Features**: - State token prevents CSRF - Session tokens are cryptographically random - HttpOnly cookies prevent XSS - Only ADMIN_ME URL can authenticate - Sessions expire after 30 days **Reference**: ADR-005 ### Progressive Enhancement Pattern **Principle**: Core functionality works without JavaScript #### Public Interface - **Without JS**: Full functionality (view notes, RSS feed) - **With JS**: No difference (no JS used on public pages) #### Admin Interface - **Without JS**: - Create/edit notes via HTML forms - Submit to server, server renders markdown - Full page refresh on submit - **With JS**: - Real-time markdown preview - No page refresh for preview - Still submits via form (progressive enhancement) **Implementation**: ```html
``` **Reference**: ADR-003 ## Standards Compliance ### IndieWeb Standards #### Microformats2 **Required Classes**: - `h-entry`: Mark up notes - `h-card`: Mark up author information - `e-content`: Note content - `dt-published`: Publication timestamp - `u-url`: Permalink URL **Example**: ```html

Note content here

``` **Validation**: https://indiewebify.me/ #### IndieAuth **Compliance**: OAuth 2.0 authorization code flow **Endpoints**: Delegated to indielogin.com **Token Format**: Bearer tokens **Validation**: Token introspection **Reference**: https://indieauth.spec.indieweb.org/ #### Micropub **Compliance**: Full Micropub spec support **Content Types**: JSON and form-encoded **Required Responses**: 201 Created with Location header **Query Support**: q=config, q=source **Validation**: https://micropub.rocks/ **Reference**: https://micropub.spec.indieweb.org/ ### Web Standards #### RSS 2.0 **Compliance**: Valid RSS 2.0 XML **Required Elements**: title, link, description, pubDate, guid **Date Format**: RFC-822 **HTML Content**: CDATA-wrapped **Validation**: https://validator.w3.org/feed/ #### HTTP **Status Codes**: Proper use of 200, 201, 400, 401, 404, 500 **Headers**: Content-Type, Cache-Control, Location **Methods**: GET, POST, PUT, DELETE **CORS**: Allow cross-origin for API endpoints #### HTML5 **Compliance**: Valid semantic HTML **Accessibility**: ARIA labels, alt text, proper heading hierarchy **Responsive**: Viewport meta tag, mobile-first CSS **Forms**: Proper labels, validation attributes **Validation**: https://validator.w3.org/ ## Security Architecture ### Authentication Security - State tokens for CSRF protection (5-minute expiry) - Session tokens are cryptographically random (32 bytes) - HttpOnly cookies prevent XSS theft - Secure flag requires HTTPS - SameSite=Lax prevents CSRF - Single admin user (ADMIN_ME verification) ### Input Validation - Validate all user input - Sanitize markdown (prevent XSS in rendered HTML) - Validate Micropub payloads against spec - URL validation for IndieAuth - File path validation (prevent directory traversal) ### Database Security - Parameterized queries (prevent SQL injection) - Input sanitization before storage - Hash session tokens before storage - Content hashing for integrity ### Network Security - HTTPS required in production - SSL certificate verification on httpx requests - Secure headers (CSP, X-Frame-Options, etc.) - Rate limiting via reverse proxy (nginx/Caddy) ### File System Security - Atomic file operations - Restricted permissions on data/ directory - Prevent directory traversal attacks - Validate file paths before operations ## Performance Targets ### Response Times - API responses: < 100ms - Page loads: < 200ms - RSS feed: < 300ms ### Optimization Strategy - SQLite indexes on frequently queried columns - Cache RSS feed (5 minutes) - Minimal dependencies = fast startup - Server-side rendering = fast first paint - Single CSS file = one request - Optional JS = doesn't block rendering ### Resource Usage - Memory: < 100MB for typical workload - Disk: Minimal (SQLite + markdown files) - CPU: Minimal (no heavy processing) **Scaling**: Designed for single-user, typical load is <10 requests/minute. Over-engineering for scale would violate simplicity principle. ## Testing Strategy ### Unit Tests (pytest) - Database operations (CRUD, queries) - Slug generation and validation - Markdown rendering - File operations (atomic writes) - Session management - Token validation - Content hash calculation ### Integration Tests - IndieLogin authentication flow (mocked API) - Micropub note creation (full flow) - RSS feed generation (validation) - API endpoints (request/response) - File + database sync - Error handling ### Manual Tests - Real IndieLogin authentication - Micropub client integration (e.g., Quill) - RSS feed in actual reader - Browser compatibility - Mobile responsiveness - Accessibility (screen readers) ### Validation Tests - HTML validation (W3C validator) - RSS validation (W3C feed validator) - Microformats validation (indiewebify.me) - Micropub compliance (micropub.rocks) ## Risk Assessment ### Technical Risks #### Risk: IndieLogin.com Outage **Impact**: Cannot authenticate new sessions **Likelihood**: Low (stable service) **Mitigation**: - Sessions last 30 days (brief outages don't lock out user) - Document manual session creation in database - V2: Add fallback authentication method #### Risk: File/Database Sync Failure **Impact**: Data inconsistency **Likelihood**: Low (atomic operations, error handling) **Mitigation**: - Write files first, database second - Transaction rollback on failure - Integrity check on startup (optional) - Regular backups #### Risk: File System Corruption **Impact**: Lost notes **Likelihood**: Very low (standard filesystem operations) **Mitigation**: - Atomic file writes - Regular backups (user responsibility) - Markdown files are recoverable #### Risk: Dependency Vulnerabilities **Impact**: Security breach **Likelihood**: Medium (all software has bugs) **Mitigation**: - Minimal dependencies (6 direct) - All dependencies are mature, maintained - Regular updates - Security scanning (optional) ### Operational Risks #### Risk: User Misconfiguration **Impact**: Application doesn't work **Likelihood**: Medium (manual setup required) **Mitigation**: - Clear documentation - .env.example with all settings - Validation on startup - Helpful error messages #### Risk: Backup Neglect **Impact**: Data loss **Likelihood**: Medium (user responsibility) **Mitigation**: - Document backup procedures - Make backup easy (copy data/ folder) - Consider automated backup scripts (V2) ## Migration and Future Considerations ### V1 to V2 Migration Path - Add features without breaking existing data - Markdown files remain compatible - Database schema migrations (ALTER TABLE) - Backward compatible API changes ### Potential V2 Enhancements - Webmentions support - Media uploads (photos) - Additional post types (articles, replies) - Full-text search (SQLite FTS) - Automated backups - Self-hosted IndieAuth option - Multiple IndieAuth providers - Draft/scheduled posts - Tags and categories - Import/export tools ### Data Portability Strategy **Export Formats**: - Markdown files (already portable) - JSON export (notes + metadata) - RSS feed (existing notes) - HTML archive (static site generator) **Import Strategy** (V2): - From other blogging platforms - From JSON backup - From markdown directories ## Success Criteria The technology stack is successful if: 1. **User can publish notes from any Micropub client** ✓ - Protocol: Micropub over HTTP - Auth: IndieAuth tokens - Format: Stored as markdown files 2. **Notes appear in RSS readers immediately** ✓ - Format: Valid RSS 2.0 - Generator: feedgen library - Caching: 5 minutes 3. **System runs on minimal resources** ✓ - Stack: Flask + SQLite (single process) - Memory: < 100MB - Dependencies: 6 direct 4. **Code is readable and maintainable** ✓ - Language: Python (user's preference) - Framework: Flask (minimal, clear) - Style: black formatting, type hints 5. **All IndieWeb validators pass** ✓ - Microformats: Server-side templating makes this easy - IndieAuth: Delegated to indielogin.com - Micropub: Spec-compliant implementation 6. **Setup takes less than 5 minutes** ✓ - Steps: Clone, venv, pip install, configure .env, run - No build process - No complex dependencies 7. **System runs for months without intervention** ✓ - Architecture: Stateless application - Persistence: SQLite (reliable) - Auth: Long-lived sessions (30 days) ## Quick Start Guide ### Development Setup ```bash # Clone repository git clone && cd starpunk # Create virtual environment python -m venv venv source venv/bin/activate # or `venv\Scripts\activate` on Windows # Install dependencies pip install -r requirements.txt # Configure cp .env.example .env # Edit .env: set SITE_URL, ADMIN_ME, SESSION_SECRET # Initialize database flask db init # Run development server flask run # Visit http://localhost:5000 ``` ### Production Deployment ```bash # Setup (same as development) # ... # Install production server pip install gunicorn # Run with Gunicorn gunicorn -w 4 -b 127.0.0.1:8000 app:app # Configure nginx/Caddy for HTTPS # Configure systemd for process management # Set up regular backups of data/ directory ``` ### Configuration Reference ```bash # .env file SITE_URL=https://starpunk.example.com # Your domain ADMIN_ME=https://your-website.com # Your IndieWeb identity SESSION_SECRET=random-secret-key # Generate with: python -c "import secrets; print(secrets.token_hex(32))" DATA_PATH=./data # Where to store notes and database ``` ## Summary StarPunk's technology stack achieves radical simplicity through careful technology selection: - **Backend**: Flask (micro-framework) + SQLite (embedded DB) + Python stdlib - **Storage**: Markdown files (portability) + SQLite metadata (performance) - **Frontend**: Jinja2 (SSR) + custom CSS (200 lines) + optional vanilla JS - **Auth**: IndieLogin.com (external, zero maintenance) - **Build**: None (zero build tools, zero npm) - **Deploy**: Single package (Gunicorn + systemd + nginx) **Total Direct Dependencies**: 6 (Flask, markdown, feedgen, httpx, python-dotenv, pytest) **Lines of Code Estimate**: ~1500 LOC for complete V1 implementation **Setup Time**: < 5 minutes from clone to running This stack embodies the project philosophy: "Every line of code must justify its existence." Each technology choice prioritizes simplicity, standards compliance, and user data ownership over features and complexity. ## References ### Architecture Decision Records - [ADR-001: Python Web Framework Selection](/home/phil/Projects/starpunk/docs/decisions/ADR-001-python-web-framework.md) - [ADR-002: Flask Extensions and Dependencies](/home/phil/Projects/starpunk/docs/decisions/ADR-002-flask-extensions.md) - [ADR-003: Front-end Technology Stack](/home/phil/Projects/starpunk/docs/decisions/ADR-003-frontend-technology.md) - [ADR-004: File-Based Note Storage Architecture](/home/phil/Projects/starpunk/docs/decisions/ADR-004-file-based-note-storage.md) - [ADR-005: IndieLogin Authentication Integration](/home/phil/Projects/starpunk/docs/decisions/ADR-005-indielogin-authentication.md) ### Standards and Specifications - IndieWeb: https://indieweb.org/ - IndieAuth Spec: https://indieauth.spec.indieweb.org/ - Micropub Spec: https://micropub.spec.indieweb.org/ - Microformats2: http://microformats.org/wiki/h-entry - RSS 2.0: https://www.rssboard.org/rss-specification - CommonMark: https://spec.commonmark.org/ ### Tools and Libraries - Flask: https://flask.palletsprojects.com/ - Jinja2: https://jinja.palletsprojects.com/ - IndieLogin.com: https://indielogin.com/ - Python Markdown: https://python-markdown.github.io/ - feedgen: https://feedgen.kiesow.be/ - httpx: https://www.python-httpx.org/ ### Validation and Testing - IndieWebify.me: https://indiewebify.me/ - Micropub Rocks: https://micropub.rocks/ - W3C Feed Validator: https://validator.w3.org/feed/ - W3C HTML Validator: https://validator.w3.org/