Files
StarPunk/docs/decisions/ADR-003-frontend-technology.md
2025-11-18 19:21:31 -07:00

8.8 KiB

ADR-003: Front-end Technology Stack

Status

Accepted

Context

StarPunk requires a front-end for:

  1. Public interface (homepage, note permalinks) - Server-side rendered
  2. Admin interface (note creation/editing) - Requires some interactivity
  3. Progressive enhancement principle - Core functionality must work without JavaScript

The front-end must be minimal, elegant, and align with the "no client-side complexity" principle stated in CLAUDE.MD.

Decision

Public Interface: Server-Side Rendered HTML

  • Template Engine: Jinja2 (included with Flask)
  • CSS: Custom CSS (no framework)
  • JavaScript: None required for V1
  • Build Tools: None required

Admin Interface: Enhanced Server-Side Rendering

  • Template Engine: Jinja2 (included with Flask)
  • CSS: Custom CSS (shared with public interface)
  • JavaScript: Minimal vanilla JavaScript for markdown preview only
  • Build Tools: None required

Asset Management

  • CSS: Single stylesheet served statically
  • JavaScript: Single optional file for markdown preview
  • No bundler: Direct file serving
  • No transpilation: Modern browsers only (ES6+)

Rationale

Server-Side Rendering (SSR)

Simplicity Score: 10/10

  • Zero build process
  • No JavaScript framework complexity
  • Direct Flask template rendering
  • Familiar Jinja2 syntax

Fitness Score: 10/10

  • Perfect for content-first site
  • Faster initial page load
  • Better SEO (though not critical for single-user)
  • Works without JavaScript
  • Easier to implement microformats

Maintenance Score: 10/10

  • Jinja2 is stable and mature
  • No framework version updates
  • No npm dependency hell
  • Templates are simple HTML

No CSS Framework

Simplicity Score: 10/10

  • Custom CSS is ~200 lines for entire site
  • No unused classes or styles
  • Full control over appearance
  • No framework learning curve

Fitness Score: 9/10

  • StarPunk needs minimal, elegant design
  • Single theme, no customization needed
  • Mobile-responsive can be achieved with simple media queries
  • No complex components needed

Minimal JavaScript Approach

Simplicity Score: 9/10

  • Vanilla JavaScript only (no React/Vue/Svelte)
  • Single purpose: markdown preview in admin
  • Optional progressive enhancement
  • No build step required

Fitness Score: 10/10

  • Markdown preview improves UX but isn't required
  • All functionality works without JavaScript
  • Can use fetch API for preview without library
  • Modern browser features are sufficient

Consequences

Positive

  • Zero build time
  • No node_modules directory
  • Instant development setup
  • Fast page loads
  • Works with JavaScript disabled
  • Easy to understand and modify
  • Microformats implementation is straightforward
  • Complete control over HTML output

Negative

  • No TypeScript type checking
  • No hot module replacement (but Flask auto-reload works)
  • Manual CSS organization required
  • Must write responsive CSS manually

Mitigation

  • Keep JavaScript minimal and well-commented
  • Organize CSS with clear sections
  • Use CSS custom properties for theming
  • Test manually in multiple browsers
  • Validate HTML with W3C validator

Frontend File Structure

static/
├── css/
│   └── style.css          # Single stylesheet for entire site
└── js/
    └── preview.js         # Optional markdown preview (admin only)

templates/
├── base.html              # Base template with HTML structure
├── index.html             # Homepage (note list)
├── note.html              # Single note permalink
└── admin/
    ├── base.html          # Admin base template
    ├── dashboard.html     # Admin dashboard
    ├── new.html           # Create new note
    └── edit.html          # Edit existing note

CSS Architecture

Custom CSS Properties (Variables)

:root {
  --color-text: #333;
  --color-bg: #fff;
  --color-link: #0066cc;
  --color-border: #ddd;
  --font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono: 'SF Mono', Monaco, monospace;
  --spacing-unit: 1rem;
  --max-width: 42rem;
}

Mobile-First Responsive Design

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

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

JavaScript Architecture

Markdown Preview Implementation

