kammer/HANDOFF.md
Christopher Mühl ba68fb456a test: E2E test suite + handoff documentation
50 Playwright E2E tests across 13 spec files covering all routes and
user flows (items CRUD, check-out/in, locations, labels, scanning,
search/filter). Uses vitest as runner with playwright-core for browser
automation (bun-compatible alternative to @playwright/test).

Includes Gherkin .feature files as living documentation, test support
infrastructure (IDB seeding, item factories, assertion helpers, layout
measurement), and HANDOFF.md covering project state, deployment, and
open design decisions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 20:53:08 +01:00

7.1 KiB

SolidHaus — Project Handoff

What This Is

Local-first household inventory app. Scan barcodes, track where things are, check items in/out, generate QR label sheets. Runs as a web app (SPA) or native mobile app via Capacitor.

Tech Stack

  • Framework: SvelteKit 2, Svelte 5 (runes), TypeScript
  • Styling: Tailwind CSS 4 (dark slate theme)
  • Data: IndexedDB via idb (local-first, no server required)
  • Runtime: Bun (no Node.js — bun is the only runtime used)
  • Build: Vite 7, @sveltejs/adapter-static (SPA mode, outputs to build/)
  • Testing: Vitest 4 (unit) + Vitest + playwright-core (E2E)
  • Future: Automerge (multi-device sync), Solid Protocol (linked data), Capacitor (native mobile)

Current State (Feb 2026)

What works

  • All routes functional: dashboard, items list, item detail, new item, scan, locations, labels, settings
  • Item CRUD with full field set (name, category, type, barcode, location, custody state, quantity tracking)
  • Check-out / check-in flow with reasons (in-use, lent, in-transit, in-repair, temporary)
  • Location tree with expand/collapse, item counts per location
  • QR label sheet PDF generation (A4, 5x10 grid) with batch pre-generation
  • Barcode scanning (Capacitor ML Kit on native, Barcode Detection API on web)
  • Search and filter (by name, category, type, custody state)
  • Confidence decay (confirmed → likely → assumed → unknown based on last sighting age)
  • Default German house locations seeded on first run

Test coverage

  • 174 unit testsbun run test
  • 50 E2E tests across 13 spec files — bun run test:e2e
  • Buildbun run build (outputs static SPA to build/)

What's not done yet

  • Capacitor native platforms: Config exists, deps installed, but android/ and ios/ dirs not created. Run npx cap add android && npx cap sync when ready.
  • Automerge sync: Deps installed, not wired up. Intended for multi-device sync without a central server.
  • Solid Protocol: Deps installed, not wired up. Intended for linked data / decentralized identity.
  • Photo support: Schema exists (photos IDB store), no UI for capture/display yet.
  • Sighting history: Schema exists (sightings IDB store), recorded on check-in/out but no history view UI.

Project Structure

src/
  routes/
    +layout.svelte          # App shell: loading state, bottom nav, inventory init
    +page.svelte            # Dashboard: stats, checked-out items, low stock, recent
    items/
      +page.svelte          # Item list with search/filter/sort
      new/+page.svelte      # New item form
      [id]/+page.svelte     # Item detail with check-out/in, edit, delete
    scan/+page.svelte       # Barcode scanner
    locations/+page.svelte  # Location tree + items at location
    labels/+page.svelte     # Batch ID generation + PDF label sheets
    settings/+page.svelte   # DB stats, about
  lib/
    components/             # Svelte components (ItemCard, ItemForm, LocationTree, etc.)
    data/                   # IndexedDB CRUD (db.ts, items.ts, locations.ts, sightings.ts, labels.ts)
    stores/                 # Svelte 5 rune stores (inventory.svelte.ts)
    scanning/               # Barcode detector + ID parser
    printing/               # Label sheet PDF generation
    utils/                  # ID generation, confidence decay
    types.ts                # All TypeScript types

e2e/
  features/                 # Gherkin .feature files (living documentation, not executable)
    pages/                  # One per route (8 files)
    flows/                  # One per user journey (5 files)
  specs/                    # Executable vitest + playwright-core tests
    pages/                  # Page-level tests (8 files)
    flows/                  # Flow-level tests (5 files)
  steps/                    # Step definitions (leftover from playwright-bdd attempt, unused)
  support/
    browser.ts              # Chromium lifecycle for vitest
    seed.ts                 # IDB seeding via page.evaluate()
    item-factory.ts         # Test data builders
    expect.ts               # Playwright locator assertions for vitest
    layout.ts               # DOM measurement helpers (touch targets, spacing, viewport)
  vitest.config.ts          # E2E-specific vitest config
  playwright.config.ts      # Shared Playwright settings (viewport, baseURL, etc.)

Commands

bun install               # install deps
bun run dev               # dev server at localhost:5173
bun run build             # production build → build/
bun run preview           # serve production build at localhost:4173
bun run test              # 174 unit tests
bun run test:e2e          # 50 E2E tests (needs build + preview running, or run build first)
bun run check             # svelte-check type checking

Deployment

The app is a static SPA. bun run build outputs to build/. Serve it with any static file server that supports SPA fallback (all routes → index.html).

Example with Caddy:

:8080 {
    root * /srv/solidhaus
    try_files {path} /index.html
    file_server
}

Example with nginx:

server {
    listen 8080;
    root /srv/solidhaus;
    location / {
        try_files $uri $uri/ /index.html;
    }
}

No backend required — all data lives in the browser's IndexedDB.

Design Decisions Under Discussion

These are captured but not yet implemented:

  • Item name optional: UID (pre-generated 7-char nanoid) is the only required field. Need at least one of name, description, or image.
  • Item types rework: Current itemType enum mixes behavior (consumable, perishable) with category (clothing, document). Plan to split into behavioral traits (has quantity, has expiry, is container) + freeform categories.
  • Acquisition model: Replace purchaseDate with acquisition events (purchased, gifted, loaned, rented, found, inherited) with date.
  • Container nesting: A fridge is both an item and a container. Items can be "contained in" other items, separate from location tracking.

See CLAUDE.md for full implementation guide and data schemas.

Known Quirks

  • Bun, not Node: The project uses bun exclusively. Playwright's test runner (@playwright/test) doesn't work with bun (worker thread incompatibility), so E2E tests use vitest as the runner with playwright-core for browser automation.
  • E2E needs a running server: The E2E tests connect to localhost:4173. Run bun run build && bun run preview in a separate terminal before running bun run test:e2e, or the webServer in the vitest config handles it.
  • Gherkin features are documentation only: The .feature files describe behavior in plain English but aren't wired to the test runner (playwright-bdd was abandoned due to bun compat). The .spec.ts files are the executable tests, each referencing their .feature file via @see JSDoc.
  • Step files unused: e2e/steps/ contains step definition files from the playwright-bdd approach. They're documentation artifacts, not executed.
  • Location tree interaction: Clicking a location name selects it (shows items). To expand/collapse, click the arrow toggle button (aria-label="Expand"/"Collapse"), not the name.