updated readme + just
CI / frontend (push) Failing after 0s
CI / backend (push) Failing after 1s

This commit is contained in:
2026-05-21 04:29:43 +02:00
parent 37f88f5ad1
commit 0da5b24dc3
5 changed files with 177 additions and 128 deletions
+53 -64
View File
@@ -1,6 +1,6 @@
# Ela's Atelier
# narlblog
A single-curator art portfolio. Rust/Axum API backed by markdown files on disk; Astro/React frontend with a parchment "Salon Hang" aesthetic. Each entry is a markdown post that must contain at least one image; the first image becomes the cover plate in the catalogue.
A minimalist, filesystem-backed portfolio and blog engine. Rust/Axum API for the backend and Astro/React for the frontend.
```
backend/ Rust + Axum API (filesystem-backed)
@@ -10,102 +10,91 @@ data/ Runtime data — posts, uploads, config.json (host volume)
## Quick start
```sh
cp .env.example .env
# Generate a strong admin token:
echo "ADMIN_TOKEN=$(openssl rand -hex 32)" >> .env
1. **Environment Setup**:
```sh
cp .env.example .env
# Generate a strong admin token:
echo "ADMIN_TOKEN=$(openssl rand -hex 32)" >> .env
```
docker compose up --build
# → http://localhost:4321
# → log in at /admin/login with the token from .env
```
2. **Using Just**:
This project uses `just` to simplify common tasks.
```sh
just setup # Install backend and frontend dependencies
just dev # Run both backend and frontend locally in parallel
just docker # Start the full stack using Docker Compose
```
Make sure the `data/` host directory is owned by UID 1000 (the backend container's app user):
3. **Permissions**:
Ensure the `data/` host directory is owned by UID 1000:
```sh
sudo chown -R 1000:1000 data/
```
```sh
sudo chown -R 1000:1000 data/
```
## Site Modes
The engine supports two distinct modes via the `SITE_MODE` environment variable:
- **`atelier` (Default)**: Optimized for art portfolios. Requires at least one image per post; the first image serves as the cover plate in the gallery view.
- **`blog`**: A traditional text-focused blog layout. Images are optional, and the index prioritizes titles and excerpts.
## Commands
| Command | Description |
| -------------- | ------------------------------------------------ |
| `just setup` | Installs dependencies for backend and frontend. |
| `just build` | Builds production binaries and assets. |
| `just dev` | Runs both services locally for development. |
| `just docker` | Starts the stack using `docker compose`. |
| `just test` | Runs the test suite for both services. |
## Environment
| Variable | Required | Default | Notes |
| ----------------- | -------- | --------------------- | --------------------------------------------------------------------------- |
| `ADMIN_TOKEN` | yes | — | Long random string. Stored as an HttpOnly cookie after login. |
| `SITE_MODE` | no | `atelier` | `atelier` (art portfolio) or `blog` (traditional blog). |
| `PORT` | no | `3000` | Backend port. |
| `DATA_DIR` | no | `/app/data` | Where posts/uploads/config live. |
| `COOKIE_SECURE` | no | `true` | Set `false` only for local HTTP development. |
| `FRONTEND_ORIGIN` | no | _empty_ | Set to your frontend's URL only if you expose the backend directly. |
| `RUST_LOG` | no | `info` | tracing-subscriber filter. |
| `PUBLIC_API_URL` | no | `http://backend:3000` | Backend URL the Astro proxy hits server-to-server. |
## Local development
## Authoring
Backend:
```sh
cd backend
ADMIN_TOKEN=devtoken COOKIE_SECURE=false DATA_DIR=../data cargo run
```
Frontend (separate terminal, Node ≥ 22.12):
```sh
cd frontend
npm install
npm run dev
# → http://localhost:4321 (proxies to PUBLIC_API_URL, default http://backend:3000)
```
For a fully local stack, set `PUBLIC_API_URL=http://localhost:3000` in `frontend/.env`.
## Authoring a work
Each work is a markdown file at `data/posts/<slug>.md` with YAML frontmatter. Every work **must** contain at least one markdown image — the first image becomes the cover plate on the gallery index. Image alt text becomes the figure caption on the work page.
Posts are stored as markdown files in `data/posts/<slug>.md` with YAML frontmatter.
```markdown
---
date: 2026-05-09
summary: Optional short caption shown beneath the plate on the index.
title: My First Post
summary: Optional short caption or excerpt.
tags:
- oil
- general
- 2026
draft: false
---
# Untitled (charcoal on paper)
# Content Title
![A view of the cliff at dawn](/uploads/cliff-dawn.jpg "Plate I — graphite, A3")
Post content goes here. In `atelier` mode, include at least one image:
Notes on the piece: materials, references, what worked, what didn't.
![Detail of the foreground](/uploads/cliff-detail.jpg "Plate II — detail")
![Alt text](/uploads/image.jpg "Caption")
```
- `draft: true` hides a work from the public catalogue and 404s for non-curators.
- Works are sorted by `date` descending on the index.
- The web editor at `/admin/editor` writes the same format and updates atomically.
- `draft: true` hides a post from the public index.
- Access the web editor at `/admin/editor` after logging in at `/admin/login`.
## Uploads
Allowlisted extensions: jpg, jpeg, png, webp, gif, avif, pdf, txt, md, mp3, wav, ogg, mp4, webm, mov. Magic bytes are checked against the extension. SVG and HTML are intentionally rejected — `/uploads/*` is served as-is, so any active content there would be XSS.
Max upload size: 50 MB.
## Theme
The default theme is **Salon** — aged parchment, oxblood ink, Fraunces/EB Garamond/Caveat typography. A **Salon Noir** variant (black gallery wall) is available via the theme switcher in the header.
Influences: Friedrich, Goya, Kahlo, Tillmans, Basquiat, Sherman, Matisse, Dix, Abramović.
Supported: jpg, jpeg, png, webp, gif, avif, pdf, txt, md, mp3, wav, ogg, mp4, webm, mov.
Max size: 50 MB.
## Backups
The deployed `data/` directory is the entire gallery. Back it up with whatever you trust — `rsync`, restic, borg, a sidecar container; nothing fancy is built in.
```sh
rsync -av data/ backup-host:/path/to/gallery-data/
```
The `data/` directory contains all state (posts, uploads, configuration). Backup this folder regularly.
## Stack
- **Backend**: Rust 2024 edition (requires 1.85+), axum 0.8, serde_yaml frontmatter, subtle constant-time auth, infer for upload sniffing
- **Frontend**: Astro 6, React 19, Tailwind 4, marked + marked-katex-extension + marked-highlight + DOMPurify
- **Editor**: CodeMirror 6 with vim mode and asset autocomplete
- **Backend**: Rust 2024, Axum 0.8
- **Frontend**: Astro 6, React 19, Tailwind 4
- **Editor**: CodeMirror 6 with Vim mode