Skip to content

Developer Guide

This guide covers setting up a local development environment, working on the codebase, running tests, and cutting releases. For contribution guidelines, issue etiquette, and the code of conduct, see CONTRIBUTING.md.


Prerequisites

  • Node.js 24 or later — install from nodejs.org
  • npm (bundled with Node.js)
  • Git

Setup

git clone https://gitlab.com/cozybadgerde/applications/plate.git
cd plate
npm install

Apply the commit message template so your commits follow the project's Conventional Commits format:

git config commit.template .gitmessage

Development workflow

Start the development server with hot reload:

npm run dev

Plate starts on http://localhost:3000 and reloads on every source change. It requires a running Snackbox instance — point SNACKBOX_API_URL at it:

SNACKBOX_API_URL=http://localhost:8080 npm run dev

For theme development with a live Snackbox fixture (no real Snackbox needed):

npm run theme:dev -- src/themes/picnic   # or any other theme path

Testing

npm test                    # all tests (unit + integration)
npm run test:unit           # unit tests only
npm run test:integration    # integration tests only
npm run test:watch          # watch mode
npm run test:coverage       # coverage report → build/coverage/

Unit tests are mandatory. Every new function or class must ship with at least one unit test. Bug fixes must include a regression test that fails before the fix and passes after.

Unit tests live next to the source in src/lib/__tests__/. Integration tests live in test/.


Checks

Run all checks before every commit:

npm run check   # lint + spellcheck + typecheck + all tests

Or individually:

npm run lint        # ESLint
npm run spellcheck  # cspell (en-US)
npm run typecheck   # TypeScript (no emit)

All four must pass before opening a merge request.


Project structure

src/
├── config.ts           env var loader + validateConfig()
├── server.ts           Express app, ThemeManager, bootstrap, error handlers
├── types/              TypeScript interfaces (snackbox, theme, context)
├── lib/                core logic — every file has a corresponding test
├── middleware/         Express middleware (globalContext, requestMetrics)
├── routes/             one file per route group (home, posts, pages, tags, health)
├── fixture/            built-in Snackbox fixture server (ships in dist/)
│   ├── data.ts         shared edge-case dataset — single source of truth
│   └── server.ts       startFixture() / stopFixture() — built-in http only
├── cli/                npx plate CLI entry point
│   └── index.ts        theme:init, theme:validate, theme:check, theme:dev
└── themes/picnic/      built-in fallback theme — reference implementation

test/                   integration tests
scripts/                dev tooling (benchmark, sync-version, theme-validator)
contracts/              theme manifest JSON Schema + contract documentation
deployments/            Docker Compose, systemd unit, Caddy config

For a deeper look at how the pieces fit together, see docs/ARCHITECTURE.md.


Commit messages

This project uses Conventional Commits. The .gitmessage template is the authoritative reference. Quick summary:

<type>(<scope>): <subject>

Body — explain the why, not the what. Bullet points are fine.

- resolves: #42

Types: feat, fix, docs, test, refactor, perf, chore, ci

Scope: optional — the affected area (e.g. theme, cache, renderer).


Releasing

  1. Bump the version in package.json.

  2. Sync the version to the Picnic manifest and theme schema:

    bash npm run version

  3. Regenerate the changelog:

    bash npm run changelog

  4. Run all checks:

    bash npm run check

  5. Commit and tag:

    bash git add package.json CHANGELOG.md src/themes/picnic/manifest.json contracts/theme-manifest.schema.json git commit -m "chore(release): v<version>" git tag v<version> git push --follow-tags

The CI pipeline builds and publishes the container image on tag push.


Documentation

The docs site is built with MkDocs Material. Source files live in docs/, configuration in mkdocs.yml. The CI pipeline publishes the site to GitLab Pages on every push to trunk.

The build runs with --strict, which treats warnings as errors. Broken internal links, missing nav entries, and invalid tags all fail the build.

Render locally

Docker (no install required):

docker run --rm -it -p 8000:8000 -v "$PWD":/docs \
  squidfunk/mkdocs-material:9.5.47 serve --dev-addr=0.0.0.0:8000

The site is then available at http://localhost:8000 with live reload on save.

Local install:

pip install mkdocs-material mkdocs-minify-plugin
mkdocs serve

Build and check

mkdocs build --strict
# or via Docker:
docker run --rm -v "$PWD":/docs squidfunk/mkdocs-material:9.5.47 build --strict

A clean build with no warnings means the CI Pages job will pass.


Theme development

To develop or extend the built-in Picnic theme, or to build an external theme, see docs/THEME-DEVELOPER.md.

To validate a theme against the contract:

npm run theme:check -- <path-to-theme>