Skip to content

Commit 4ec254c

Browse files
LouisOuelletclaude
andcommitted
Add: Priority levels and activity tracking for agent-operable tasks
- Add priority column to tasks table (low=-1, medium=0, high=1, critical=2) - Add priority-aware ordering (high priority first) to task queries - Create task_activity table for per-task event tracking (status changes, reassignments, priority changes, creation, deletion) - Add TaskActivityRepository with logEvent, findByTask, findRecent, findForUser methods extending OrganizationScopedRepository - Wire activity logging into TaskService (automatic on create/update/delete) - Add priority constants and normalization to TaskService - Wire activity repo into TaskController create/update/edit/delete - Add 38 assertions for priority and activity testing - Update DESIGN.md, organizations.md, ROADMAP.md, and README.md Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 9cf8f2d commit 4ec254c

11 files changed

Lines changed: 841 additions & 23 deletions

DESIGN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,7 @@ After the NetMon cleanup pass, the kernel contains:
929929

930930
### Plugins (Extracted from Core)
931931
- **Notes** (`lib/plugins/notes/`) — polymorphic note annotations (first real plugin)
932-
- **Tasks** (`lib/plugins/tasks/`) — polymorphic task management (second real plugin)
932+
- **Tasks** (`lib/plugins/tasks/`) — polymorphic task management with priority (low/medium/high/critical), activity tracking (status changes, reassignments, etc.), assignment model, execution hooks, and scheduling (second real plugin)
933933

934934
### Plugin Migrations
935935
- Plugin migrations run via `SetupService::runPluginMigrations()` during install.

ROADMAP.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ Kernel-Web V1.0 is a stable, self-hostable kernel suitable for building one busi
148148
- [P2] Migrate remaining DB-backed config to ConfigOverrideService
149149
- [x] Multi-tenant data scoping — Repository interface, data model scoping, and middleware/auto-scoping completed
150150
- [P2] Kernel update system (download + apply workflow)
151-
- [P2] Agent-operable task foundation (shared task/activity model)
151+
- [x] Agent-operable task foundation (shared task/activity model)
152152
- [P2] API/action contract conventions (safe agent-callable operations)
153153
- [P3] Make 2FA methods extensible
154154
- [P3] Disable 2FA for users with no selected method
@@ -228,7 +228,7 @@ These are planned but explicitly out of scope for V1.0. They are major systems t
228228
These are the highest-impact items that should be addressed next:
229229

230230
1. **P2: Multi-tenant data scoping** — Organization-level query filtering middleware and repository conventions. This unlocks proper business-app and SaaS-style usage.
231-
2. **P2: Agent-operable task foundation**Core task/activity model usable by humans and AI agents. Should support assignment, status, priority, due dates, links to entities, and audit history.
231+
2. **P2: API/action contract conventions**Define how plugins expose safe agent-callable actions through controllers/services with permission checks and audit logging.
232232
3. **P2: API/action contract conventions** — Define how plugins expose safe agent-callable actions through controllers/services with permission checks and audit logging.
233233
4. **P2: Migrate remaining DB-backed config to ConfigOverrideService** — Complete config/local.php-backed settings migration for non-sensitive instance config.
234234
5. **P2: Kernel update system** — Version check exists; needs download and apply workflow.

lib/plugins/tasks/README.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ Polymorphic task management — create, assign, track, and link tasks to any dom
1010
lib/plugins/tasks/
1111
├── plugin.json — manifest (routes, services, hooks, menus)
1212
├── src/
13-
│ ├── TaskController.php — HTTP endpoints
14-
│ ├── TaskService.php — Validation and business logic
15-
│ └── TaskRepository.php — Database queries
13+
│ ├── TaskController.php — HTTP endpoints
14+
│ ├── TaskService.php — Validation and business logic
15+
│ ├── TaskRepository.php — Database queries
16+
│ └── TaskActivityRepository.php — Task activity/event tracking
1617
├── routes.php — Manual route registration (optional)
17-
├── migrations/ — 9 migration files (create table → schedule fields)
18+
├── migrations/ — 11 migration files (create table → activity tracking)
1819
├── views/
1920
│ ├── index.php — Task list with scope filters
2021
│ ├── create.php — Create task form
@@ -87,6 +88,8 @@ Registered in the container under `tasks.service`:
8788
- Cron task execution requires a separate scheduler process
8889
- No subtask support (parent_id column reserved)
8990
- Reminder system is query-ready but delivery requires a notification backend
91+
- Priority uses integer weights (-1 to 2); no custom labels per-organization
92+
- Activity log is append-only; there is no edit or delete event
9093

