معماری
Overview
content/ → Gleam SSG → static HTML + feeds + search JSON → CDN
└──→ Lustre ES-module closure ┘
browser islands → HTTP → Wisp handlers → Pog → PostgreSQL
live component → WS → Mist bridge → Lustre on BEAM
└── OTP supervision
Three packages share types through shared/: komeil_site, komeil_server, and komeil_shared.
Static generation pipeline
- Walk
content/enandcontent/fafor posts and pages. - Parse TOML frontmatter (
+++fences). - Render Markdown via Maud/Mork; Djot via Jot.
- Run checks: translation pairing, draft leak, internal links, UI string completeness.
- Render every route in the route table to
dist/<path>/index.html. - Emit Atom + RSS feeds,
sitemap.xml,robots.txt, and per-language search indices. - Copy
public/assets into the output tree.
The browser target compiles four independent Lustre islands for theme, search, clipboard, and contact. A dependency-closure step copies only modules reachable from the browser entry point; no npm application or client router is involved.
Content model
Every file carries: title, description, date, updated, language, slug, translation_key, tags, draft, canonical, excerpt.
translation_key connects English and Persian versions of the same logical page. The build fails if a key is missing a language or duplicated within one language.
Projects are structured JSON in content/projects/projects.json — data, not prose.
Admin editing model
Decap CMS lives at /admin. It edits files in content/ and commits via Git. No content database. Schema matches frontmatter requirements; incompatible drafts are caught by the build.
Backend model
Wisp handlers run behind Mist with explicit request/response contracts and PostgreSQL access through Pog. A RestForOne supervisor owns the database pool, rate limiter, named Lustre server component, and HTTP/WebSocket server. Migrations run before the tree starts. Admin routes remain disabled unless ADMIN_TOKEN is set.
The panel below is not a simulated widget: its timer, client count, and ping counter live inside the supervised BEAM process. Mist carries DOM events to the server and compact Lustre patches back to the browser.
Deployment model
- Static output: Vercel, Cloudflare Pages, or any CDN serving only
site/dist/. - API: Docker image on Fly.io, a VPS, or similar — PostgreSQL alongside or managed.
- DNS + TLS + caching: Cloudflare.
Build and validation pipeline
CI runs: gleam format, tests, Erlang and JavaScript target compilation, content validation, translation validation, link checks, static build, server build, nix flake check, and Docker build verification.