Commit Graph
3 Commits
Author SHA1 Message Date
Kristian WindandClaude Opus 5 afc46a5c20 fix(api): do the things the API says yes to
Release / Build and publish image (push) Failing after 9m58s
Three reports from somebody driving the app through the MCP connector,
all the same shape: an argument accepted, an OK returned, and nothing
done.

**project_id on an update never moved the task.** Both the REST handler
and the MCP tool read it, both checked the caller's rights on the
destination — which reads as "understood" — and then neither passed it
on, because store.TaskUpdate has no such field: a project change is a
move, since sort_order is per project. So the task stayed where it was
and the answer said OK. Moving a task between projects was impossible
except by creating it again and closing the old one, which is what the
person ended up doing. Both paths now go through one helper, so they
cannot drift apart again.

**An unknown #project vanished without a word.** The parser reads
"#3Dekoration" correctly; the lookup then fails, the task goes to the
Inbox, and the name is gone from the title with nothing anywhere saying
why. Still not an error — a thought should not be thrown away over a typo
— but quick-add now returns unknown_project, and the MCP tool returns a
note written for a model to relay. The old behaviour was kind in the web
interface, where you see the row appear in the wrong place and fix it. In
a chat nobody sees the row.

**Sub-tasks were unreachable over MCP.** create_task had no parent_id,
though the REST API has had it all along, so importing a parent with
seven children produced eight unrelated tasks with the parent's name
prefixed onto each. A sub-task joins its parent's project — the two
cannot disagree — and a second level is refused rather than silently
flattened.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 16:24:58 +02:00
Kristian WindandClaude Opus 5 a96aae57ec feat(recurrence): repeating tasks as RRULE, in Danish and English
"vand planterne hver mandag" becomes FREQ=WEEKLY;BYDAY=MO. The stored
form is RFC 5545, not a private format, so the same field will drive the
CalDAV server and the ICS feed without a translation layer.

Ticking off a repeating task advances it instead of closing it, keeping
the same row — so its sub-tasks and comments stay attached. A weekly
review is one thing that recurs, not fifty-two things. The clock time
survives the move, and the completion is still written to the activity
log, because "what did I get done this week" has to include the chores
that repeat.

Recurrence is parsed before dates, and that ordering is load-bearing:
"hver mandag" contains a weekday, so a date parser reading it first
would claim Monday as a one-off and strand "hver" in the title. It is
also resolved before the time-only case, or "hver mandag kl 9" typed
after nine would land tomorrow morning instead of on Monday.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 06:53:00 +02:00
Kristian WindandClaude Opus 5 dff86dd23d feat(api): projects, sections, tasks, quick add, views and live sync
Completes the MVP surface: project and section CRUD, task CRUD with
sub-trees, drag-and-drop ordering, the quick-add endpoint over the
natural-language parser, Today and Upcoming, search, sharing with roles,
an activity log and a WebSocket for live updates.

Permission checks are route middleware rather than a first line in each
handler, so an endpoint is guarded by where it sits instead of by the
author remembering. Anything the caller may not see answers 404, never
403 — a 403 confirms the thing exists. Visibility is enforced inside the
list query, so another user's project cannot be reached by filtering or
searching at it.

Ordering is a float, so a drop writes one row instead of renumbering the
list. When repeated drops into one gap exhaust the precision, the
section is spread out again and the move retried — in a separate
transaction, since the attempt that discovered the problem rolls back.

The connection pool is not 1: a single connection makes the pool a lock,
and a query run while an earlier result set is still open then waits for
a connection it is itself holding. The store now closes its rows before
querying again, and the pool leaves that mistake slow rather than fatal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 23:44:55 +02:00