Astro site evolving toward Macari: mostly static public blog and pages, plus an SSR command centre behind auth. See docs/spec.md and docs/deliverables-tracker.md.
Stack highlights: Astro 6, Starlight (/docs), TypeScript, Tailwind 3 (via @astrojs/tailwind; package.json overrides align its astro peer with the app until the integration declares Astro 6), MDX, content collections, RSS, sitemap, @astrojs/node standalone server, filesystem sessions, SQLite (better-sqlite3), bcrypt password hashes.
Requirements: Node.js 20+ (22 recommended).
npm install
cp .env.example .envSet in .env at least PUBLIC_SITE_URL. Use http://localhost:4321 for local dev (see .env.example). Production builds still enforce same-origin checks on form POSTs, so the public URL you deploy under should match PUBLIC_SITE_URL (scheme, host, port).
For the command centre, set bootstrap credentials so the first (empty) database creates an admin user:
MACARI_BOOTSTRAP_USERNAME=admin
MACARI_BOOTSTRAP_PASSWORD=your-secure-passwordOptional: MACARI_DB_PATH (defaults to ./data/macari.db under the project).
npm run devThe dev script sets ASTRO_DEV_RELAX_ORIGIN=1 so sign-in forms are not blocked by Astro’s same-origin check when PUBLIC_SITE_URL and the browser URL differ slightly (e.g. localhost vs 127.0.0.1). Production builds keep strict checks.
Open http://localhost:4321.
Bootstrap reads MACARI_BOOTSTRAP_* from your real .env file via dotenv and runtime env lookup (Vite was not reliably exposing those vars to SQLite code in dev). Ensure .env contains MACARI_BOOTSTRAP_USERNAME and MACARI_BOOTSTRAP_PASSWORD, then restart pnpm dev / npm run dev.
If you reset the database, delete SQLite sidecar files too (WAL mode): data/macari.db, data/macari.db-wal, and data/macari.db-shm if present.
pnpm v10+ blocks dependency install scripts unless you allow them. This repo lists better-sqlite3, sharp, and esbuild in pnpm-workspace.yaml (onlyBuiltDependencies).
After cloning or if you see “Could not locate the bindings file”, run a clean install:
rm -rf node_modules
pnpm installIf it still fails, run pnpm rebuild better-sqlite3 (needs a C++ toolchain). As a fallback, npm install also works.
- With bootstrap vars set, run
npm run dev. - Open http://localhost:4321/command — you should be redirected to
/auth/sign-in. - Sign in with the bootstrap username and password — you should land on the command centre and can Sign out.
Public header/footer do not link to /command (see product spec).
| Command | Description |
|---|---|
npm run dev |
Dev server with hot reload |
npm run build |
astro check + production build (dist/client + dist/server) |
npm run preview |
Preview after build |
npm start |
Run Node standalone: node ./dist/server/entry.mjs (set HOST / PORT if needed) |
- Starlight reference: public docs live at
/docs(start at/docs/guides/for quick start, configuration, editorial features, and copy-paste AI prompts). - Posts:
src/content/posts/as.mdor.mdx. draft: trueomits the entry from the production build (no page, no RSS).unlisted: true(non-draft) keeps a shareable URL but omits the entry from the blog/notes indexes, RSS,/search,/tags, and the sitemap; the page is markednoindexfor crawlers.- Writing kind: posts support
writingKind: article | essay | journal(defaultarticle); notes supportwritingKind: note | snippet | log(defaultnote). Shown in cards, detail headers, note index, tag archives, and search. - Hero images:
src/assets/posts/(see sample posts). - Short notes:
src/content/notes/as.mdor.mdx(published at/notesand/notes/{slug}; samedraft/unlistedrules). Optionaltags:feed/tagsand per-tag archives with posts. - Wikilinks in Markdown and MDX prose:
[[note-or-post-slug]]or[[slug|Display text]]resolves to/notes/...or/blog/...when a matching file exists undersrc/content/notesorsrc/content/posts. Unresolved slugs render as a dashed “missing” span. Code blocks are left unchanged. - Backlinks: note and blog post detail pages include a Linked from section listing other published notes/posts whose bodies contain a wikilink that resolves to that page (same scope as rendered wikilinks: fenced and inline code are excluded).
- Public search:
/searchloads/search-index.json(build-time index) and filters client-side by title, tags, description, and body text (all words must match). - Site metadata:
src/lib/site.ts. - Motion: with
prefers-reduced-motion: reduce, decorative CSS transitions/animations are collapsed site-wide; the blog reading-progress bar still tracks scroll without animating the width.
Build with your real site URL so feeds and metadata resolve correctly:
docker build --build-arg PUBLIC_SITE_URL=https://your-domain.com -t macari .
docker run --rm \
-e MACARI_BOOTSTRAP_USERNAME=admin \
-e MACARI_BOOTSTRAP_PASSWORD='use-a-long-secret' \
-p 4321:4321 \
-v macari-data:/app/data \
-v macari-sessions:/app/.astro \
macariThe image runs the SSR entrypoint (node ./dist/server/entry.mjs). The server binds HOST (default 0.0.0.0) and PORT (default 4321); platforms such as Coolify usually set PORT—no code changes required.
Persist these paths on a volume so SQLite and sign-in sessions survive container restarts:
| Path | Purpose |
|---|---|
/app/data |
SQLite database (MACARI_DB_PATH default) |
/app/.astro |
Filesystem session store (Astro @astrojs/node) |
The Dockerfile declares both as **VOLUME**s and includes a HEALTHCHECK that requests / using the runtime PORT.
- Create the service from this repo’s Dockerfile (repository build).
- Set build argument
PUBLIC_SITE_URLto your public URL (scheme + host, no trailing path). - Set runtime env:
MACARI_BOOTSTRAP_USERNAME,MACARI_BOOTSTRAP_PASSWORD, and optionallyMACARI_DB_PATH(default/app/data/macari.dbunder the mounted volume). - Attach persistent storage mapped to
/app/dataand/app/.astro(two mounts or one parent volume—both directories must remain writable by the container user). - Ensure the proxy forwards
X-Forwarded-Proto/Hostcorrectly so Astro’s origin checks and redirects matchPUBLIC_SITE_URL.
- Install:
npm install - Build:
npm run build - Start:
npm start
Set PUBLIC_SITE_URL at build time. Set MACARI_BOOTSTRAP_* or provision users separately for production.
src/
components/
content.config.ts
content/posts/
data/
layouts/
lib/
auth/ # password helpers
db.ts # SQLite + schema + bootstrap user
middleware.ts # gates /command/**
pages/
api/auth/ # login, logout
auth/
blog/
command/ # private shell (SSR)
styles/
public/
docs/ # product spec, tracker, architecture notes
Branching, PR expectations, lint/format, and CI are documented in CONTRIBUTING.md.
MIT — use freely for your own site.