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
nix developdrops into a shell with PHP 8.2+, Composer, and Node available- A local Kimai instance starts and is accessible in the browser
- The Kimai instance contains seeded time entry data spanning multiple months
- 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(usegithub:NixOS/nixpkgs/nixpkgs-unstable) - DevShell packages:
- PHP 8.2 with extensions:
gd,intl,mbstring,pdo_mysql,xml,xsl,zip,tokenizer— usephp82.buildEnv { extensions = { enabled, all }: enabled ++ (with all; [ xsl pdo_mysql ]); } php82Packages.composernodejs_22mariadb(11.4.x)symfony-cliprocess-compose
- PHP 8.2 with extensions:
- Shell hook: print a message pointing to
dev/setup.shfor first-time setup andprocess-compose -f dev/process-compose.yaml upfor starting the stack
Create .envrc with use flake for direnv integration.
Task 2: Create process-compose config
Create dev/process-compose.yaml:
mariadbprocess:- 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)
- Command:
kimaiprocess:- Command:
symfony server:start --no-tls --dir=$PWD/dev/kimai --port=8010 - Depends on:
mariadb(condition: process_healthy)
- Command:
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"succeedsnix 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)
- Enter devshell:
nix develop - Run setup:
bash dev/setup.sh - Start stack:
process-compose -f dev/process-compose.yaml up - Open browser:
http://127.0.0.1:8010 - Login:
susan_super/password
Verification checklist:
- Kimai dashboard loads in browser
cd dev/kimai && bin/console kimai:pluginslists "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=devenables Symfony's auto-recompilation, so cache:clear is only needed after initial plugin symlink.
Plan created: 2026-04-08