diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 9fe3b59..381a54a 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -29,11 +29,11 @@ Decimal phases appear between their surrounding integers in numeric order. 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/mounted so code changes are reflected without reinstallation -**Plans**: TBD +**Plans:** 2 plans Plans: -- [ ] 01-01: TBD -- [ ] 01-02: TBD +- [ ] 01-01-PLAN.md — Nix flake with devshell, process-compose config, and bootstrap script +- [ ] 01-02-PLAN.md — Run setup, create plugin scaffold, verify end-to-end ### Phase 2: Plugin Scaffold + Data Layer **Goal**: Plugin is recognized by Kimai, shows a widget on the dashboard, and serves aggregated daily time data via API diff --git a/.planning/phases/01-dev-environment/01-01-PLAN.md b/.planning/phases/01-dev-environment/01-01-PLAN.md new file mode 100644 index 0000000..3e2e4e3 --- /dev/null +++ b/.planning/phases/01-dev-environment/01-01-PLAN.md @@ -0,0 +1,241 @@ +--- +phase: 01-dev-environment +plan: 01 +type: execute +wave: 1 +depends_on: [] +files_modified: + - flake.nix + - dev/process-compose.yaml + - dev/setup.sh + - .gitignore + - .envrc +autonomous: true +requirements: + - DEV-01 +must_haves: + truths: + - "nix develop drops into a shell with PHP 8.2+, Composer 2.x, Node 22.x, MariaDB, symfony-cli, and process-compose" + - "process-compose up starts MariaDB on port 3307 with a local data directory and Symfony dev server" + - "setup.sh clones Kimai, installs deps, creates DB, loads fixtures, and symlinks plugin" + artifacts: + - path: "flake.nix" + provides: "Nix devshell with all required packages and PHP extensions" + contains: "php82" + - path: "dev/process-compose.yaml" + provides: "MariaDB + Symfony dev server process definitions" + contains: "mariadb" + - path: "dev/setup.sh" + provides: "One-time Kimai bootstrap script" + contains: "kimai:reset:dev" + - path: ".gitignore" + provides: "Ignore dev artifacts (kimai clone, mariadb data, node_modules)" + contains: "dev/kimai" + key_links: + - from: "dev/process-compose.yaml" + to: "dev/.mariadb-data" + via: "mysqld --datadir" + pattern: "mariadb-data" + - from: "dev/setup.sh" + to: "dev/kimai" + via: "git clone kimai" + pattern: "git clone.*kimai" +--- + + +Create the Nix flake, process-compose config, and bootstrap script for the Kimai dev environment. + +Purpose: Provide a reproducible, one-command dev setup that gives the developer PHP 8.2+, MariaDB, Composer, Node, and all tooling needed for Kimai plugin development. +Output: flake.nix, dev/process-compose.yaml, dev/setup.sh, .gitignore + + + +@/home/toph/code/toph/kimai-heatmap/.claude/get-shit-done/workflows/execute-plan.md +@/home/toph/code/toph/kimai-heatmap/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/phase-1/RESEARCH.md + + + + + + Task 1: Create Nix flake with devshell + flake.nix, .envrc, .gitignore + +Create `flake.nix` with a devshell providing: + +**Packages:** +- PHP 8.2 with extensions: gd, intl, mbstring, pdo, pdo_mysql, xml, xsl, zip, tokenizer (use `pkgs.php82.buildEnv { extensions = { enabled, all }: enabled ++ (with all; [ xsl pdo_mysql ]); }`) +- `pkgs.php82Packages.composer` for Composer +- `pkgs.nodejs` (22.x) for JS tooling +- `pkgs.mariadb` (11.4.x) for database +- `pkgs.symfony-cli` for Symfony dev server +- `pkgs.process-compose` for multi-service management + +**Flake structure:** +- Use `flake-utils.lib.eachDefaultSystem` for portability +- Input: `nixpkgs` (use `github:NixOS/nixpkgs/nixpkgs-unstable`) +- Single devShell output +- Shell hook: print a short message with available commands (setup, start) + +**Also create:** +- `.envrc` with `use flake` for direnv integration +- `.gitignore` with entries for: + - `dev/kimai/` (cloned Kimai instance) + - `dev/.mariadb-data/` (MariaDB data directory) + - `dev/.mariadb.sock` (MariaDB socket) + - `dev/.mariadb.pid` (MariaDB PID file) + - `node_modules/` + - `vendor/` + - `.direnv/` + - `result` (nix build output) + - `*.js.map` (source maps) + - `dist/` (built JS output) + + + cd /home/toph/code/toph/kimai-heatmap && nix develop --command bash -c "php --version && composer --version && node --version && mysqld --version && symfony version && process-compose version" 2>&1 | head -20 + + nix develop provides PHP 8.2+, Composer, Node 22.x, MariaDB, symfony-cli, and process-compose. All commands resolve. + + + + Task 2: Create process-compose config and setup script + dev/process-compose.yaml, dev/setup.sh + +**Create `dev/process-compose.yaml`:** + +```yaml +version: "0.5" +processes: + mariadb: + command: | + mysqld --datadir=$PWD/dev/.mariadb-data \ + --socket=$PWD/dev/.mariadb.sock \ + --port=3307 \ + --skip-grant-tables \ + --skip-networking=false \ + --bind-address=127.0.0.1 + readiness_probe: + exec: + command: mysqladmin --socket=$PWD/dev/.mariadb.sock ping + initial_delay_seconds: 2 + period_seconds: 1 + shutdown: + command: mysqladmin --socket=$PWD/dev/.mariadb.sock shutdown + + kimai: + command: symfony server:start --no-tls --dir=$PWD/dev/kimai --port=8010 + depends_on: + mariadb: + condition: process_healthy +``` + +Use port 8010 for Kimai to avoid conflicts. Use `$PWD` for paths so process-compose works from project root. + +**Create `dev/setup.sh`** (make executable with `chmod +x`): + +The script should: +1. Check if already set up (if `dev/kimai` exists, skip clone) +2. Initialize MariaDB data directory if not present: + ```bash + mysql_install_db --datadir=./dev/.mariadb-data --auth-root-authentication-method=normal + ``` +3. Start MariaDB temporarily for setup (background, wait for ready): + ```bash + mysqld --datadir=./dev/.mariadb-data --socket=./dev/.mariadb.sock --port=3307 --skip-grant-tables --bind-address=127.0.0.1 & + MARIADB_PID=$! + # Wait for MariaDB to be ready + for i in $(seq 1 30); do mysqladmin --socket=./dev/.mariadb.sock ping 2>/dev/null && break; sleep 1; done + ``` +4. Create the `kimai` database: + ```bash + mysql --socket=./dev/.mariadb.sock -e "CREATE DATABASE IF NOT EXISTS kimai;" + ``` +5. Clone Kimai 2.52.0: + ```bash + git clone -b 2.52.0 --depth 1 https://github.com/kimai/kimai.git dev/kimai + ``` +6. Configure Kimai `.env.local` (NOT .env -- .env.local overrides): + ```bash + cat > dev/kimai/.env.local << 'ENVEOF' + DATABASE_URL=mysql://root@127.0.0.1:3307/kimai?charset=utf8mb4&serverVersion=11.4.8-MariaDB + APP_SECRET=change-me-dev-only-not-production + APP_ENV=dev + ENVEOF + ``` +7. Run Composer install in Kimai: + ```bash + cd dev/kimai && composer install --no-interaction + ``` +8. Run Kimai install (creates schema): + ```bash + bin/console kimai:install -n + ``` +9. Load dev fixtures (seeds test data): + ```bash + bin/console kimai:reset:dev -n + ``` +10. Symlink plugin directory: + ```bash + mkdir -p var/plugins + ln -sf "$(cd ../.. && pwd)" var/plugins/KimaiHeatmapBundle + ``` +11. Clear Kimai cache: + ```bash + bin/console cache:clear + ``` +12. Stop temporary MariaDB: + ```bash + kill $MARIADB_PID 2>/dev/null + wait $MARIADB_PID 2>/dev/null + ``` +13. Print success message with instructions to run `process-compose -f dev/process-compose.yaml up` + +**Important details:** +- Use `set -euo pipefail` at the top +- Use `127.0.0.1` NOT `localhost` in DATABASE_URL (localhost triggers Unix socket mode on Linux) +- The symlink target name MUST be `KimaiHeatmapBundle` (matches bundle class name) +- Use `--skip-grant-tables` for MariaDB since this is local dev only +- The script must be idempotent: skip steps that are already done (check for existing directories) + + + cd /home/toph/code/toph/kimai-heatmap && test -x dev/setup.sh && test -f dev/process-compose.yaml && head -5 dev/process-compose.yaml | grep -q "version" && echo "OK" + + dev/process-compose.yaml defines MariaDB + Kimai processes with health checks. dev/setup.sh is executable and contains the full bootstrap sequence (clone, install, seed, symlink). + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| Local dev only | No external network exposure; MariaDB binds to 127.0.0.1, Kimai on localhost:8010 | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-01-01 | Information Disclosure | MariaDB --skip-grant-tables | accept | Local dev only, bound to 127.0.0.1, no production data. Acceptable for dev environment. | +| T-01-02 | Information Disclosure | APP_SECRET in .env.local | accept | Dev-only value, .env.local is gitignored inside dev/kimai/ (Kimai's own .gitignore), not committed to plugin repo | + + + +1. `nix develop` provides all required tools (PHP 8.2+, Composer, Node, MariaDB, symfony-cli, process-compose) +2. `dev/setup.sh` exists, is executable, and contains the complete bootstrap sequence +3. `dev/process-compose.yaml` defines MariaDB and Kimai processes with dependency ordering +4. `.gitignore` excludes dev artifacts + + + +Running `nix develop` enters a shell with all dev tools. The setup script and process-compose config are ready to be executed in Plan 02. + + + +After completion, create `.planning/phases/01-dev-environment/01-01-SUMMARY.md` + diff --git a/.planning/phases/01-dev-environment/01-02-PLAN.md b/.planning/phases/01-dev-environment/01-02-PLAN.md new file mode 100644 index 0000000..5384bf4 --- /dev/null +++ b/.planning/phases/01-dev-environment/01-02-PLAN.md @@ -0,0 +1,186 @@ +--- +phase: 01-dev-environment +plan: 02 +type: execute +wave: 2 +depends_on: + - 01-01 +files_modified: + - KimaiHeatmapBundle.php + - composer.json +autonomous: false +requirements: + - DEV-02 + - DEV-03 +must_haves: + truths: + - "Running dev/setup.sh bootstraps a working Kimai instance with seeded timesheet data" + - "The Kimai instance has timesheet entries spanning multiple months" + - "Kimai recognizes KimaiHeatmapBundle as a loaded plugin" + - "The Kimai dashboard is accessible in the browser at localhost:8010" + artifacts: + - path: "KimaiHeatmapBundle.php" + provides: "Symfony bundle class implementing Kimai PluginInterface" + contains: "implements PluginInterface" + - path: "composer.json" + provides: "Plugin metadata with kimai-plugin type and autoload config" + contains: "kimai-plugin" + key_links: + - from: "dev/kimai/var/plugins/KimaiHeatmapBundle" + to: "project root" + via: "symlink" + pattern: "KimaiHeatmapBundle" + - from: "KimaiHeatmapBundle.php" + to: "Kimai plugin loader" + via: "PluginInterface implementation" + pattern: "PluginInterface" +--- + + +Run the setup script to bootstrap Kimai, create the minimal plugin scaffold, and verify the full dev environment works end-to-end. + +Purpose: Validate that the dev environment from Plan 01 actually produces a working Kimai instance with test data and a recognized plugin. +Output: Working Kimai instance, minimal plugin bundle class and composer.json, human-verified browser access. + + + +@/home/toph/code/toph/kimai-heatmap/.claude/get-shit-done/workflows/execute-plan.md +@/home/toph/code/toph/kimai-heatmap/.claude/get-shit-done/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/phase-1/RESEARCH.md +@.planning/phases/01-dev-environment/01-01-SUMMARY.md + + + + + + Task 1: Create plugin scaffold and run setup + KimaiHeatmapBundle.php, composer.json + +**Step 1: Create the minimal plugin bundle class** at project root `KimaiHeatmapBundle.php`: + +```php + /home/toph/code/toph/kimai-heatmap` (absolute path, directory name matches bundle class). + +**Step 4: Verify seeded data exists:** + +```bash +cd dev/kimai && bin/console doctrine:query:sql "SELECT COUNT(*) as cnt FROM kimai2_timesheet" +``` + +Should return a count of several hundred entries minimum. + +**Step 5: Verify plugin is loaded:** + +```bash +cd dev/kimai && bin/console kimai:plugins +``` + +Should list "Activity Heatmap" (the plugin name from composer.json extra.kimai.name). + + + cd /home/toph/code/toph/kimai-heatmap/dev/kimai && bin/console kimai:plugins 2>&1 | grep -i "heatmap" && bin/console doctrine:query:sql "SELECT COUNT(*) as cnt FROM kimai2_timesheet" 2>&1 + + Kimai instance running with seeded data. Plugin listed in kimai:plugins output. Database contains timesheet entries. + + + + Task 2: Verify dev environment in browser + Human verifies the complete dev environment works end-to-end by accessing Kimai in the browser and confirming the plugin is loaded. + Complete dev environment: Nix devshell with local Kimai instance, seeded test data, and plugin recognized by Kimai. + + 1. From the project root, run: `process-compose -f dev/process-compose.yaml up` + 2. Wait for both MariaDB and Kimai to show as healthy/running + 3. Open browser to http://127.0.0.1:8010 + 4. Log in with username `susan_super` password `password` (super admin from fixtures) + 5. Verify the dashboard loads (no errors) + 6. Navigate to System > Plugins -- verify "Activity Heatmap" appears in the list + 7. Stop process-compose with Ctrl+C + + Human confirms Kimai dashboard loads and plugin is listed + Dashboard accessible, plugin visible in admin, seeded data present + Type "approved" or describe issues + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| Plugin -> Kimai | Plugin runs inside Kimai's PHP process with full access to Kimai internals | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-01-03 | Elevation of Privilege | PluginInterface | accept | Plugin runs with same privileges as Kimai itself. This is by design in Kimai's plugin architecture. Personal use, single user. | +| T-01-04 | Information Disclosure | Fixture credentials (password: "password") | accept | Dev environment only. Fixtures create test users with known passwords. Not exposed beyond localhost. | + + + +1. `bin/console kimai:plugins` lists "Activity Heatmap" +2. `SELECT COUNT(*) FROM kimai2_timesheet` returns > 100 entries +3. Kimai dashboard loads in browser at http://127.0.0.1:8010 +4. Plugin appears in System > Plugins admin page + + + +Developer can run `nix develop`, execute `dev/setup.sh` once, then `process-compose -f dev/process-compose.yaml up` to get a working Kimai instance with seeded data and the heatmap plugin recognized. Dashboard accessible in browser, plugin listed in admin. + + + +After completion, create `.planning/phases/01-dev-environment/01-02-SUMMARY.md` +