kimai-plugin-heatmap/.planning/milestones/v1.0-phases/phase-1/PLAN.md
Christopher Mühl 244c7c66fc
chore: archive v1.0 milestone
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-08 23:25:26 +02:00

7.4 KiB

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):

#!/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" <<EOF
DATABASE_URL=mysql://root@127.0.0.1:3307/kimai?charset=utf8mb4&serverVersion=11.4.8-MariaDB
APP_SECRET=$(openssl rand -hex 16)
APP_ENV=dev
MAILER_URL=null://null
EOF

# Step 5: Install Composer dependencies
echo "==> 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

namespace KimaiPlugin\KimaiHeatmapBundle;

use App\Plugin\PluginInterface;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class KimaiHeatmapBundle extends Bundle implements PluginInterface
{
}

composer.json:

{
    "name": "kimai-plugin/heatmap-bundle",
    "type": "kimai-plugin",
    "description": "GitHub-style activity heatmap dashboard widget for Kimai",
    "license": "MIT",
    "autoload": {
        "psr-4": {
            "KimaiPlugin\\KimaiHeatmapBundle\\": ""
        }
    },
    "extra": {
        "kimai": {
            "require": 25200,
            "name": "Activity Heatmap"
        }
    }
}

Commit: feat: add minimal plugin scaffold (bundle class + composer.json)

Task 2: Run setup and verify (CHECKPOINT — requires manual browser verification)

  1. Enter devshell: nix develop
  2. Run setup: bash dev/setup.sh
  3. Start stack: process-compose -f dev/process-compose.yaml up
  4. Open browser: http://127.0.0.1:8010
  5. Login: susan_super / password

Verification checklist:

  • Kimai dashboard loads in browser
  • cd dev/kimai && bin/console kimai:plugins lists "Activity Heatmap"
  • cd dev/kimai && bin/console doctrine:query:sql "SELECT COUNT(*) FROM kimai2_timesheet" returns > 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