Local development¶
The frontend development environment runs Next.js on the host and Valkey in a small Docker Compose service. The standard workflow below uses an external Hubuum Server reachable from the host.
For an isolated server with a freshly restored test corpus, run
npm run dev:sandbox -- --pr 411. It starts the dependencies and frontend and
prompts for a corpus-admin password. See the sandbox guide
for tag/SHA/PR selection, keeping and resuming data, and
resetting sandbox user passwords.
This workflow does not require dev:deps or edits to .env.local.
First-time setup¶
Install Node.js 24 LTS and Docker Compose or Podman with a Compose provider, then install the project dependencies:
The project type-checks with TypeScript 7. Next.js still consumes the
TypeScript 6 programmatic API during its build, so package.json installs the
two official side-by-side aliases: @typescript/native provides the tsc
binary, while typescript points to the TypeScript 6 compatibility package.
Keep both aliases until Next.js supports the TypeScript 7 API directly.
Vitest's configuration stays in vitest.config.mjs so Vite's native config
loader treats it as ESM without changing either TypeScript alias.
Edit .env.local and set BACKEND_BASE_URL to the Hubuum Server URL that the
host-side Next.js process can reach:
BACKEND_BASE_URL is not resolved from inside compose.dev.yml. If Hubuum
Server runs in another container, publish its HTTP port to the host and use that
published address. A Compose-only service name such as http://hubuum:8080
will not resolve from npm run dev. A remote HTTPS Hubuum Server URL also works
when it is reachable from the development machine.
Restart Next.js after changing .env.local.
Start¶
Start the Valkey session store and wait for it to become healthy:
The launcher waits for Valkey to answer PING; it does not require Compose's
Docker-specific --wait option. It uses docker when available (including the
Podman Docker interface), otherwise podman. Set
HUBUUM_CONTAINER_RUNTIME=podman to select Podman explicitly, and use the same
setting for npm run dev:deps:down. HUBUUM_VALKEY_PROJECT optionally selects an
isolated Compose project. Writable Valkey directories remain temporary memory
mounts with persistence disabled.
Then start Next.js:
Open http://127.0.0.1:3000. Authenticated use requires both the configured
Hubuum Server and Valkey; /readyz reports whether both dependencies are ready.
Local development and production launchers default to 127.0.0.1:3000 to avoid
differences in IPv4/IPv6 resolution of localhost. Choose
another port or listen address with npm's -- argument separator:
npm run dev -- --port 4000 --listen 127.0.0.1
npm run dev -- --port=4000 --listen='*'
# After npm run build:
npm start -- --port 4000 --listen localhost
--listen '*' binds all IPv4 interfaces; quote the asterisk so the shell does
not expand it into filenames. IPv6 addresses such as ::1 (loopback) or ::
(all IPv6 interfaces) are accepted, with or without brackets. --hostname/-H
remain aliases for --listen, and -p is an alias for --port.
An explicit --port overrides the process environment's PORT. Set PORT
before launching, not in .env.local. Local launchers ignore inherited
HOSTNAME values and use --listen for the bind address. Container images keep
their explicit PORT/HOSTNAME settings. Other Next.js development options,
such as --webpack, are forwarded unchanged. Use --help to see the options.
Sunset, Mountains, Clouds, and Forest are bundled login backgrounds, with Sunset used
on a device that has not selected one yet. Private login
artwork can be placed in the repository's login-backgrounds/ directory.
AVIF, JPEG, PNG, and WebP files are discovered on each login-page request,
remain ignored by Git, and appear under Appearance in the background selector with a Random
choice.
Stop¶
Stop Next.js with Ctrl-C, then remove the development Valkey container and
network:
The development Valkey data is intentionally ephemeral, so stopping it signs out existing local sessions.
Browser quality checks¶
Install the browser used by the end-to-end suite once:
Run the public accessibility, contrast, and responsive-layout checks without backend credentials:
Pixel comparisons run separately in CI so an intentional or accidental visual
change does not hide the functional results. Both CI and baseline updates use
the same digest-pinned Playwright 1.63.0 Noble linux/amd64 image, bundled
Chromium, and the fixed v0.0.0+visual display version. Docker is required to
refresh intentional baselines (Apple-silicon hosts run the image through Docker
emulation):
Review every changed PNG under tests/e2e/__screenshots__/ before committing
it. Do not update baselines with host-installed browsers because their font and
graphics stacks are not the supported baseline environment. The tablet
assertions allow a narrow 1.5% pixel tolerance for stable runner-CPU text
antialiasing; the other viewports retain the stricter 1% tolerance.
Run login, session, logout, keyboard interaction, resource-picker, accessibility, and authenticated screenshot checks against disposable Hubuum Server and Valkey containers:
The command resets the disposable admin password immediately before the test,
keeps it only in the child-process environment, and removes the containers and
volumes afterward. Override the pinned compatibility image with
HUBUUM_AUTH_E2E_BACKEND_IMAGE when testing another server build.
The default test target is released Server v0.0.16. To focus on schemas and
task cancellation:
npm run test:credential-fixtures
npm run test:live-backend
npm run test:e2e:authenticated -- --grep 'schema workspace|task cancellation'
The contract run requires schema evolution, saved diagnostics and HTML reports,
task cancellation, per-kind deadlines, and backup format 6. Browser checks cover
the guided schema flow, conflicts, reports, accessible pagination, cancellation
acknowledgement, authorization failures, and mobile layout after a real login.
CI pins the release digest listed in docs/compatibility.md. The scheduled
backend-main workflow continues checking future server builds separately.
npm run test:e2e:authenticated:full runs the complete authenticated suite,
then the live credential approval and restore checks on the same disposable
stack. Release readiness requires both to pass against Server v0.0.16.
Restore runs last because it replaces the database and invalidates tokens.
When explicitly testing an older backend image, set
HUBUUM_FULL_E2E_CREDENTIAL_APPROVALS=legacy to verify its original mutation flow.
The broader authenticated dashboard and create-flow checks run when
E2E_USERNAME and E2E_PASSWORD are set. Point either Playwright suite at an
already running frontend with PLAYWRIGHT_BASE_URL, for example
http://127.0.0.1:3000. CI runs the public functional checks, portable visual
comparisons, and disposable authenticated smoke flow as independent jobs.
Credential approval compatibility checks¶
npx playwright test tests/e2e/credential-approvals.spec.ts checks optional
password prompting, cancellation, accessibility, responsive layout, and legacy
responses without backend credentials.
tests/e2e/credential-approvals-live.spec.ts is an explicit opt-in test against a
disposable backend and an already running frontend. Set PLAYWRIGHT_BASE_URL,
E2E_USERNAME=admin, and capture E2E_PASSWORD in memory using the disposable
container's hubuum-admin --reset-password admin immediately before each run.
Set E2E_CREDENTIAL_APPROVALS=required for Server v0.0.16 or newer, or legacy
for a server without it, then run:
These checks create credentials and imports. On a fully disposable stack only,
E2E_CREDENTIAL_RESTORE=1 also verifies backup, approved restore confirmation,
and capability-authenticated polling through completion. Live credential tests
disable traces, screenshots, and video so secrets are not recorded in artifacts.
Use another Valkey port¶
If port 6379 is already occupied, start the dependency on another loopback port
and update .env.local to match:
Forward server compatibility¶
The live contract suite defaults to the pinned Server 0.0.16 contract. Set
HUBUUM_LIVE_EXPECT_SERVER_VERSION when verifying a specific release candidate.
The scheduled backend-main job sets HUBUUM_LIVE_FORWARD_COMPATIBILITY=1 to
exercise the complete contract across server version bumps; required release CI
retains its exact version check. Credential fixtures obtain approval only after
reauthentication_required, preserving the bearer, body, expiry precision, and
request guards. Older servers need no approval endpoint.