Files
StarPunk/docs/architecture/technology-stack.md
2025-11-18 19:21:31 -07:00

33 KiB

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:

-- 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:

: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:

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

# 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)

Purpose: HTTPS termination, static file serving Justification:

  • Handle SSL/TLS certificates
  • Serve static files efficiently
  • Rate limiting (optional)
  • Proven deployment pattern

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:

<!-- Note editor works without JS -->
<form method="POST" action="/api/notes">
  <textarea name="content" required></textarea>
  <button type="submit">Publish</button>
</form>

<!-- JS enhances with preview -->
<script src="/static/js/preview.js"></script>

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:

<article class="h-entry">
  <div class="e-content">
    <p>Note content here</p>
  </div>
  <footer>
    <a class="u-url" href="/note/abc123">
      <time class="dt-published" datetime="2024-11-18T12:00:00Z">
        November 18, 2024
      </time>
    </a>
  </footer>
</article>

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

# Clone repository
git clone <repo> && 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

# 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

# .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

Standards and Specifications

Tools and Libraries

Validation and Testing