For users with Nix installed, you can use the provided flake for a reproducible development environment:
cd .configs
nix developThis provides Node.js 24, pnpm, and Git. The flake is regularly updated to track the latest nixpkgs-unstable.
The following snippet contains the most important commands for development.
pnpm install
cp .env.example .env # Copy the example environment file
pnpm run build # Build the project
pnpm run dev # Starts a development server on port 5173
pnpm run check # Check for various issues
pnpm run lint # Lint the code
pnpm run format # Format the code (Or use a Prettier extension in your editor)
pnpm run test # Run tests with VitestThe console should remain usable at small viewport widths, with 375px as the baseline mobile target.
When changing layouts, lists, tables, or chart-heavy pages, validate in responsive mode (for example 375x812) and ensure:
- No page-level horizontal scrolling on mobile
- Horizontal overflow is scoped to the component that needs it (for example tables)
- Two-column desktop layouts collapse to one column on mobile where relevant
- Touch targets and controls remain usable without overlapping
Styles use @layer ordering and design tokens from @nais/ds-svelte-community:
- Tokens: Use
--ax-space-*,--ax-radius-*,--ax-text-*variables — never hardcode spacing, radii, or colors - Utility classes:
src/styles/app.cssprovides.layout-two-column,.layout-sidebar,.table-scroll,.detail-actions,.loading-centeredfor common patterns - LayerChart theming:
src/styles/layerchart.cssmaps chart library variables to design tokens. The.darkblock must mirror the:rootdeclarations (tokens resolve differently per scope) - Validation: Run
pnpm run lint— ESLint includes custom rules for missing CSS variables and unused GraphQL files
The project is configured with AI assistant guidelines and the Svelte MCP (Model Context Protocol) server:
-
AGENTS.md — Project guidelines for AI assistants (GitHub Copilot, Cursor, Claude Code, etc.), covering Svelte 5 runes patterns, Houdini GraphQL conventions, CSS variable rules, component library usage, code quality standards, and security patterns.
-
Svelte MCP Server — Provides Svelte 5 and SvelteKit documentation to AI assistants via the official remote endpoint at
https://mcp.svelte.dev/mcp. In VS Code, it is available through the MCP server registry (no project config needed). For other editors (Cursor, Claude Code, Zed), it is configured in.mcp.json. Tools:list-sections,get-documentation,svelte-autofixer,playground-link.
To connect to a nais-api instance, run the nais CLI proxy on your host machine:
nais auth login -n
nais alpha api proxyThen set your .env:
VITE_GRAPHQL_ENDPOINT="http://localhost:4242/graphql"
VITE_PROXY_ENDPOINT="http://localhost:4242"
VITE_SCHEMA_ENDPOINT="http://localhost:4242/graphql"This project implements several security measures to protect against supply chain attacks:
pnpm v11 blocks lifecycle scripts by default. Only packages listed in pnpm-workspace.yaml under allowBuilds can run lifecycle scripts.
pnpm enforces a 14-day cooldown period via minimumReleaseAge: 20160 in pnpm-workspace.yaml. Only packages published at least 14 days ago are eligible for installation, reducing the risk of newly compromised packages.
To check for available updates:
pnpm run check-outdatedTo update outdated dependencies (respects 14-day cooldown):
pnpm run update-outdatedWhen merging a Dependabot PR for a package newer than 14 days (e.g. a security fix), add the package to minimumReleaseAgeExclude in pnpm-workspace.yaml before running pnpm install.
The 14-day cooldown enforced by pnpm's minimumReleaseAge is the primary supply-chain defense. Run pnpm audit to check for known vulnerabilities after installing.
In production api uses oauth2 to authenticate users.
When running locally, the frontend will proxy requests to the locally running backend through a Vite Proxy. This proxy will add a special header for local development to specify which user to run as.
There's two well known users:
| User | Description |
|---|---|
dev.usersen@example.com |
A user with tenant wide permissions, but owns a team |
admin.usersen@example.com |
A user with all permissions |
You can specify which user to run as through .env.
See .env.example for an example.
This repository uses GitHub Copilot to generate code.
The application uses Pino for structured JSON logging.
- Development: Human-readable logs with colors via
pino-pretty - Production: Structured JSON logs to stdout
Set LOG_LEVEL environment variable to control verbosity (trace, debug, info, warn, error, fatal). Default is info.
Server-side code should use the logger:
import { logger } from '$lib/logger';
logger.info({ userId: 123 }, 'User logged in');
logger.error({ error, context: 'some-context' }, 'An error occurred');HTTP requests are automatically logged in hooks.server.ts (errors and slow requests only).