# Phase 1: Dev Environment — Plan **Goal:** Developer can run `nix develop` and have a working Kimai instance with test data, ready for plugin development. **Requirements:** DEV-01, DEV-02, DEV-03 **Research:** phase-1/RESEARCH.md ## Success Criteria 1. `nix develop` drops into a shell with PHP 8.2+, Composer, and Node available 2. A local Kimai instance starts and is accessible in the browser 3. The Kimai instance contains seeded time entry data spanning multiple months 4. A plugin directory is symlinked so code changes are reflected without reinstallation ## Waves ### Wave 1: Nix Flake + Infrastructure Scripts (autonomous) #### Plan 01-01: Nix Flake and Dev Infrastructure **Objective:** Create a reproducible dev environment with all dependencies and a one-command bootstrap. **Task 1: Create Nix flake and devshell** Create `flake.nix` at project root: - Input: `nixpkgs` (use `github:NixOS/nixpkgs/nixpkgs-unstable`) - DevShell packages: - PHP 8.2 with extensions: `gd`, `intl`, `mbstring`, `pdo_mysql`, `xml`, `xsl`, `zip`, `tokenizer` — use `php82.buildEnv { extensions = { enabled, all }: enabled ++ (with all; [ xsl pdo_mysql ]); }` - `php82Packages.composer` - `nodejs_22` - `mariadb` (11.4.x) - `symfony-cli` - `process-compose` - Shell hook: print a message pointing to `dev/setup.sh` for first-time setup and `process-compose -f dev/process-compose.yaml up` for starting the stack Create `.envrc` with `use flake` for direnv integration. **Task 2: Create process-compose config** Create `dev/process-compose.yaml`: - `mariadb` process: - Command: `mysqld --datadir=$PWD/dev/.mariadb-data --socket=$PWD/dev/.mariadb.sock --port=3307 --skip-grant-tables --skip-networking=0 --bind-address=127.0.0.1` - Readiness probe: `mysqladmin --socket=$PWD/dev/.mariadb.sock ping` (initial delay 2s, period 1s) - `kimai` process: - Command: `symfony server:start --no-tls --dir=$PWD/dev/kimai --port=8010` - Depends on: `mariadb` (condition: process_healthy) **Task 3: Create setup script** Create `dev/setup.sh` (executable): ```bash #!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_DIR="$(dirname "$SCRIPT_DIR")" KIMAI_DIR="$SCRIPT_DIR/kimai" DATA_DIR="$SCRIPT_DIR/.mariadb-data" # Step 1: Initialize MariaDB data directory if [ ! -d "$DATA_DIR" ]; then echo "==> Initializing MariaDB data directory..." mysql_install_db --datadir="$DATA_DIR" --auth-root-authentication-method=normal fi # Step 2: Start MariaDB temporarily for setup echo "==> Starting MariaDB for setup..." mysqld --datadir="$DATA_DIR" --socket="$SCRIPT_DIR/.mariadb.sock" --port=3307 --skip-grant-tables --skip-networking=0 --bind-address=127.0.0.1 & MARIADB_PID=$! trap "kill $MARIADB_PID 2>/dev/null || true" EXIT # Wait for MariaDB to be ready for i in $(seq 1 30); do if mysqladmin --socket="$SCRIPT_DIR/.mariadb.sock" ping 2>/dev/null; then break fi sleep 1 done # Create database mysql --socket="$SCRIPT_DIR/.mariadb.sock" -e "CREATE DATABASE IF NOT EXISTS kimai;" # Step 3: Clone Kimai if [ ! -d "$KIMAI_DIR" ]; then echo "==> Cloning Kimai 2.52.0..." git clone -b 2.52.0 --depth 1 https://github.com/kimai/kimai.git "$KIMAI_DIR" fi # Step 4: Configure Kimai cat > "$KIMAI_DIR/.env.local" < Installing Composer dependencies..." cd "$KIMAI_DIR" composer install --no-interaction # Step 6: Install Kimai (creates schema, runs migrations) echo "==> Installing Kimai..." bin/console kimai:install -n # Step 7: Load test fixtures echo "==> Loading test fixtures..." bin/console kimai:reset:dev -n # Step 8: Symlink plugin echo "==> Symlinking plugin..." mkdir -p var/plugins ln -sfn "$PROJECT_DIR" var/plugins/KimaiHeatmapBundle # Step 9: Clear cache bin/console cache:clear echo "" echo "==> Setup complete!" echo " Run: process-compose -f dev/process-compose.yaml up" echo " Then open: http://127.0.0.1:8010" echo " Login: susan_super / password" ``` **Task 4: Create .gitignore** Create/update `.gitignore`: ``` dev/kimai/ dev/.mariadb-data/ dev/.mariadb.sock dev/.mariadb.sock.lock node_modules/ vendor/ .direnv/ ``` **Commit:** `feat: add nix flake, process-compose, and setup script for dev environment` **Verification:** - `nix develop --command bash -c "php --version && composer --version && node --version"` succeeds - `nix develop --command bash -c "which mariadb && which symfony && which process-compose"` succeeds --- ### Wave 2: Kimai Instance + Plugin Scaffold (checkpoint required) #### Plan 01-02: Bootstrap Kimai and Create Plugin Scaffold **Objective:** Get Kimai running with test data and the plugin recognized. **Task 1: Create minimal plugin scaffold** Create these files at project root (the project root IS the plugin bundle): `KimaiHeatmapBundle.php`: ```php 0 rows - [ ] Plugin appears in Kimai admin > Plugins page ## Requirement Coverage | Requirement | Plan | Verified By | |-------------|------|-------------| | DEV-01 | 01-01 | `nix develop` provides PHP 8.2+, Composer, Node | | DEV-02 | 01-02 | `kimai:reset:dev` loads fixtures; SQL count check | | DEV-03 | 01-02 | `kimai:plugins` lists the plugin; plugin visible in admin | ## Risks | Risk | Mitigation | |------|------------| | MariaDB local datadir doesn't work | Fall back to `--socket` only or use `mysql_install_db --user=$(whoami)` | | PHP extension missing in Nix | Add explicit extensions to `php.buildEnv`; iterate based on `composer install` errors | | Kimai 2.52.0 incompatible with MariaDB 11.4 | Try `mariadb_1011` (10.11.x) from nixpkgs as fallback | | `kimai:reset:dev` fixture count too low | Acceptable for dev — supplement with API calls later if needed | ## Notes - Timebox this phase to 1 day. If Nix+MariaDB setup takes longer, consider Docker fallback. - The plugin scaffold is intentionally minimal — just enough for Kimai to recognize it. Real functionality comes in Phase 2. - `APP_ENV=dev` enables Symfony's auto-recompilation, so cache:clear is only needed after initial plugin symlink. --- *Plan created: 2026-04-08*