> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hr-easy.nlead.ch/llms.txt
> Use this file to discover all available pages before exploring further.

# Local setup

> Getting a development environment running — everything in Docker.

## Everything runs in Docker

There is exactly one command to start development:

```bash theme={null}
docker compose up
```

That starts the Next.js app on port 3000, PostgreSQL on 5432, and MailHog (SMTP 1025,
web UI 8025). Hot reload works through volume mounts on `src/`, `prisma/` and
`public/`; the Node debugger is on 9229.

<Warning>
  Do **not** run `npm run dev`, Prisma commands, or `npm install` for the app on the
  host. They run in the container:

  ```bash theme={null}
  docker compose exec app npx prisma studio
  docker compose exec app npm install <pkg>
  ```
</Warning>

## Prerequisites

* Docker with Compose
* Node.js 22 on the host, for the quality gate (see below)

## First run

<Steps>
  <Step title="Copy the environment file">
    ```bash theme={null}
    cp .env.example .env
    ```

    Most of it is optional for local work. The integrations (Graph, bexio, DocuSign,
    SECO) degrade cleanly when unconfigured.
  </Step>

  <Step title="Start the stack">
    ```bash theme={null}
    docker compose up
    ```
  </Step>

  <Step title="Push the schema and seed">
    ```bash theme={null}
    docker compose exec app npx prisma db push
    docker compose exec app npm run db:seed
    ```
  </Step>

  <Step title="Optionally seed demo data">
    ```bash theme={null}
    docker compose exec app npm run db:seed-demo
    # and to remove it again
    docker compose exec app npm run db:unseed-demo
    ```
  </Step>

  <Step title="Open the app">
    [http://localhost:3000](http://localhost:3000). Mail goes to MailHog at
    [http://localhost:8025](http://localhost:8025) — magic links included.
  </Step>
</Steps>

## Signing in locally

Local development can use a dev-login route, guarded three ways: `ENABLE_DEV_LOGIN`
must be exactly `"true"`, `NODE_ENV` must not be `production`, and the host must not be
a production domain.

<Warning>
  Production deployments must leave `ENABLE_DEV_LOGIN` unset. It is not a feature flag — it is a
  local-only bypass.
</Warning>

Set `COOKIE_SECURE=false` for plain `http://localhost` (the dev compose files already
do). Never set it in a deployed environment.

## The quality gate runs on the host

The gate is deliberately Docker-free and Postgres-free — unit and component tests mock
the database — so it also works in web sessions where `docker compose exec` is not
available:

```bash theme={null}
npm run gate        # full: format, guards, script tests, lint, typecheck, tests, build
npm run gate:fast   # quick: format, guards, lint, typecheck — what the pre-push hook runs
```

See [The quality gate](/development/quality-gate).

## Git hooks

Installed automatically on `npm install`:

| Hook       | Does                                                                      |
| ---------- | ------------------------------------------------------------------------- |
| pre-commit | Auto-formats staged files with Prettier; runs the schema-migration guard. |
| pre-push   | Runs `npm run gate:fast`.                                                 |

Bypass deliberately with `--no-verify` when you have a reason.

## Useful commands

```bash theme={null}
# Database
docker compose exec app npx prisma db push
docker compose exec app npm run db:migrate:create -- describe_your_change
docker compose exec app npm run db:studio

# Tests
npm test                       # unit + component
npm run test:watch
npm run test:e2e               # Playwright

# Contracts
npm run gen:openapi            # regenerate the portal contract artifacts
```

## Which CI path your diff takes

```bash theme={null}
git diff --name-only origin/develop...HEAD | bash scripts/classify-pr-paths.sh
```

`docs_only=true` means CI runs only the static leg. `prisma_changed=false` means the
Postgres migrations job is skipped.
