From ffab9dc4da541c8579738db8a1b8b1bad4e38c4d Mon Sep 17 00:00:00 2001
From: Fabian de Boer
Date: Sun, 19 Jul 2026 22:49:00 +0200
Subject: [PATCH 08/10] removed kanban from gitignore
---
.gitignore | 1 -
kanban/.lock | 0
kanban/activity.jsonl | 87 +++++++++++++++++++
kanban/config.yml | 47 ++++++++++
kanban/tasks/001-pixabay-api.md | 13 +++
kanban/tasks/002-pexels-api.md | 13 +++
kanban/tasks/003-random-words.md | 13 +++
.../tasks/004-search-for-original-images.md | 13 +++
kanban/tasks/005-image-processing.md | 14 +++
kanban/tasks/006-full-screen-gui.md | 14 +++
.../007-ai-generated-images-for-input.md | 14 +++
kanban/tasks/008-automatic-mode.md | 14 +++
kanban/tasks/009-framework-guide.md | 13 +++
kanban/tasks/010-check-framework.md | 16 ++++
...request-building-lazy-url-single-encode.md | 22 +++++
...utoloader-use-path-separator-instead-of.md | 20 +++++
...-hygiene-zap-debug-false-secrets-in-git.md | 19 ++++
...-add-csrf-protection-to-word-input-form.md | 17 ++++
...e-wrong-parameter-with-proper-404-error.md | 17 ++++
...16-fix-and-secure-cli-scripts-reset-php.md | 23 +++++
...on-folder-names-unique-stop-suppressing.md | 17 ++++
...uce-zaphandler-interface-for-getcontent.md | 18 ++++
...-source-of-truth-for-word-count-cleanup.md | 13 +++
...t-template-rendering-pattern-across-all.md | 13 +++
...lidate-duplicated-screen-size-constants.md | 17 ++++
...tgifstopng-extension-rename-fix-log-xml.md | 19 ++++
...app-base-dir-to-dir-make-getzaptemplate.md | 19 ++++
...eadme-yahoo-brave-drop-outdated-roadmap.md | 17 ++++
28 files changed, 522 insertions(+), 1 deletion(-)
create mode 100644 kanban/.lock
create mode 100644 kanban/activity.jsonl
create mode 100644 kanban/config.yml
create mode 100644 kanban/tasks/001-pixabay-api.md
create mode 100644 kanban/tasks/002-pexels-api.md
create mode 100644 kanban/tasks/003-random-words.md
create mode 100644 kanban/tasks/004-search-for-original-images.md
create mode 100644 kanban/tasks/005-image-processing.md
create mode 100644 kanban/tasks/006-full-screen-gui.md
create mode 100644 kanban/tasks/007-ai-generated-images-for-input.md
create mode 100644 kanban/tasks/008-automatic-mode.md
create mode 100644 kanban/tasks/009-framework-guide.md
create mode 100644 kanban/tasks/010-check-framework.md
create mode 100644 kanban/tasks/011-fix-brave-request-building-lazy-url-single-encode.md
create mode 100644 kanban/tasks/012-fix-autoloader-use-path-separator-instead-of.md
create mode 100644 kanban/tasks/013-config-hygiene-zap-debug-false-secrets-in-git.md
create mode 100644 kanban/tasks/014-add-csrf-protection-to-word-input-form.md
create mode 100644 kanban/tasks/015-replace-die-wrong-parameter-with-proper-404-error.md
create mode 100644 kanban/tasks/016-fix-and-secure-cli-scripts-reset-php.md
create mode 100644 kanban/tasks/017-make-session-folder-names-unique-stop-suppressing.md
create mode 100644 kanban/tasks/018-introduce-zaphandler-interface-for-getcontent.md
create mode 100644 kanban/tasks/019-single-source-of-truth-for-word-count-cleanup.md
create mode 100644 kanban/tasks/020-consistent-template-rendering-pattern-across-all.md
create mode 100644 kanban/tasks/021-consolidate-duplicated-screen-size-constants.md
create mode 100644 kanban/tasks/022-fix-convertgifstopng-extension-rename-fix-log-xml.md
create mode 100644 kanban/tasks/023-anchor-zap-app-base-dir-to-dir-make-getzaptemplate.md
create mode 100644 kanban/tasks/024-refresh-readme-yahoo-brave-drop-outdated-roadmap.md
diff --git a/.gitignore b/.gitignore
index 4dfc547..b9c4024 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,5 @@
sessions/*
conf/conf.local.php
ignore
-kanban/
.pi-tasks
docs/framework_review.md
diff --git a/kanban/.lock b/kanban/.lock
new file mode 100644
index 0000000..e69de29
diff --git a/kanban/activity.jsonl b/kanban/activity.jsonl
new file mode 100644
index 0000000..1453eab
--- /dev/null
+++ b/kanban/activity.jsonl
@@ -0,0 +1,87 @@
+{"timestamp":"2026-07-15T14:55:51.244024579+02:00","action":"create","task_id":1,"detail":"pixabay api"}
+{"timestamp":"2026-07-15T14:56:56.736534944+02:00","action":"edit","task_id":1,"detail":"pixabay api"}
+{"timestamp":"2026-07-15T14:58:10.598825995+02:00","action":"create","task_id":2,"detail":"Pexels api"}
+{"timestamp":"2026-07-15T14:58:27.253134741+02:00","action":"edit","task_id":2,"detail":"Pexels api"}
+{"timestamp":"2026-07-15T15:00:10.532523584+02:00","action":"create","task_id":3,"detail":"random words"}
+{"timestamp":"2026-07-15T15:02:31.109387111+02:00","action":"create","task_id":4,"detail":"search for original images"}
+{"timestamp":"2026-07-15T15:02:43.403448994+02:00","action":"edit","task_id":4,"detail":"search for original images"}
+{"timestamp":"2026-07-15T15:13:21.132728219+02:00","action":"create","task_id":5,"detail":"image processing"}
+{"timestamp":"2026-07-15T15:15:54.327404411+02:00","action":"create","task_id":6,"detail":"full screen gui"}
+{"timestamp":"2026-07-15T15:17:54.955029144+02:00","action":"create","task_id":7,"detail":"ai generated images for input"}
+{"timestamp":"2026-07-15T15:20:29.077954887+02:00","action":"create","task_id":8,"detail":"automatic mode"}
+{"timestamp":"2026-07-15T15:22:18.569491561+02:00","action":"create","task_id":9,"detail":"library guide"}
+{"timestamp":"2026-07-15T15:22:33.368044405+02:00","action":"move","task_id":9,"detail":"backlog -\u003e todo"}
+{"timestamp":"2026-07-15T15:23:07.895052923+02:00","action":"move","task_id":6,"detail":"backlog -\u003e todo"}
+{"timestamp":"2026-07-15T15:23:14.910744836+02:00","action":"move","task_id":5,"detail":"backlog -\u003e todo"}
+{"timestamp":"2026-07-17T00:46:24.790499349+02:00","action":"edit","task_id":9,"detail":"framework guide"}
+{"timestamp":"2026-07-17T01:14:23.984206626+02:00","action":"move","task_id":9,"detail":"todo -\u003e in-progress"}
+{"timestamp":"2026-07-17T02:16:23.061670813+02:00","action":"create","task_id":10,"detail":"check framework"}
+{"timestamp":"2026-07-17T02:16:52.676988996+02:00","action":"move","task_id":9,"detail":"in-progress -\u003e done"}
+{"timestamp":"2026-07-17T02:54:59.922251442+02:00","action":"move","task_id":10,"detail":"todo -\u003e in-progress"}
+{"timestamp":"2026-07-17T03:04:14.08873263+02:00","action":"priority","task_id":10,"detail":"high -\u003e medium"}
+{"timestamp":"2026-07-17T03:04:15.072297537+02:00","action":"priority","task_id":10,"detail":"medium -\u003e low"}
+{"timestamp":"2026-07-17T03:04:23.967707693+02:00","action":"priority","task_id":10,"detail":"low -\u003e medium"}
+{"timestamp":"2026-07-17T03:04:24.575872692+02:00","action":"priority","task_id":10,"detail":"medium -\u003e high"}
+{"timestamp":"2026-07-17T03:25:58.441011923+02:00","action":"edit","task_id":10,"detail":"check framework"}
+{"timestamp":"2026-07-17T03:26:01.636755342+02:00","action":"move","task_id":10,"detail":"in-progress -\u003e review"}
+{"timestamp":"2026-07-17T03:26:18.979779542+02:00","action":"edit","task_id":10,"detail":"check framework"}
+{"timestamp":"2026-07-17T03:26:18.979863107+02:00","action":"release","task_id":10,"detail":"tui@mcBookje"}
+{"timestamp":"2026-07-17T03:50:56.347742215+02:00","action":"move","task_id":6,"detail":"todo -\u003e backlog"}
+{"timestamp":"2026-07-17T03:51:00.178032766+02:00","action":"move","task_id":5,"detail":"todo -\u003e backlog"}
+{"timestamp":"2026-07-17T03:57:00.446052295+02:00","action":"create","task_id":11,"detail":"Fix Brave request building: lazy URL + single encode"}
+{"timestamp":"2026-07-17T03:57:06.830184988+02:00","action":"create","task_id":12,"detail":"Fix autoloader: use PATH_SEPARATOR instead of hardcoded ':'"}
+{"timestamp":"2026-07-17T03:57:13.889026673+02:00","action":"create","task_id":13,"detail":"Config hygiene: ZAP_DEBUG=false, secrets in git-ignored local file, sessions perms"}
+{"timestamp":"2026-07-17T03:57:20.700148188+02:00","action":"create","task_id":14,"detail":"Add CSRF protection to word-input form"}
+{"timestamp":"2026-07-17T03:57:28.29860719+02:00","action":"create","task_id":15,"detail":"Replace die('Wrong parameter') with proper 404/error handler"}
+{"timestamp":"2026-07-17T03:57:35.273661605+02:00","action":"create","task_id":16,"detail":"Fix and secure cli_scripts/reset.php"}
+{"timestamp":"2026-07-17T03:57:50.885872288+02:00","action":"create","task_id":17,"detail":"Make session folder names unique, stop suppressing mkdir errors"}
+{"timestamp":"2026-07-17T03:57:59.05551049+02:00","action":"create","task_id":18,"detail":"Introduce ZAPHandler interface for getContent()"}
+{"timestamp":"2026-07-17T03:58:05.367581371+02:00","action":"create","task_id":19,"detail":"Single source of truth for word count + cleanup handleWords"}
+{"timestamp":"2026-07-17T03:58:11.989024488+02:00","action":"create","task_id":20,"detail":"Consistent template rendering pattern across all handlers"}
+{"timestamp":"2026-07-17T03:58:20.432255313+02:00","action":"create","task_id":21,"detail":"Consolidate duplicated screen-size constants"}
+{"timestamp":"2026-07-17T03:58:30.405465201+02:00","action":"create","task_id":22,"detail":"Fix convertGifsToPng extension + rename/fix log.xml"}
+{"timestamp":"2026-07-17T03:58:37.159090865+02:00","action":"create","task_id":23,"detail":"Anchor ZAP_APP_BASE_DIR to __DIR__, make getZAPTemplate throw"}
+{"timestamp":"2026-07-17T03:58:43.664420067+02:00","action":"create","task_id":24,"detail":"Refresh README (Yahoo→Brave, drop outdated roadmap, fix tone)"}
+{"timestamp":"2026-07-17T12:26:07.265732515+02:00","action":"move","task_id":10,"detail":"review -\u003e done"}
+{"timestamp":"2026-07-17T12:26:29.348995723+02:00","action":"move","task_id":11,"detail":"todo -\u003e in-progress"}
+{"timestamp":"2026-07-17T12:26:34.350031444+02:00","action":"edit","task_id":11,"detail":"Fix Brave request building: lazy URL + single encode"}
+{"timestamp":"2026-07-17T12:26:38.760178641+02:00","action":"move","task_id":11,"detail":"in-progress -\u003e review"}
+{"timestamp":"2026-07-17T12:26:38.760294679+02:00","action":"handoff","task_id":11,"detail":"Fix Brave request building: lazy URL + single encode"}
+{"timestamp":"2026-07-17T12:26:38.760385873+02:00","action":"release","task_id":11,"detail":"Fix Brave request building: lazy URL + single encode"}
+{"timestamp":"2026-07-17T12:27:40.64656083+02:00","action":"move","task_id":12,"detail":"todo -\u003e in-progress"}
+{"timestamp":"2026-07-17T12:27:53.052811022+02:00","action":"edit","task_id":12,"detail":"Fix autoloader: use PATH_SEPARATOR instead of hardcoded ':'"}
+{"timestamp":"2026-07-17T12:27:53.056394858+02:00","action":"move","task_id":12,"detail":"in-progress -\u003e review"}
+{"timestamp":"2026-07-17T12:27:53.056484271+02:00","action":"handoff","task_id":12,"detail":"Fix autoloader: use PATH_SEPARATOR instead of hardcoded ':'"}
+{"timestamp":"2026-07-17T12:27:53.056530205+02:00","action":"release","task_id":12,"detail":"Fix autoloader: use PATH_SEPARATOR instead of hardcoded ':'"}
+{"timestamp":"2026-07-17T21:40:38.025770941+02:00","action":"move","task_id":13,"detail":"todo -\u003e in-progress"}
+{"timestamp":"2026-07-17T21:54:34.996015797+02:00","action":"move","task_id":13,"detail":"in-progress -\u003e review"}
+{"timestamp":"2026-07-17T22:27:10.995630482+02:00","action":"move","task_id":13,"detail":"review -\u003e done"}
+{"timestamp":"2026-07-18T11:42:51.254205784+02:00","action":"move","task_id":18,"detail":"todo -\u003e in-progress"}
+{"timestamp":"2026-07-18T11:50:59.773873861+02:00","action":"edit","task_id":18,"detail":"Introduce ZAPHandler interface for getContent()"}
+{"timestamp":"2026-07-18T11:51:03.257951319+02:00","action":"edit","task_id":18,"detail":"Introduce ZAPHandler interface for getContent()"}
+{"timestamp":"2026-07-18T11:51:03.258056745+02:00","action":"release","task_id":18,"detail":"tui@mcBookje"}
+{"timestamp":"2026-07-18T11:51:03.28154522+02:00","action":"move","task_id":18,"detail":"in-progress -\u003e done"}
+{"timestamp":"2026-07-19T19:06:12.923187222+02:00","action":"edit","task_id":17,"detail":"Make session folder names unique, stop suppressing mkdir errors"}
+{"timestamp":"2026-07-19T19:06:12.930146038+02:00","action":"claim","task_id":17,"detail":"rain-raven"}
+{"timestamp":"2026-07-19T19:06:58.839482716+02:00","action":"move","task_id":17,"detail":"todo -\u003e done"}
+{"timestamp":"2026-07-19T20:09:41.967705512+02:00","action":"edit","task_id":16,"detail":"Fix and secure cli_scripts/reset.php"}
+{"timestamp":"2026-07-19T20:09:41.967823882+02:00","action":"claim","task_id":16,"detail":"rain-raven"}
+{"timestamp":"2026-07-19T20:09:41.988956545+02:00","action":"move","task_id":16,"detail":"todo -\u003e done"}
+{"timestamp":"2026-07-19T20:20:19.991872348+02:00","action":"edit","task_id":15,"detail":"Replace die('Wrong parameter') with proper 404/error handler"}
+{"timestamp":"2026-07-19T20:20:19.991950864+02:00","action":"claim","task_id":15,"detail":"rain-raven"}
+{"timestamp":"2026-07-19T20:20:20.013428274+02:00","action":"move","task_id":15,"detail":"todo -\u003e done"}
+{"timestamp":"2026-07-19T21:23:27.794040982+02:00","action":"edit","task_id":14,"detail":"Add CSRF protection to word-input form"}
+{"timestamp":"2026-07-19T21:23:27.794120976+02:00","action":"claim","task_id":14,"detail":"rain-raven"}
+{"timestamp":"2026-07-19T21:23:27.819566153+02:00","action":"move","task_id":14,"detail":"todo -\u003e done"}
+{"timestamp":"2026-07-19T21:31:14.49434419+02:00","action":"edit","task_id":24,"detail":"Refresh README (Yahoo→Brave, drop outdated roadmap, fix tone)"}
+{"timestamp":"2026-07-19T21:31:14.494474852+02:00","action":"claim","task_id":24,"detail":"rain-raven"}
+{"timestamp":"2026-07-19T21:31:14.518300878+02:00","action":"move","task_id":24,"detail":"todo -\u003e done"}
+{"timestamp":"2026-07-19T21:39:02.761552753+02:00","action":"edit","task_id":23,"detail":"Anchor ZAP_APP_BASE_DIR to __DIR__, make getZAPTemplate throw"}
+{"timestamp":"2026-07-19T21:39:02.761712873+02:00","action":"claim","task_id":23,"detail":"rain-raven"}
+{"timestamp":"2026-07-19T21:39:02.783567342+02:00","action":"move","task_id":23,"detail":"todo -\u003e done"}
+{"timestamp":"2026-07-19T21:42:54.751029245+02:00","action":"edit","task_id":22,"detail":"Fix convertGifsToPng extension + rename/fix log.xml"}
+{"timestamp":"2026-07-19T21:42:54.751140546+02:00","action":"claim","task_id":22,"detail":"rain-raven"}
+{"timestamp":"2026-07-19T21:42:54.773029003+02:00","action":"move","task_id":22,"detail":"todo -\u003e done"}
+{"timestamp":"2026-07-19T21:49:54.312195218+02:00","action":"edit","task_id":21,"detail":"Consolidate duplicated screen-size constants"}
+{"timestamp":"2026-07-19T21:49:54.312297605+02:00","action":"claim","task_id":21,"detail":"rain-raven"}
+{"timestamp":"2026-07-19T21:49:54.334491216+02:00","action":"move","task_id":21,"detail":"todo -\u003e done"}
diff --git a/kanban/config.yml b/kanban/config.yml
new file mode 100644
index 0000000..eb9fd78
--- /dev/null
+++ b/kanban/config.yml
@@ -0,0 +1,47 @@
+version: 10
+board:
+ name: ZapMachine
+tasks_dir: tasks
+statuses:
+ - name: backlog
+ show_duration: false
+ - name: todo
+ - name: in-progress
+ require_claim: true
+ - name: review
+ require_claim: true
+ - name: done
+ show_duration: false
+ - name: archived
+ show_duration: false
+priorities:
+ - low
+ - medium
+ - high
+ - critical
+defaults:
+ status: backlog
+ priority: medium
+ class: standard
+claim_timeout: 1m
+classes:
+ - name: expedite
+ wip_limit: 1
+ bypass_column_wip: true
+ - name: fixed-date
+ - name: standard
+ - name: intangible
+tui:
+ title_lines: 2
+ age_thresholds:
+ - after: 0s
+ color: "242"
+ - after: 1h
+ color: "34"
+ - after: 24h
+ color: "226"
+ - after: 72h
+ color: "208"
+ - after: 168h
+ color: "196"
+next_id: 25
diff --git a/kanban/tasks/001-pixabay-api.md b/kanban/tasks/001-pixabay-api.md
new file mode 100644
index 0000000..85e9e35
--- /dev/null
+++ b/kanban/tasks/001-pixabay-api.md
@@ -0,0 +1,13 @@
+---
+id: 1
+title: pixabay api
+status: backlog
+priority: high
+created: 2026-07-15T14:55:51.243108541+02:00
+updated: 2026-07-15T14:56:56.735673124+02:00
+tags:
+ - search
+class: standard
+---
+
+Add Pixabay api as search engine
diff --git a/kanban/tasks/002-pexels-api.md b/kanban/tasks/002-pexels-api.md
new file mode 100644
index 0000000..3d8f41b
--- /dev/null
+++ b/kanban/tasks/002-pexels-api.md
@@ -0,0 +1,13 @@
+---
+id: 2
+title: Pexels api
+status: backlog
+priority: high
+created: 2026-07-15T14:58:10.597616484+02:00
+updated: 2026-07-15T14:58:27.252246225+02:00
+tags:
+ - search
+class: standard
+---
+
+Use pexels api as a seach engine
diff --git a/kanban/tasks/003-random-words.md b/kanban/tasks/003-random-words.md
new file mode 100644
index 0000000..28991e1
--- /dev/null
+++ b/kanban/tasks/003-random-words.md
@@ -0,0 +1,13 @@
+---
+id: 3
+title: random words
+status: backlog
+priority: high
+created: 2026-07-15T15:00:10.530100379+02:00
+updated: 2026-07-15T15:00:10.530100379+02:00
+tags:
+ - search
+class: standard
+---
+
+random word version (https://random-words-api.kushcreates.com/)
diff --git a/kanban/tasks/004-search-for-original-images.md b/kanban/tasks/004-search-for-original-images.md
new file mode 100644
index 0000000..0cb420b
--- /dev/null
+++ b/kanban/tasks/004-search-for-original-images.md
@@ -0,0 +1,13 @@
+---
+id: 4
+title: search for original images
+status: backlog
+priority: low
+created: 2026-07-15T15:02:31.107843015+02:00
+updated: 2026-07-15T15:02:43.402550141+02:00
+tags:
+ - search
+class: standard
+---
+
+input number and search for a fresh photo with a camera filename like 'img####.jpg'
diff --git a/kanban/tasks/005-image-processing.md b/kanban/tasks/005-image-processing.md
new file mode 100644
index 0000000..c472770
--- /dev/null
+++ b/kanban/tasks/005-image-processing.md
@@ -0,0 +1,14 @@
+---
+id: 5
+title: image processing
+status: backlog
+priority: critical
+created: 2026-07-15T15:13:21.131166647+02:00
+updated: 2026-07-17T03:51:00.175266589+02:00
+started: 2026-07-15T15:23:14.91034394+02:00
+tags:
+ - image_processing
+class: standard
+---
+
+Put back the original image processing from the old Zap Machine
diff --git a/kanban/tasks/006-full-screen-gui.md b/kanban/tasks/006-full-screen-gui.md
new file mode 100644
index 0000000..4c107a0
--- /dev/null
+++ b/kanban/tasks/006-full-screen-gui.md
@@ -0,0 +1,14 @@
+---
+id: 6
+title: full screen gui
+status: backlog
+priority: critical
+created: 2026-07-15T15:15:54.325695132+02:00
+updated: 2026-07-17T03:50:56.343336322+02:00
+started: 2026-07-15T15:23:07.894599552+02:00
+tags:
+ - gui
+class: standard
+---
+
+Full screen GUI with the collage covering the background and a partly transparen control panel and feedback screen on the right
diff --git a/kanban/tasks/007-ai-generated-images-for-input.md b/kanban/tasks/007-ai-generated-images-for-input.md
new file mode 100644
index 0000000..0680553
--- /dev/null
+++ b/kanban/tasks/007-ai-generated-images-for-input.md
@@ -0,0 +1,14 @@
+---
+id: 7
+title: ai generated images for input
+status: backlog
+priority: medium
+created: 2026-07-15T15:17:54.953039352+02:00
+updated: 2026-07-15T15:17:54.953039352+02:00
+tags:
+ - search
+ - source
+class: standard
+---
+
+use a scraper (brightdata) or write one ourselves to scrape for ai genarated images as sources
diff --git a/kanban/tasks/008-automatic-mode.md b/kanban/tasks/008-automatic-mode.md
new file mode 100644
index 0000000..b71b059
--- /dev/null
+++ b/kanban/tasks/008-automatic-mode.md
@@ -0,0 +1,14 @@
+---
+id: 8
+title: automatic mode
+status: backlog
+priority: medium
+created: 2026-07-15T15:20:29.075465548+02:00
+updated: 2026-07-15T15:20:29.075465548+02:00
+tags:
+ - gui
+ - mode
+class: standard
+---
+
+if one or more people are watching automatically generate a zap layer every 21 seconds
diff --git a/kanban/tasks/009-framework-guide.md b/kanban/tasks/009-framework-guide.md
new file mode 100644
index 0000000..7b5abd3
--- /dev/null
+++ b/kanban/tasks/009-framework-guide.md
@@ -0,0 +1,13 @@
+---
+id: 9
+title: framework guide
+status: done
+priority: critical
+created: 2026-07-15T15:22:18.567355625+02:00
+updated: 2026-07-17T02:16:52.6730631+02:00
+started: 2026-07-15T15:22:33.367755161+02:00
+completed: 2026-07-17T02:16:52.676581649+02:00
+class: standard
+---
+
+add the usage of the framework in the README. How does this framework work, how to add templates with interactive elements
diff --git a/kanban/tasks/010-check-framework.md b/kanban/tasks/010-check-framework.md
new file mode 100644
index 0000000..f2fe51f
--- /dev/null
+++ b/kanban/tasks/010-check-framework.md
@@ -0,0 +1,16 @@
+---
+id: 10
+title: check framework
+status: done
+priority: high
+created: 2026-07-17T02:16:23.059189291+02:00
+updated: 2026-07-17T12:26:07.258170416+02:00
+started: 2026-07-17T12:26:07.265125164+02:00
+completed: 2026-07-17T12:26:07.265125164+02:00
+class: standard
+---
+
+Check if the framework is the optimal, most simple and flexible way to go. If not: suggest some changes.
+
+[[2026-07-17]] Fri 03:25
+Framework review committed: docs/framework_review.md (commit 2f61b07). Verdict: architecture is simple/flexible (zero-config routing, autoloader, Search plugin interface, native templates) — keep as-is. Not optimal due to 3 P0 correctness bugs (Brave size/offset params never sent because setQuery builds URL before setParam; query double-URL-encoded; autoloader hardcodes ':' vs PATH_SEPARATOR), P1 config/security (ZAP_DEBUG=true & placeholder key committed, no CSRF, die() routing, unsafe reset.php, second-resolution session folder collisions), P2 consistency. NO source edits — deliverable is docs-only. Includes recommended-task table for follow-up fixes (each independently approvable). Handing to review for Fabian's approval before any code changes.
diff --git a/kanban/tasks/011-fix-brave-request-building-lazy-url-single-encode.md b/kanban/tasks/011-fix-brave-request-building-lazy-url-single-encode.md
new file mode 100644
index 0000000..5f2c2cc
--- /dev/null
+++ b/kanban/tasks/011-fix-brave-request-building-lazy-url-single-encode.md
@@ -0,0 +1,22 @@
+---
+id: 11
+title: 'Fix Brave request building: lazy URL + single encode'
+status: review
+priority: high
+created: 2026-07-17T03:57:00.444816503+02:00
+updated: 2026-07-17T12:26:38.759875442+02:00
+tags:
+ - search
+ - bug
+class: standard
+---
+
+From framework review (docs/framework_review.md). Two-part fix in resource/Brave.class.php + lib/ImgSearch.class.php:
+1. Move URL construction from setQuery() to getData() so setParam('start'/'size') values are applied (currently size defaults to 3 instead of 16, offset is never sent).
+2. Remove double urlencode: ImgSearch passes urlencode(word) into Brave::setQuery which urlencodes again → %2520 for spaces. Fix: pass raw word from ImgSearch; engine owns encoding.
+
+[[2026-07-17]] Fri 12:26
+P0-1: Moved URL construction from setQuery() to new buildRequest() called from getData() — size/offset now use setParam() values (resource/Brave.class.php). P0-2: Removed urlencode() call from ImgSearch::getImageData() — raw word passed to engine, single encode in Brave (lib/ImgSearch.class.php). Both pass php -l.
+
+[[2026-07-17]] Fri 12:26
+P0-1 + P0-2 implemented. Changes to resource/Brave.class.php and lib/ImgSearch.class.php. Both pass php -l. Ready for your commit.
diff --git a/kanban/tasks/012-fix-autoloader-use-path-separator-instead-of.md b/kanban/tasks/012-fix-autoloader-use-path-separator-instead-of.md
new file mode 100644
index 0000000..211a40d
--- /dev/null
+++ b/kanban/tasks/012-fix-autoloader-use-path-separator-instead-of.md
@@ -0,0 +1,20 @@
+---
+id: 12
+title: 'Fix autoloader: use PATH_SEPARATOR instead of hardcoded '':'''
+status: review
+priority: high
+created: 2026-07-17T03:57:06.82901804+02:00
+updated: 2026-07-17T12:27:53.056263524+02:00
+tags:
+ - framework
+ - bug
+class: standard
+---
+
+From framework review (docs/framework_review.md). conf/init.php uses explode(':', get_include_path()) but the include path separator is ':' on Unix and ';' on Windows. Makes the autoloader fail on Windows. Fix: explode(PATH_SEPARATOR, get_include_path()).
+
+[[2026-07-17]] Fri 12:27
+Changed explode(':', ...) to explode(PATH_SEPARATOR, ...) in conf/init.php. PHP passes php -l.
+
+[[2026-07-17]] Fri 12:27
+P0-3 fixed. One-line change in conf/init.php. Ready for your commit.
diff --git a/kanban/tasks/013-config-hygiene-zap-debug-false-secrets-in-git.md b/kanban/tasks/013-config-hygiene-zap-debug-false-secrets-in-git.md
new file mode 100644
index 0000000..0d6ba07
--- /dev/null
+++ b/kanban/tasks/013-config-hygiene-zap-debug-false-secrets-in-git.md
@@ -0,0 +1,19 @@
+---
+id: 13
+title: 'Config hygiene: ZAP_DEBUG=false, secrets in git-ignored local file, sessions perms'
+status: done
+priority: medium
+created: 2026-07-17T03:57:13.88777683+02:00
+updated: 2026-07-17T22:27:10.989415474+02:00
+started: 2026-07-17T22:27:10.994979516+02:00
+completed: 2026-07-17T22:27:10.994979516+02:00
+tags:
+ - security
+ - config
+class: standard
+---
+
+From framework review (docs/framework_review.md), P1-1. conf/conf.php is git-tracked and ships with ZAP_DEBUG=true, BRAVE_API_KEY='your api key' placeholder. Fixes:
+- Default ZAP_DEBUG=false in committed conf.php
+- Add git-ignored conf/conf.local.php loaded by init.php if present, for secrets
+- Tighten sessions/ permissions from 777 to 770 (or document webserver-user group)
diff --git a/kanban/tasks/014-add-csrf-protection-to-word-input-form.md b/kanban/tasks/014-add-csrf-protection-to-word-input-form.md
new file mode 100644
index 0000000..1dc212c
--- /dev/null
+++ b/kanban/tasks/014-add-csrf-protection-to-word-input-form.md
@@ -0,0 +1,17 @@
+---
+id: 14
+title: Add CSRF protection to word-input form
+status: done
+priority: medium
+created: 2026-07-17T03:57:20.699057952+02:00
+updated: 2026-07-19T21:23:27.817959707+02:00
+started: 2026-07-19T21:23:27.819406405+02:00
+completed: 2026-07-19T21:23:27.819406405+02:00
+tags:
+ - security
+claimed_by: rain-raven
+claimed_at: 2026-07-19T21:23:27.817959707+02:00
+class: standard
+---
+
+From framework review (docs/framework_review.md), P1-2. tpl/index.tpl POSTs to mode=display which writes session state and triggers image downloads. No CSRF token means a cross-site request can drive the machine. Fix: add session-bound CSRF token to the form, validate in ZAPDisplay.
diff --git a/kanban/tasks/015-replace-die-wrong-parameter-with-proper-404-error.md b/kanban/tasks/015-replace-die-wrong-parameter-with-proper-404-error.md
new file mode 100644
index 0000000..0119a46
--- /dev/null
+++ b/kanban/tasks/015-replace-die-wrong-parameter-with-proper-404-error.md
@@ -0,0 +1,17 @@
+---
+id: 15
+title: Replace die('Wrong parameter') with proper 404/error handler
+status: done
+priority: medium
+created: 2026-07-17T03:57:28.297533467+02:00
+updated: 2026-07-19T20:20:20.011896223+02:00
+started: 2026-07-19T20:20:20.013282064+02:00
+completed: 2026-07-19T20:20:20.013282064+02:00
+tags:
+ - framework
+claimed_by: rain-raven
+claimed_at: 2026-07-19T20:20:20.011896223+02:00
+class: standard
+---
+
+From framework review (docs/framework_review.md), P1-3. ZAPController::__construct() calls die('Wrong parameter') when an unknown mode is given — no HTTP status, no HTML, and the polling onerror contract expects ERROR_PREFIX HTML. Fix: return a proper 404 response (or brand error page via ZAPError handler). Also consider mode allowlist.
diff --git a/kanban/tasks/016-fix-and-secure-cli-scripts-reset-php.md b/kanban/tasks/016-fix-and-secure-cli-scripts-reset-php.md
new file mode 100644
index 0000000..1932343
--- /dev/null
+++ b/kanban/tasks/016-fix-and-secure-cli-scripts-reset-php.md
@@ -0,0 +1,23 @@
+---
+id: 16
+title: Fix and secure cli_scripts/reset.php
+status: done
+priority: medium
+created: 2026-07-17T03:57:35.272402311+02:00
+updated: 2026-07-19T20:09:41.987393047+02:00
+started: 2026-07-19T20:09:41.988806323+02:00
+completed: 2026-07-19T20:09:41.988806323+02:00
+tags:
+ - cli
+ - security
+claimed_by: rain-raven
+claimed_at: 2026-07-19T20:09:41.987393047+02:00
+class: standard
+---
+
+From framework review (docs/framework_review.md), P1-4. cli_scripts/reset.php has multiple issues:
+- Case mismatch: glob('./Sessions/*') vs actual 'sessions/' directory → no-op on case-sensitive FS
+- No auth/CSRF: bare $_GET['allcollages'] == 'clear' triggers destructive unlink/rmdir
+- If web-accessible it's an unauthenticated destructive endpoint
+- Misplaced in cli_scripts/ (uses $_GET like a web script)
+Fix: correct path, add CLI guard (php_sapi_name()), gate destructive branch behind confirmation.
diff --git a/kanban/tasks/017-make-session-folder-names-unique-stop-suppressing.md b/kanban/tasks/017-make-session-folder-names-unique-stop-suppressing.md
new file mode 100644
index 0000000..746f354
--- /dev/null
+++ b/kanban/tasks/017-make-session-folder-names-unique-stop-suppressing.md
@@ -0,0 +1,17 @@
+---
+id: 17
+title: Make session folder names unique, stop suppressing mkdir errors
+status: done
+priority: medium
+created: 2026-07-17T03:57:50.884126062+02:00
+updated: 2026-07-19T19:06:58.837663313+02:00
+started: 2026-07-19T19:06:58.839287746+02:00
+completed: 2026-07-19T19:06:58.839287746+02:00
+tags:
+ - session
+claimed_by: rain-raven
+claimed_at: 2026-07-19T19:06:58.837663313+02:00
+class: standard
+---
+
+From framework review (docs/framework_review.md), P1-5. ZAP_MOMENT = date('Y-m-d-H_i_s') has second resolution. Two submissions in the same second collide on mkdir — suppressed with @, returns null folder, silently breaks all downstream operations. Fix: append random suffix to folder name, drop @, add recursive flag.
diff --git a/kanban/tasks/018-introduce-zaphandler-interface-for-getcontent.md b/kanban/tasks/018-introduce-zaphandler-interface-for-getcontent.md
new file mode 100644
index 0000000..16cde7e
--- /dev/null
+++ b/kanban/tasks/018-introduce-zaphandler-interface-for-getcontent.md
@@ -0,0 +1,18 @@
+---
+id: 18
+title: Introduce ZAPHandler interface for getContent()
+status: done
+priority: medium
+created: 2026-07-17T03:57:59.054256365+02:00
+updated: 2026-07-18T11:51:03.280085523+02:00
+started: 2026-07-18T11:51:03.281402582+02:00
+completed: 2026-07-18T11:51:03.281402582+02:00
+tags:
+ - framework
+class: standard
+---
+
+From framework review (docs/framework_review.md), P1-7. Currently getContent() is convention-only — no interface enforces it. A handler missing the method fails at runtime, not definition time. Fix: create a ZAPHandler (or ModeHandler) interface with public function getContent(), implement it on all existing handlers, add instanceof check in ZAPController.
+
+[[2026-07-18]] Sat 11:50
+Created ZAPHandler interface with getContent(), implemented on ZAPHome/ZAPDisplay/ZAPZap, added instanceof check in ZAPController::fetch().
diff --git a/kanban/tasks/019-single-source-of-truth-for-word-count-cleanup.md b/kanban/tasks/019-single-source-of-truth-for-word-count-cleanup.md
new file mode 100644
index 0000000..5d4982b
--- /dev/null
+++ b/kanban/tasks/019-single-source-of-truth-for-word-count-cleanup.md
@@ -0,0 +1,13 @@
+---
+id: 19
+title: Single source of truth for word count + cleanup handleWords
+status: todo
+priority: low
+created: 2026-07-17T03:58:05.365933671+02:00
+updated: 2026-07-17T03:58:05.365933671+02:00
+tags:
+ - cleanup
+class: standard
+---
+
+From framework review (docs/framework_review.md), P2-1/2. MAX_WORDS drives the template loop but handleWords() independently re-scans POST. Also has / typo. Fix: iterate 1..MAX_WORDS in handleWords, clean up variable naming.
diff --git a/kanban/tasks/020-consistent-template-rendering-pattern-across-all.md b/kanban/tasks/020-consistent-template-rendering-pattern-across-all.md
new file mode 100644
index 0000000..0d22f76
--- /dev/null
+++ b/kanban/tasks/020-consistent-template-rendering-pattern-across-all.md
@@ -0,0 +1,13 @@
+---
+id: 20
+title: Consistent template rendering pattern across all handlers
+status: todo
+priority: low
+created: 2026-07-17T03:58:11.987251314+02:00
+updated: 2026-07-17T03:58:11.987251314+02:00
+tags:
+ - cleanup
+class: standard
+---
+
+From framework review (docs/framework_review.md), P2-3. ZAPHome uses extract(get_object_vars()) (the documented pattern); ZAPDisplay does not — it manually declares local vars and accesses directly in the template. Pick one pattern (extract or explicit) and apply consistently.
diff --git a/kanban/tasks/021-consolidate-duplicated-screen-size-constants.md b/kanban/tasks/021-consolidate-duplicated-screen-size-constants.md
new file mode 100644
index 0000000..91ccbdd
--- /dev/null
+++ b/kanban/tasks/021-consolidate-duplicated-screen-size-constants.md
@@ -0,0 +1,17 @@
+---
+id: 21
+title: Consolidate duplicated screen-size constants
+status: done
+priority: low
+created: 2026-07-17T03:58:20.43055577+02:00
+updated: 2026-07-19T21:49:54.332882291+02:00
+started: 2026-07-19T21:49:54.33435439+02:00
+completed: 2026-07-19T21:49:54.33435439+02:00
+tags:
+ - cleanup
+claimed_by: rain-raven
+claimed_at: 2026-07-19T21:49:54.332882291+02:00
+class: standard
+---
+
+From framework review (docs/framework_review.md), P2-5. ImgIOTools and ImgTools both define $maxScreenWidth/$maxScreenHeight to the same values (1067/600). Drift risk. Consolidate into one place.
diff --git a/kanban/tasks/022-fix-convertgifstopng-extension-rename-fix-log-xml.md b/kanban/tasks/022-fix-convertgifstopng-extension-rename-fix-log-xml.md
new file mode 100644
index 0000000..a0bcc07
--- /dev/null
+++ b/kanban/tasks/022-fix-convertgifstopng-extension-rename-fix-log-xml.md
@@ -0,0 +1,19 @@
+---
+id: 22
+title: Fix convertGifsToPng extension + rename/fix log.xml
+status: done
+priority: low
+created: 2026-07-17T03:58:30.403935395+02:00
+updated: 2026-07-19T21:42:54.771387687+02:00
+started: 2026-07-19T21:42:54.772886896+02:00
+completed: 2026-07-19T21:42:54.772886896+02:00
+tags:
+ - cleanup
+claimed_by: rain-raven
+claimed_at: 2026-07-19T21:42:54.771387687+02:00
+class: standard
+---
+
+From framework review (docs/framework_review.md), P2-6/7. Two small fixes:
+1. convertGifsToPng produces cat.gif.png (appends .png instead of replacing .gif) — confusing filenames.
+2. Log writes HTML fragments () into log.xml — not valid XML. Rename to log.html or emit proper XML.
diff --git a/kanban/tasks/023-anchor-zap-app-base-dir-to-dir-make-getzaptemplate.md b/kanban/tasks/023-anchor-zap-app-base-dir-to-dir-make-getzaptemplate.md
new file mode 100644
index 0000000..8bb0a12
--- /dev/null
+++ b/kanban/tasks/023-anchor-zap-app-base-dir-to-dir-make-getzaptemplate.md
@@ -0,0 +1,19 @@
+---
+id: 23
+title: Anchor ZAP_APP_BASE_DIR to __DIR__, make getZAPTemplate throw
+status: done
+priority: low
+created: 2026-07-17T03:58:37.157613187+02:00
+updated: 2026-07-19T21:39:02.781954542+02:00
+started: 2026-07-19T21:39:02.783424942+02:00
+completed: 2026-07-19T21:39:02.783424942+02:00
+tags:
+ - cleanup
+claimed_by: rain-raven
+claimed_at: 2026-07-19T21:39:02.781954542+02:00
+class: standard
+---
+
+From framework review (docs/framework_review.md), P2-8/9. Two fixes in conf/init.php:
+1. ZAP_APP_BASE_DIR = realpath('.'.DIRECTORY_SEPARATOR.'..') is cwd-dependent — breaks if entry point is not www/ or cli_scripts/. Use realpath(__DIR__ . '/..') instead.
+2. getZAPTemplate returns ERROR_PREFIX . 'No template' string on missing file instead of throwing — inconsistent with other error paths. Make it throw.
diff --git a/kanban/tasks/024-refresh-readme-yahoo-brave-drop-outdated-roadmap.md b/kanban/tasks/024-refresh-readme-yahoo-brave-drop-outdated-roadmap.md
new file mode 100644
index 0000000..2f8f118
--- /dev/null
+++ b/kanban/tasks/024-refresh-readme-yahoo-brave-drop-outdated-roadmap.md
@@ -0,0 +1,17 @@
+---
+id: 24
+title: Refresh README (Yahoo→Brave, drop outdated roadmap, fix tone)
+status: done
+priority: low
+created: 2026-07-17T03:58:43.662424712+02:00
+updated: 2026-07-19T21:31:14.516637296+02:00
+started: 2026-07-19T21:31:14.51815456+02:00
+completed: 2026-07-19T21:31:14.51815456+02:00
+tags:
+ - docs
+claimed_by: rain-raven
+claimed_at: 2026-07-19T21:31:14.516637296+02:00
+class: standard
+---
+
+From framework review (docs/framework_review.md), P2-11. README.md still says 'the most relevant image that search engine Yahoo comes up with', tells Windows users 'Windows suck', and lists a roadmap that doesn't map to kanban. Refresh prose to match current state (Brave search, no Yahoo).
From 3edb156749844de83627711f22c95d2b8b232f4b Mon Sep 17 00:00:00 2001
From: Fabian de Boer
Date: Mon, 20 Jul 2026 01:14:00 +0200
Subject: [PATCH 09/10] clean up code in ZapHome and ZapDisplay (#19 and #20)
---
kanban/activity.jsonl | 6 ++++++
...ingle-source-of-truth-for-word-count-cleanup.md | 8 ++++++--
...istent-template-rendering-pattern-across-all.md | 8 ++++++--
lib/ZAPDisplay.class.php | 14 +++++---------
lib/ZAPHome.class.php | 9 +--------
5 files changed, 24 insertions(+), 21 deletions(-)
diff --git a/kanban/activity.jsonl b/kanban/activity.jsonl
index 1453eab..0aab3a4 100644
--- a/kanban/activity.jsonl
+++ b/kanban/activity.jsonl
@@ -85,3 +85,9 @@
{"timestamp":"2026-07-19T21:49:54.312195218+02:00","action":"edit","task_id":21,"detail":"Consolidate duplicated screen-size constants"}
{"timestamp":"2026-07-19T21:49:54.312297605+02:00","action":"claim","task_id":21,"detail":"rain-raven"}
{"timestamp":"2026-07-19T21:49:54.334491216+02:00","action":"move","task_id":21,"detail":"todo -\u003e done"}
+{"timestamp":"2026-07-19T22:54:27.983080764+02:00","action":"edit","task_id":20,"detail":"Consistent template rendering pattern across all handlers"}
+{"timestamp":"2026-07-19T22:54:27.98319541+02:00","action":"claim","task_id":20,"detail":"rain-raven"}
+{"timestamp":"2026-07-19T22:54:28.007952955+02:00","action":"move","task_id":20,"detail":"todo -\u003e done"}
+{"timestamp":"2026-07-20T01:09:23.947300407+02:00","action":"edit","task_id":19,"detail":"Single source of truth for word count + cleanup handleWords"}
+{"timestamp":"2026-07-20T01:09:23.947430566+02:00","action":"claim","task_id":19,"detail":"rain-raven"}
+{"timestamp":"2026-07-20T01:09:23.97076796+02:00","action":"move","task_id":19,"detail":"todo -\u003e done"}
diff --git a/kanban/tasks/019-single-source-of-truth-for-word-count-cleanup.md b/kanban/tasks/019-single-source-of-truth-for-word-count-cleanup.md
index 5d4982b..c0685a6 100644
--- a/kanban/tasks/019-single-source-of-truth-for-word-count-cleanup.md
+++ b/kanban/tasks/019-single-source-of-truth-for-word-count-cleanup.md
@@ -1,12 +1,16 @@
---
id: 19
title: Single source of truth for word count + cleanup handleWords
-status: todo
+status: done
priority: low
created: 2026-07-17T03:58:05.365933671+02:00
-updated: 2026-07-17T03:58:05.365933671+02:00
+updated: 2026-07-20T01:09:23.968637294+02:00
+started: 2026-07-20T01:09:23.970603129+02:00
+completed: 2026-07-20T01:09:23.970603129+02:00
tags:
- cleanup
+claimed_by: rain-raven
+claimed_at: 2026-07-20T01:09:23.968637294+02:00
class: standard
---
diff --git a/kanban/tasks/020-consistent-template-rendering-pattern-across-all.md b/kanban/tasks/020-consistent-template-rendering-pattern-across-all.md
index 0d22f76..9dd7b1d 100644
--- a/kanban/tasks/020-consistent-template-rendering-pattern-across-all.md
+++ b/kanban/tasks/020-consistent-template-rendering-pattern-across-all.md
@@ -1,12 +1,16 @@
---
id: 20
title: Consistent template rendering pattern across all handlers
-status: todo
+status: done
priority: low
created: 2026-07-17T03:58:11.987251314+02:00
-updated: 2026-07-17T03:58:11.987251314+02:00
+updated: 2026-07-19T22:54:28.006158702+02:00
+started: 2026-07-19T22:54:28.007766996+02:00
+completed: 2026-07-19T22:54:28.007766996+02:00
tags:
- cleanup
+claimed_by: rain-raven
+claimed_at: 2026-07-19T22:54:28.006158702+02:00
class: standard
---
diff --git a/lib/ZAPDisplay.class.php b/lib/ZAPDisplay.class.php
index 65656e9..3be56b0 100755
--- a/lib/ZAPDisplay.class.php
+++ b/lib/ZAPDisplay.class.php
@@ -80,15 +80,11 @@ class ZAPDisplay implements ZAPHandler {
*/
private function handleWords() {
$words = array();
- $ix = 1;
- $postix = sprintf("%02d", $ix);
- $wd = 'word' . $postix;
-
- while(!empty($_POST[$wd])) {
- array_push($words, $_POST[$wd]);
- $ix++;
- $postfix = sprintf("%02d", $ix);
- $wd = 'word' . $postfix;
+ for ($i = 1; $i <= MAX_WORDS; $i++) {
+ $key = 'word' . sprintf("%02d", $i);
+ if (!empty($_POST[$key])) {
+ $words[] = $_POST[$key];
+ }
}
return $words;
}
diff --git a/lib/ZAPHome.class.php b/lib/ZAPHome.class.php
index 21de450..207b0f8 100755
--- a/lib/ZAPHome.class.php
+++ b/lib/ZAPHome.class.php
@@ -8,11 +8,6 @@ class ZAPHome implements ZAPHandler {
*/
private $template = 'index';
- /**
- * ZAP version
- */
- private $ver;
-
/**
* Parsable content
*/
@@ -22,10 +17,8 @@ class ZAPHome implements ZAPHandler {
* Constructor
*/
public function __construct() {
- $this->ver = ZAP_VERSION;
- extract(get_object_vars($this));
-
ob_start();
+ $ver = ZAP_VERSION;
include getZAPTemplate($this->template);
$this->tpl .= ob_get_clean();
}
From 42cfff87d030189e45569973d2bf14fe2c09bd24 Mon Sep 17 00:00:00 2001
From: Fabian de Boer
Date: Mon, 20 Jul 2026 14:35:35 +0200
Subject: [PATCH 10/10] optimize framework: ready to merge and release 0.9.0
---
.gitignore | 1 -
docs/framework_review.md | 39 +++++++++++++++++++
kanban/activity.jsonl | 2 +
...request-building-lazy-url-single-encode.md | 6 ++-
...utoloader-use-path-separator-instead-of.md | 6 ++-
5 files changed, 49 insertions(+), 5 deletions(-)
create mode 100644 docs/framework_review.md
diff --git a/.gitignore b/.gitignore
index b9c4024..532dbc8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,3 @@ sessions/*
conf/conf.local.php
ignore
.pi-tasks
-docs/framework_review.md
diff --git a/docs/framework_review.md b/docs/framework_review.md
new file mode 100644
index 0000000..2865e02
--- /dev/null
+++ b/docs/framework_review.md
@@ -0,0 +1,39 @@
+# ZAP Framework Review
+
+Task #10 — *“Check if the framework is the optimal, most simple and flexible way to go. If not: suggest some changes.”*
+
+This review audits the internal ZapMachine PHP framework (documented in `docs/framework_guide.md`) against three criteria — **optimal**, **simple**, and **flexible** — based on a full read of the current source on branch `optimize-framework` (commit `d971512`).
+
+**Scope:** audit + recommendations only. **No source files are modified in this deliverable.** Every recommendation below is a proposal that should get its own kanban task and separate approval before implementation.
+
+---
+
+## Verdict
+
+The framework’s **architecture is genuinely simple and flexible** for its scope. Adding a new page (`?mode=`) is a one-class + one-template operation with zero registration. Adding a new search engine is a one-class operation behind a clean interface. PHP-native templating means no build step and no engine dependency. These are real strengths and should be preserved.
+
+It is **not optimal**, however, because:
+
+1. **Three P0 correctness bugs** silently degrade the core search pipeline (Brave `size`/`offset` params never sent; query double-URL-encoded; autoloader path split hardcodes `':'`).
+2. **Unsafe / committed config defaults** (`ZAP_DEBUG=true`, placeholder API key in git-tracked `conf/conf.php`, `chmod 777`).
+3. **Several loose abstraction boundaries** make the “framework contract” described in the guide looser than the code actually enforces (no `ZAPHandler` interface, inconsistent `extract()` template pattern, raw `$_SESSION` access beside a `Session` wrapper).
+
+None of these require replacing the architecture. They are bug fixes, a config-hygiene pass, and a few small interface tightenings. Recommended effort: a handful of small, well-scoped tasks — **not** a rewrite.
+
+---
+
+
+## Strengths worth preserving
+
+| Aspect | Why it’s good |
+|---|---|
+| Front-controller + naming convention (`ZAP` + ucfirst(mode)) | Zero-config routing. A new mode = one class in `lib/` + one `.tpl`. No route table, no registration. Very flexible, very simple. (`lib/ZAPController.class.php`) |
+| `spl_autoload_register` over the include path | No manual `require_once` for library classes; drop a `.class.php` in the right dir and it loads. (`conf/init.php`) |
+| `Search` interface plugin system | Engines are interchangeable behind a 3-method contract and a universal result-array shape. Adding `Pixabay`/`Pexels` (tasks #1/#2) is a clean drop-in. (`resource/Search.interface.php`, `resource/Brave.class.php`) |
+| PHP-native templates (`ob_start`/`include`/`extract`/`ob_get_clean`) | No template engine, no compilation step, no extra dependency. Simplest possible rendering. |
+| `Config` singleton | Decouples runtime config (e.g. registered engines) from individual classes. (`conf/Config.class.php`) |
+| Clear layering | routing / handlers / search / imaging / utils are in separate dirs with single responsibilities. |
+
+These answer the “simple and flexible” part of the brief affirmatively. The rest of this document is about getting to “optimal.”
+
+---
diff --git a/kanban/activity.jsonl b/kanban/activity.jsonl
index 0aab3a4..3352de4 100644
--- a/kanban/activity.jsonl
+++ b/kanban/activity.jsonl
@@ -91,3 +91,5 @@
{"timestamp":"2026-07-20T01:09:23.947300407+02:00","action":"edit","task_id":19,"detail":"Single source of truth for word count + cleanup handleWords"}
{"timestamp":"2026-07-20T01:09:23.947430566+02:00","action":"claim","task_id":19,"detail":"rain-raven"}
{"timestamp":"2026-07-20T01:09:23.97076796+02:00","action":"move","task_id":19,"detail":"todo -\u003e done"}
+{"timestamp":"2026-07-20T14:15:55.814485137+02:00","action":"move","task_id":12,"detail":"review -\u003e done"}
+{"timestamp":"2026-07-20T14:15:59.830512648+02:00","action":"move","task_id":11,"detail":"review -\u003e done"}
diff --git a/kanban/tasks/011-fix-brave-request-building-lazy-url-single-encode.md b/kanban/tasks/011-fix-brave-request-building-lazy-url-single-encode.md
index 5f2c2cc..88f61cc 100644
--- a/kanban/tasks/011-fix-brave-request-building-lazy-url-single-encode.md
+++ b/kanban/tasks/011-fix-brave-request-building-lazy-url-single-encode.md
@@ -1,10 +1,12 @@
---
id: 11
title: 'Fix Brave request building: lazy URL + single encode'
-status: review
+status: done
priority: high
created: 2026-07-17T03:57:00.444816503+02:00
-updated: 2026-07-17T12:26:38.759875442+02:00
+updated: 2026-07-20T14:15:59.825243496+02:00
+started: 2026-07-20T14:15:59.830054903+02:00
+completed: 2026-07-20T14:15:59.830054903+02:00
tags:
- search
- bug
diff --git a/kanban/tasks/012-fix-autoloader-use-path-separator-instead-of.md b/kanban/tasks/012-fix-autoloader-use-path-separator-instead-of.md
index 211a40d..54fd574 100644
--- a/kanban/tasks/012-fix-autoloader-use-path-separator-instead-of.md
+++ b/kanban/tasks/012-fix-autoloader-use-path-separator-instead-of.md
@@ -1,10 +1,12 @@
---
id: 12
title: 'Fix autoloader: use PATH_SEPARATOR instead of hardcoded '':'''
-status: review
+status: done
priority: high
created: 2026-07-17T03:57:06.82901804+02:00
-updated: 2026-07-17T12:27:53.056263524+02:00
+updated: 2026-07-20T14:15:55.809367918+02:00
+started: 2026-07-20T14:15:55.814059562+02:00
+completed: 2026-07-20T14:15:55.814059562+02:00
tags:
- framework
- bug