// static/js/preview.js
// Simple markdown preview using marked.js CDN (no build step)
// Progressive enhancement - form works without this

Decision: Use marked.js from CDN for client-side preview

  • Justification: Same library as server-side (consistency)
  • Simplicity: No bundling required
  • Reliability: CDN delivers cached version
  • Alternative: No preview (acceptable fallback)

Template Organization

Jinja2 Template Strategy

  • Inheritance: Use base templates for common structure
  • Blocks: Define clear content blocks for overriding
  • Macros: Create reusable microformat snippets
  • Filters: Use Jinja2 filters for date formatting

Example Base Template Structure

{# templates/base.html #}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>{% block title %}{{ site.title }}{% endblock %}</title>
  <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
  <link rel="alternate" type="application/rss+xml" href="{{ url_for('feed') }}">
  {% block head %}{% endblock %}
</head>
<body>
  {% block content %}{% endblock %}
</body>
</html>

Microformats Integration

Server-side rendering makes microformats implementation straightforward:

{# Macro for h-entry note rendering #}
{% macro render_note(note) %}
<article class="h-entry">
  <div class="e-content">
    {{ note.content_html | safe }}
  </div>
  <footer>
    <a class="u-url" href="{{ url_for('note', slug=note.slug) }}">
      <time class="dt-published" datetime="{{ note.created_at.isoformat() }}">
        {{ note.created_at.strftime('%B %d, %Y') }}
      </time>
    </a>
  </footer>
</article>
{% endmacro %}

Build and Development Workflow

Development

  1. Run Flask development server: flask run
  2. Edit templates/CSS/JS directly
  3. Browser auto-refresh on template changes
  4. No build step required

Production

  1. Copy static files to production
  2. Templates are rendered on-demand
  3. Optionally enable Flask caching for rendered HTML
  4. Serve static assets with nginx/Apache (optional)

Browser Support

  • Modern browsers (Chrome 90+, Firefox 88+, Safari 14+, Edge 90+)
  • Mobile browsers (iOS Safari 14+, Chrome Android 90+)
  • Progressive enhancement ensures basic functionality on older browsers

Alternatives Considered

React/Vue/Svelte (Rejected)

  • Simplicity: 2/10 - Requires build tools, npm, bundlers
  • Fitness: 3/10 - Massive overkill for content site
  • Maintenance: 5/10 - Constant framework updates
  • Verdict: Violates "no client-side complexity" principle

htmx (Considered)

  • Simplicity: 8/10 - Single JavaScript file, declarative
  • Fitness: 6/10 - Useful for dynamic updates, but not needed in V1
  • Maintenance: 8/10 - Stable, minimal dependencies
  • Verdict: Interesting for V2, but V1 doesn't need dynamic updates

Alpine.js (Considered)

  • Simplicity: 8/10 - Lightweight, declarative
  • Fitness: 5/10 - Good for small interactions, but we barely need any
  • Maintenance: 8/10 - Well maintained
  • Verdict: Too much for the minimal JS we need

Tailwind CSS (Rejected)

  • Simplicity: 4/10 - Requires build process, large configuration
  • Fitness: 3/10 - Utility-first doesn't fit minimal design needs
  • Maintenance: 7/10 - Well maintained but heavy
  • Verdict: Build process violates simplicity; custom CSS is sufficient

Bootstrap/Bulma (Rejected)

  • Simplicity: 5/10 - Large framework with many unused features
  • Fitness: 3/10 - Component-heavy, we need minimal custom design
  • Maintenance: 9/10 - Very stable
  • Verdict: Too much CSS for what we need

PicoCSS/Water.css (Considered)

  • Simplicity: 9/10 - Classless CSS, just include and go
  • Fitness: 7/10 - Good starting point but may not match design vision
  • Maintenance: 8/10 - Maintained, simple
  • Verdict: Close consideration, but custom CSS gives full control

Standards Compliance

  • Semantic HTML5 elements
  • Valid HTML (W3C validator)
  • Accessible forms and navigation
  • Proper heading hierarchy
  • ARIA labels where needed
  • Mobile-responsive (viewport meta tag)
  • Progressive enhancement (works without JS)

References