Skip to content

Development

Kristian-Buriasco edited this page Jul 26, 2026 · 3 revisions

Development

For contributors working on the Albm codebase.

Setup

npm ci
cp .env.example .env      # set SESSION_SECRET
npm run dev               # http://localhost:3200

On first run with no ADMIN_PASSWORD_HASH, a temporary admin password is printed to the console — use it at /admin/login.

See also CONTRIBUTING.md.

Checks (before a PR)

npm run typecheck
npm run lint
npm run build

CI runs typecheck, lint, build, and Playwright e2e on PRs.

End-to-end tests

npm run test:e2e:install   # once
npm run test:e2e           # Playwright; throwaway data dir

Database & migrations

  • SQLite via Drizzle ORM. Schema lives in src/db/schema.ts.

  • Migrations in this repo are hand-written, not generated (drizzle-kit generate doesn't produce a usable migration here). After changing the schema:

    1. Write the raw .sql file directly under drizzle/ (next sequential number).

    2. Append a matching entry to drizzle/meta/_journal.json.

    3. Test the full migration chain against a scratch copy of a dev database before committing:

      cp data/gallery.db /tmp/scratch.db
      node -e "
        const Database = require('better-sqlite3');
        const { drizzle } = require('drizzle-orm/better-sqlite3');
        const { migrate } = require('drizzle-orm/better-sqlite3/migrator');
        migrate(drizzle(new Database('/tmp/scratch.db')), { migrationsFolder: './drizzle' });
        console.log('OK');
      "

    Commit both the new .sql file and the updated journal. Migrations apply automatically at boot; an existing database is backed up to DATA_DIR/backups/ first. A failed migration aborts startup rather than serving a half-migrated DB.

Conventions

  • TypeScript, App Router, server components by default; 'use client' only where needed.
  • Keep the security bar: server-side length caps + rate limiting on public writes, existence-404 (not 403) for unpublished galleries, never render user input as HTML, no new outbound network calls.
  • Self-contained only — no external CDN/font/script requests from pages.
  • docs/openapi.yaml (mirrored to public/openapi.yaml) is hand-maintained, like the changelog. If a route's request/response shape changes, update its spec entry in the same commit.

Stack

Next.js 15 (App Router, standalone) · SQLite + Drizzle + better-sqlite3 · sharp · Tailwind · iron-session · @simplewebauthn · Playwright.

Optional: tesseract.js, @vladmandic/face-api + WASM TensorFlow.

Required native modules: sharp, better-sqlite3.

Scope

Albm is a focused single-admin app. Please open an issue to discuss larger features (multi-tenant, plugins, etc.) before building them.

Clone this wiki locally