# narlblog 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) frontend/ Astro + React, SSRs pages and proxies /api/* data/ Runtime data — posts, uploads, config.json (host volume) ``` ## Quick start 1. **Environment Setup**: ```sh cp .env.example .env # Generate a strong admin token: echo "ADMIN_TOKEN=$(openssl rand -hex 32)" >> .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 ``` 3. **Permissions**: Ensure the `data/` host directory is owned by UID 1000: ```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. | | `PUBLIC_API_URL` | no | `http://backend:3000` | Backend URL the Astro proxy hits server-to-server. | ## Authoring Posts are stored as markdown files in `data/posts/.md` with YAML frontmatter. ```markdown --- date: 2026-05-09 title: My First Post summary: Optional short caption or excerpt. tags: - general - 2026 draft: false --- # Content Title Post content goes here. In `atelier` mode, include at least one image: ![Alt text](/uploads/image.jpg "Caption") ``` - `draft: true` hides a post from the public index. - Access the web editor at `/admin/editor` after logging in at `/admin/login`. ## Uploads Supported: jpg, jpeg, png, webp, gif, avif, pdf, txt, md, mp3, wav, ogg, mp4, webm, mov. Max size: 50 MB. ## Backups The `data/` directory contains all state (posts, uploads, configuration). Backup this folder regularly. ## Stack - **Backend**: Rust 2024, Axum 0.8 - **Frontend**: Astro 6, React 19, Tailwind 4 - **Editor**: CodeMirror 6 with Vim mode