9194
## Migration Status
9295

@@ -103,3 +106,5 @@ All 9 migrations are included in the plugin:
103106
| 0036 | drop_tasks_assigned_user_id.php | Remove deprecated assigned_user_id column |
104107
| 0037 | add_task_execution_tracking.php | last_run_at, last_run_status, last_run_message |
105108
| 0043 | add_task_schedule_fields.php | schedule_type, schedule_value |
109+
| 0056 | add_task_priority.php | priority column (low=-1, medium=0, high=1, critical=2) |
110+
| 0057 | create_task_activity_table.php | task_activity table for per-task event tracking |
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
<?php
2+
3+
use App\Core\Migration;
4+
5+
/**
6+
* Add priority column to tasks table.
7+
*
8+
* Priority values:
9+
* -1 = low
10+
* 0 = medium (default)
11+
* 1 = high
12+
* 2 = critical
13+
*
14+
* Tasks with higher priority are sorted before lower-priority tasks
15+
* in the default task list ordering.
16+
*
17+
* Migration number: 0056
18+
*/
19+
class AddTaskPriority extends Migration
20+
{
21+
public function up(): void
22+
{
23+
$this->db->execute('ALTER TABLE tasks ADD COLUMN priority INTEGER NOT NULL DEFAULT 0');
24+
$this->db->execute(
25+
'CREATE INDEX IF NOT EXISTS tasks_priority ON tasks (priority)'
26+
);
27+
}
28+
29+
public function down(): void
30+
{
31+
// SQLite < 3.35.0 cannot DROP COLUMN. Recreate the table.
32+
$pdo = $this->db->pdo();
33+
34+
$pdo->exec("
35+
CREATE TABLE tasks_new (
36+
id INTEGER NOT NULL,
37+
title VARCHAR(255) NOT NULL,
38+
description TEXT,
39+
status VARCHAR(32) NOT NULL DEFAULT 'open',
40+
due_at VARCHAR(32),
41+
entity_type VARCHAR(64),
42+
entity_id INTEGER,
43+
created_by_user_id INTEGER,
44+
created_at VARCHAR(32) NOT NULL,
45+
updated_at VARCHAR(32) NOT NULL,
46+
reminder_due_sent_at VARCHAR(32),
47+
reminder_overdue_sent_at VARCHAR(32),
48+
deleted_at VARCHAR(32),
49+
assigned_type TEXT,
50+
assigned_id INTEGER,
51+
execution_type TEXT,
52+
execution_payload TEXT,
53+
last_run_at VARCHAR(32),
54+
last_run_status VARCHAR(32),
55+
last_run_message TEXT,
56+
schedule_type VARCHAR(32),
57+
schedule_value TEXT,
58+
organization_id INTEGER,
59+
60+
PRIMARY KEY (id),
61+
FOREIGN KEY (created_by_user_id) REFERENCES users(id) ON DELETE SET NULL
62+
)
63+
");
64+
65+
$pdo->exec("
66+
INSERT INTO tasks_new
67+
(id, title, description, status, due_at,
68+
entity_type, entity_id, created_by_user_id,
69+
created_at, updated_at,
70+
reminder_due_sent_at, reminder_overdue_sent_at, deleted_at,
71+
assigned_type, assigned_id, execution_type, execution_payload,
72+
last_run_at, last_run_status, last_run_message,
73+
schedule_type, schedule_value, organization_id)
74+
SELECT
75+
id, title, description, status, due_at,
76+
entity_type, entity_id, created_by_user_id,
77+
created_at, updated_at,
78+
reminder_due_sent_at, reminder_overdue_sent_at, deleted_at,
79+
assigned_type, assigned_id, execution_type, execution_payload,
80+
last_run_at, last_run_status, last_run_message,
81+
schedule_type, schedule_value, organization_id
82+
FROM tasks
83+
");
84+
85+
$pdo->exec('DROP TABLE tasks');
86+
$pdo->exec('ALTER TABLE tasks_new RENAME TO tasks');
87+
88+
$pdo->exec('CREATE INDEX IF NOT EXISTS tasks_entity ON tasks (entity_type, entity_id)');
89+
$pdo->exec('CREATE INDEX IF NOT EXISTS tasks_created_by_user_id ON tasks (created_by_user_id)');
90+
$pdo->exec('CREATE INDEX IF NOT EXISTS tasks_status ON tasks (status)');
91+
$pdo->exec('CREATE INDEX IF NOT EXISTS tasks_due_at ON tasks (due_at)');
92+
$pdo->exec('CREATE INDEX IF NOT EXISTS tasks_deleted_at ON tasks (deleted_at)');
93+
$pdo->exec('CREATE INDEX IF NOT EXISTS tasks_assigned_type ON tasks (assigned_type, assigned_id)');
94+
}
95+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
use App\Core\Migration;
4+
5+
/**
6+
* Create task_activity table for per-task event tracking.
7+
*
8+
* Each row records a discrete event on a task (status change, reassignment,
9+
* priority change, creation, etc.). This provides an audit trail for the
10+
* task lifecycle, distinct from the admin_audit_log which logs all system-wide
11+
* admin actions.
12+
*
13+
* Event types:
14+
* task_created — task was created
15+
* status_changed — status was changed
16+
* assigned — task was assigned or reassigned
17+
* priority_changed — priority was changed
18+
* completed — task was completed
19+
* canceled — task was canceled
20+
* deleted — task was soft-deleted
21+
*
22+
* Migration number: 0057
23+
*/
24+
class CreateTaskActivityTable extends Migration
25+
{
26+
public function up(): void
27+
{
28+
$this->db->pdo()->exec(
29+
"CREATE TABLE IF NOT EXISTS task_activity (
30+
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
31+
task_id INTEGER NOT NULL,
32+
event_type VARCHAR(32) NOT NULL,
33+
user_id INTEGER NULL,
34+
old_value TEXT,
35+
new_value TEXT,
36+
meta TEXT NOT NULL DEFAULT '{}',
37+
created_at VARCHAR(32) NOT NULL,
38+
FOREIGN KEY (task_id) REFERENCES tasks(id) ON DELETE CASCADE,
39+
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL
40+
)"
41+
);
42+
43+
$this->db->execute(
44+
'CREATE INDEX IF NOT EXISTS task_activity_task_id ON task_activity (task_id)'
45+
);
46+
$this->db->execute(
47+
'CREATE INDEX IF NOT EXISTS task_activity_created_at ON task_activity (created_at DESC)'
48+
);
49+
$this->db->execute(
50+
'CREATE INDEX IF NOT EXISTS task_activity_event_type ON task_activity (event_type)'
51+
);
52+
}
53+
54+
public function down(): void
55+
{
56+
$this->db->pdo()->exec('DROP TABLE IF EXISTS task_activity');
57+
}
58+
}

lib/plugins/tasks/plugin.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@
2727
"migrations/0035_backfill_task_assignment_model.php",
2828
"migrations/0036_drop_tasks_assigned_user_id.php",
2929
"migrations/0037_add_task_execution_tracking.php",
30-
"migrations/0043_add_task_schedule_fields.php"
30+
"migrations/0043_add_task_schedule_fields.php",
31+
"migrations/0056_add_task_priority.php",
32+
"migrations/0057_create_task_activity_table.php"
3133
],
3234
"services": {
3335
"tasks.service": {

0 commit comments

Comments
 (0)