📚 View Component Library (Storybook)
For enhanced security and isolation, we recommend using a containerized development environment:
- Install the Dev Containers extension
- Open the project in VS Code
- Click "Reopen in Container" when prompted (or run command:
Dev Containers: Reopen in Container) - The container will automatically install dependencies and configure allowed scripts
- Use the integrated terminal in VS Code to run commands (all terminals opened in VS Code will run inside the container)
Use the built-in Dev Containers support available in recent versions.
Manually use Docker to run the development environment:
# Use the devcontainer image directly
docker run -it -v $(pwd):/workspaces/console-frontend -w /workspaces/console-frontend -p 5173:5173 -p 6006:6006 mcr.microsoft.com/devcontainers/javascript-node:22 bash
# Inside the container, run your development commands
npm install && npx allow-scripts auto
npm run dev- Isolated development environment (protection against supply chain attacks)
- Consistent Node.js version across team
- Pre-configured extensions and settings (VS Code/JetBrains)
- All npm commands run in a secure, sandboxed environment
For users with Nix installed, you can use the provided flake for a reproducible development environment:
cd .configs
nix developThis provides the same Node.js 22 and Git setup as the devcontainer. The flake is regularly updated to track the latest nixpkgs-unstable.
The following snippet contains the most important commands for development.
npm install
cp .env.example .env # Copy the example environment file
npm run build # Build the project
npm run dev # Starts a development server on port 5173
npm run check # Check for various issues
npm run lint # Lint the code
npm run format # Format the code (Or use a Prettier extension in your editor)
npm run test # Run tests with Vitest
npm run lockfile-lint # Validate package-lock.json securityThe project includes a component library documented with Storybook:
npm run storybook # Start Storybook dev server on port 6006
npm run build-storybook # Build static Storybook for deploymentStory files:
Component stories are located throughout the codebase alongside their components:
src/lib/ui/*.stories.svelte- UI component storiessrc/lib/domain/**/*.stories.svelte- Domain-specific component stories
Storybook configuration files are in .storybook/.
Upgrading Storybook:
When upgrading Storybook, use the upgrade script which automatically updates all related packages and reformats the files:
npm run upgrade-storybook <version>
# Example: npm run upgrade-storybook 10.1.11This will upgrade all Storybook packages together and reformat all project files:
storybook@storybook/sveltekit@storybook/addon-docs@storybook/addon-themes@storybook/addon-svelte-csf@chromatic-com/storybookeslint-plugin-storybook
Note: The upgrade script automatically checks the 14-day cooldown policy. To manually check a version's age before upgrading, use npm run check-age storybook <version>.
To connect to a nais-api instance, run the nais CLI proxy on your host machine (outside the devcontainer):
# On your host machine
nais auth login -n
nais alpha api proxyInside the devcontainer, update your .env to use host.docker.internal to access the host machine:
VITE_GRAPHQL_ENDPOINT="http://host.docker.internal:4242/graphql"
VITE_PROXY_ENDPOINT="http://host.docker.internal:4242"
VITE_SCHEMA_ENDPOINT="http://host.docker.internal:4242/graphql"This project implements several security measures to protect against supply chain attacks:
.npmrc: Containsignore-scripts=trueto disable all lifecycle scripts (preinstall, install, postinstall) by default@lavamoat/allow-scripts: Explicitly allowlists packages that need to run lifecycle scripts@lavamoat/preinstall-always-fail: Prevents accidental script execution during development
Only packages listed in package.json under lavamoat.allowScripts can run lifecycle scripts. To update the allowlist:
npm run allow-scripts.ncurc.cjs: Configuresnpm-check-updateswith a 14-day cooldown period- Only allows updates to packages published at least 14 days ago
- Reduces risk of compromised packages with malicious updates
To check for outdated dependencies:
npm run check-outdatedTo update outdated dependencies (respects 14-day cooldown):
npm run update-outdatedTo check when a specific package version was published:
npm run check-age <package-name> <version>
# Example: npm run check-age storybook 10.1.3lockfile-lint: Validatespackage-lock.jsonintegrity- Runs in CI/CD to detect tampering or unexpected changes
To manually validate the lockfile:
npm run lockfile-lintThe devcontainer automatically aliases npm to npq-hero, which provides interactive security checks before installing packages. When you run npm install <package> in the container, npq will:
- Check packages against known security vulnerabilities
- Verify package popularity and trustworthiness
- Alert you to suspicious patterns
Note: This alias only affects terminal sessions in the devcontainer.
Additional info:
- When running
npm installwithout package names (i.e., to install all dependencies), or when runningnpm ci,npq-herodoes not perform interactive security checks. - Security checks are only performed when installing or updating specific packages (e.g.,
npm install <package>).
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).