Reviewed-on: #1
Armandine
Pre-rendered Svelte gallery site served by Nginx. Build outputs to build/; image is built and pushed via Woodpecker CI/CD from this repo.
Stack
- Site: Svelte 5 + SvelteKit (TypeScript),
@sveltejs/adapter-static. Gallery is rendered at build time fromsrc/lib/media.ts; lightbox and theme toggle run from a preloaded client script (static/assets/js/script.js). - CSS: PostCSS (nesting + level 2), component-scoped styles; critical CSS inlined at build time with Beasties.
- Runtime:
nginx:alpine(seeDockerfile) serves the contents ofbuild/. - Registry: Gitea at
git.mifi.dev→ imagegit.mifi.dev/mifi-holdings/armandine. - Deploy: Portainer on Linode; stack uses this image (no volume for site content).
Local development
# Install dependencies
pnpm install
# Dev server with hot reload (http://localhost:5173)
pnpm dev
# Type-check (Svelte + TypeScript)
pnpm check
# Lint JS/TS and CSS
pnpm lint
# Check formatting (CI uses this)
pnpm format:check
# Fix formatting
pnpm format
# Build for production (Vite + critical CSS step)
pnpm build
# Preview the built site (http://localhost:4173)
pnpm preview
Dev container
Open the repo in a dev container (VS Code/Cursor: Dev Containers: Reopen in Container) for a consistent environment:
- Node 22 (matches CI), with
pnpm installrun after create - Docker (outside of Docker) – uses the host Docker socket so you can run
pnpm buildand test the image inside the dev container - ESLint, Prettier, Stylelint, Svelte extensions plus format-on-save and fix-on-save
Ports:
- 5173 – SvelteKit dev server (
pnpm dev) - 4173 – Preview built site (
pnpm preview) - 80 – Nginx when running the Docker container locally
Manual build and push
-
Log in to the Gitea container registry:
docker login git.mifi.devUse your Gitea username and a token with package permissions.
-
Build the site and Docker image:
pnpm build pnpm docker:buildpnpm buildruns Vite build then Beasties to inline critical CSS intobuild/. The Dockerfile copiesbuild/into the image. -
Push to the registry:
pnpm docker:pushThen on the server, redeploy the stack (e.g. Portainer “Pull and redeploy” or your webhook).
Woodpecker CI/CD
Three pipelines (see .woodpecker/):
| Pipeline | When | What |
|---|---|---|
| ci | Every push to main, every PR |
Lint (ESLint + Stylelint), Prettier check, Svelte/TypeScript check |
| build | Push/tag/manual on main only (after ci) |
Build site to build/, build Docker image, push to git.mifi.dev/mifi-holdings/armandine |
| deploy | After build | Trigger Portainer stack redeploy via webhook |
Order: ci → build → deploy.
Secrets (Woodpecker)
Configure in the repo’s Woodpecker secrets:
gitea_registry_username– Gitea user for registry logingitea_package_token– Gitea token with package read/writeportainer_webhook_url– Portainer stack webhook URL for redeploy- Mattermost/Discord webhook secrets (see
.woodpecker/*.yamlfor notifications)
Server / Portainer
- Stack is defined by
docker-compose.ymlin this repo. - Compose uses the image from the registry (
git.mifi.dev/mifi-holdings/armandine:latest); no volume for site content (it’s inside the image). - Ensure the server can pull from
git.mifi.dev. After a push, either let the deploy pipeline trigger the Portainer webhook or manually “Pull and redeploy” the stack.
Project layout
├── src/
│ ├── app.html # SvelteKit HTML template
│ ├── app.css # Global CSS (variables, body, lightbox)
│ ├── app.d.ts # App types
│ ├── routes/
│ │ ├── +layout.svelte
│ │ ├── +layout.ts # prerender = true
│ │ ├── +page.svelte # Main page (header, gallery, lightbox markup)
│ │ └── +page.ts # Loads media data for build-time gallery
│ └── lib/
│ ├── media.ts # Typed gallery media list (used at build time)
│ └── components/
│ ├── GalleryFigure.svelte
│ └── SiteHeader.svelte
├── static/ # Copied as-is to build root
│ ├── robots.txt
│ └── assets/
│ ├── js/ # script.js (lightbox, theme), ga-init.js
│ ├── media/ # desktop/, tablet/, mobile/, thumbnail/, videos/
│ └── favicon*.png, favicon.ico
├── scripts/
│ └── critical-css.js # Beasties post-step on build/
├── build/ # Output of pnpm build (Vite + Beasties)
├── Dockerfile # nginx:alpine + COPY build/
├── docker-compose.yml
├── package.json # Scripts: dev, build, preview, check, lint, format
├── .devcontainer/
├── .woodpecker/
│ ├── ci.yaml
│ ├── build.yaml
│ └── deploy.yaml
├── README.md
└── AGENTS.md # Guidance for LLM agents
Version
package.json version: 1.0.0 (bump when you want to track releases).