231 lines
11 KiB
Markdown
231 lines
11 KiB
Markdown
# River Rooks | Technical Publication & Systems Architecture Blog
|
|
|
|
> Developer-centric, high-signal, low-noise personal technical publication and systems architecture blog.
|
|
|
|
Inspired by native terminal environments, modal text editors (Zed, Ghostty), and tiling window managers, this site prioritizes raw performance, keyboard navigability, information density, and structured craftsmanship over generic marketing aesthetics.
|
|
|
|
---
|
|
|
|
## 1. Quickstart: Production Server Deployment
|
|
|
|
The production deployment uses a **decoupled container architecture**. The server does not need Node.js, git, or build dependencies—it only pulls the prebuilt engine from the registry and mounts a local folder containing your Markdown posts.
|
|
|
|
### 1.1 Server Directory Structure (`~/docker/blog`)
|
|
```text
|
|
~/docker/blog/
|
|
├── .env # Environment variables (SITE_DOMAIN, etc.)
|
|
├── docker-compose.yml # Production container definition
|
|
└── posts/ # Your live Markdown articles (.md)
|
|
```
|
|
|
|
### 1.2 Production `docker-compose.yml`
|
|
```yaml
|
|
services:
|
|
web:
|
|
image: git.riverrooks.dev/venus/river-rooks-blog:latest
|
|
container_name: river_rooks_web
|
|
restart: unless-stopped
|
|
volumes:
|
|
- "./posts:/app/src/posts:ro"
|
|
environment:
|
|
- "SITE_DOMAIN=${SITE_DOMAIN:?Error: SITE_DOMAIN is not set. Please define SITE_DOMAIN in .env}"
|
|
- "SITE_URL=${SITE_URL:-https://${SITE_DOMAIN}}"
|
|
- "PORT=${PORT:-8080}"
|
|
- "WATCH=${WATCH:-false}"
|
|
ports:
|
|
- "${HOST_PORT:-${PORT:-8080}}:${PORT:-8080}"
|
|
networks:
|
|
- backend
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.blog.rule=Host(`riverrooks.dev`) || Host(`www.riverrooks.dev`)"
|
|
- "traefik.http.routers.blog.entrypoints=websecure"
|
|
- "traefik.http.routers.blog.tls.certresolver=basic"
|
|
- "traefik.http.services.blog.loadbalancer.server.port=8080"
|
|
- "traefik.docker.network=backend"
|
|
|
|
networks:
|
|
backend:
|
|
external: true
|
|
```
|
|
|
|
### 1.3 Deployment Commands
|
|
```bash
|
|
# 1. Pull the prebuilt engine from Gitea registry
|
|
docker compose pull
|
|
|
|
# 2. Launch the container
|
|
docker compose up -d
|
|
|
|
# 3. Verify healthcheck status (transitions to healthy in 3-5 seconds)
|
|
docker compose ps
|
|
```
|
|
|
|
---
|
|
|
|
## 2. Local Development & Verification
|
|
|
|
All templates, styles, and engine code are developed in this repository (`~/code/blog`).
|
|
|
|
### 2.1 Native Node.js Workflow
|
|
```bash
|
|
# Install dependencies
|
|
npm install
|
|
|
|
# Run automated test suite (unit tests, filters, server, and docker assertions)
|
|
npm test
|
|
|
|
# Launch Eleventy dev server with hot-reload (binds to http://localhost:8080)
|
|
npm run dev
|
|
|
|
# Compile static assets to _site/
|
|
npm run build
|
|
|
|
# Start the native static server locally
|
|
npm start
|
|
```
|
|
|
|
### 2.2 Local Docker Compose Workflow
|
|
The local `docker-compose.yml` provides sensible defaults (`localhost`, port 8080, and mounts `./src/posts`):
|
|
```bash
|
|
# Build and run the local container stack
|
|
docker compose up -d --build
|
|
|
|
# View container logs (Eleventy compilation + server output)
|
|
docker compose logs -f
|
|
|
|
# Stop and clean up
|
|
docker compose down
|
|
```
|
|
|
|
### 2.3 Development Standards: Strict TDD & Adversarial Verification
|
|
This project enforces a strict test-first development lifecycle and verification standard:
|
|
1. **Tests Written Before Functional Code:** Automated test cases in `test/` must always be written before writing or modifying any functional code, filters, templates, server endpoints, or scripts.
|
|
2. **Mandatory Adversarial Testing:** Standard behavior for any functional change must always include adversarial test cases (boundary values, malformed/null inputs, unauthorized requests, path traversals, corrupt frontmatter, and design spec violations).
|
|
3. **Pre-Presentation Verification Gate:** Every change must be verified by running `npm test`. All test cases must pass before presenting the final output or committing code.
|
|
|
|
---
|
|
|
|
## 3. Push & Update Cycles
|
|
|
|
Because the system separates the **Engine** (templates/code) from the **Content** (markdown notes), updates follow two distinct paths:
|
|
|
|
### 3.1 Publishing or Editing Articles (Content Workflow)
|
|
When you write a new note or edit an existing article:
|
|
|
|
1. **Add or update the Markdown file** in `posts/` (e.g. `posts/my-new-post.md`):
|
|
```yaml
|
|
---
|
|
title: "My Article Title"
|
|
date: 2026-09-14
|
|
tags: ["#systems", "#architecture"]
|
|
excerpt: "A short synopsis of the article."
|
|
hidden: false # (Optional) Set to true to hide from public lists while keeping direct link active
|
|
---
|
|
|
|
# Article Content...
|
|
```
|
|
2. **Recompile the site:**
|
|
```bash
|
|
docker compose restart web
|
|
```
|
|
*Eleventy compiles the mounted markdown in ~150ms and starts serving immediately.*
|
|
|
|
> [!TIP]
|
|
> **Zero-Restart Live Reload:** Set `WATCH=true` in your server's `docker-compose.yml` environment. Eleventy will watch the `posts/` directory in the background. Whenever a note is saved or synced (e.g., from Obsidian), the site automatically updates in memory without running any commands.
|
|
|
|
### 3.2 Updating Blog Templates, CSS, or Features (Engine Workflow)
|
|
When you modify design tokens, Nunjucks templates, server routes, or dependencies:
|
|
|
|
1. **Develop and verify locally:**
|
|
```bash
|
|
npm test
|
|
```
|
|
2. **Build and push the new engine image to the Gitea container registry:**
|
|
```bash
|
|
# Build the engine image
|
|
docker build -t git.riverrooks.dev/venus/river-rooks-blog:latest .
|
|
|
|
# Push to Gitea
|
|
docker push git.riverrooks.dev/venus/river-rooks-blog:latest
|
|
```
|
|
3. **Update the production server:**
|
|
```bash
|
|
docker compose pull
|
|
docker compose up -d
|
|
```
|
|
|
|
---
|
|
|
|
## 4. System Architecture & Structure
|
|
|
|
### 4.1 High-Level Architecture
|
|
```text
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Dev Machine / Workstation │
|
|
│ src/ (templates, CSS, config) + Dockerfile + entrypoint.sh │
|
|
└──────────────────────────────┬──────────────────────────────┘
|
|
│ docker push
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Gitea Container Registry (git.riverrooks.dev) │
|
|
│ image: venus/river-rooks-blog:latest │
|
|
└──────────────────────────────┬──────────────────────────────┘
|
|
│ docker pull
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ Production Server │
|
|
│ │
|
|
│ ~/docker/blog/posts/ ──(volume)──> [ river_rooks_web ] │
|
|
│ (Live Markdown Notes) ├── entrypoint.sh │
|
|
│ ├── 11ty compiles │
|
|
│ Traefik (SSL / Proxy) <──────────── └── server.js (:8080) │
|
|
└─────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
### 4.2 Key Engine Components
|
|
- **`entrypoint.sh`**: Dynamic container entrypoint. Compiles mounted markdown notes with Eleventy on boot, starts optional background file watcher, and spawns `server.js` as PID 1 for clean signal handling.
|
|
- **`Dockerfile`**: Minimal `node:22-alpine` container with pre-installed dependencies, baseline static pre-compilation, and baked-in `HEALTHCHECK` querying `http://127.0.0.1:8080/healthz`.
|
|
- **`server.js`**: Zero-dependency native Node static web server supporting clean directory URLs, MIME caching, security headers, and the `/healthz` telemetry endpoint.
|
|
- **`eleventy.config.js`**: Eleventy 3.x configuration, custom collections (`posts`, `tagList`), markdown-it anchor plugins, and custom date/reading-time filters.
|
|
|
|
### 4.3 Directory Map
|
|
```text
|
|
.
|
|
├── .agents/ # Antigravity agent configurations & rules
|
|
├── sample-designs/ # Design specifications & HTML/CSS prototypes
|
|
├── src/ # Blog engine source
|
|
│ ├── _data/ # Site metadata & navigation
|
|
│ ├── _filters/ # Modular Eleventy filters (date, readingTime, headings)
|
|
│ ├── _includes/
|
|
│ │ ├── layouts/ # Base & post Nunjucks templates
|
|
│ │ └── partials/ # Global bar, hero tile, post cards, code box
|
|
│ ├── assets/
|
|
│ │ └── css/ # Modular CSS (tokens, reset, layout, components)
|
|
│ └── posts/ # Default/fallback markdown posts
|
|
├── test/ # Automated test suite (node:test)
|
|
├── docker-compose.yml # Local development compose file
|
|
├── sample-docker-compose.yml # Production-ready compose template
|
|
├── Dockerfile # Production container image definition
|
|
├── entrypoint.sh # Container startup & compilation entrypoint
|
|
├── server.js # Native Node static HTTP server
|
|
├── eleventy.config.js # Eleventy configuration
|
|
├── package.json # Project scripts & dependencies
|
|
└── README.md # Documentation & runbook
|
|
```
|
|
|
|
---
|
|
|
|
## 5. Strict Design Specification
|
|
|
|
All UI components and stylesheets strictly follow [`sample-designs/design-specification.md`](./sample-designs/design-specification.md):
|
|
|
|
| Rule | Constraint |
|
|
| :--- | :--- |
|
|
| **Color Scheme** | Dark-mode native only. Canvas: `#0d0f12`, Surface: `#121417`, Elevated: `#1c1f26`, Borders: `#2b303b`. |
|
|
| **Accents** | Terminal accents: Cyan (`#00f0ff`), Green (`#00e676`), Amber (`#ffb700`), Red (`#ff5252`). |
|
|
| **Borders & Radius** | Crisp 1px solid borders. Zero to 4px maximum border-radius (sharp corners). |
|
|
| **Strict Anti-Patterns** | **NO** glassmorphism (`backdrop-filter`), **NO** drop shadows or glows, **NO** gradients, **NO** spring animations. |
|
|
| **Typography** | Monospace for UI & code (`IBM Plex Mono`, `JetBrains Mono`); clean sans-serif for body prose (`Inter`). |
|
|
| **Interactivity** | Instant binary hover snaps (no slow fade transitions); high-contrast focus outlines for keyboard navigation. |
|