Vikunja
Crate: adapter-vikunja · Capabilities: tasks
Vikunja is an open-source, self-hosted task manager. The adapter is tasks-only and is one of the two “collaborative tasks” backends (assignment + membership), alongside Todoist.
Authentication
Section titled “Authentication”A personal API token the user mints in Vikunja, sent as a Bearer
token. The server base URL is user-supplied (self-hosted or hosted
instance).
Data model mapping
Section titled “Data model mapping”- Projects → task lists. Projects nest via
parent_project_id(surfaced asTaskList.parent_id), so the sidebar renders the tree. - Buckets → sections (per-project kanban view); degrades to “no sections” on servers that don’t expose the view/bucket endpoints.
- Tasks:
start_date/due_datemap onto Aperio’sscheduled_*/deadline_*. Vikunja uses an RFC-3339 sentinel (0001-01-01T…) for “no date” — treated as unset on read, emitted on write when a slot is empty. - Priority maps by label: Vikunja 1/2/3 (Low/Medium/High) ↔ Aperio Low/Medium/High. Unset (0) reads as Low; Urgent (4) and DO NOW (5) collapse to High and write back as High (3) — Aperio has only three levels.
- Status / in-progress. Vikunja has no boolean “in progress”, only
done+percent_done. Aperio ridespercent_done: Completed →done = true; InProgress →done = false,percent_done = 0.5; Open →done = false,percent_done = 0. On read a not-done task with any progress is InProgress, so a task nudged to e.g. 50% in Vikunja’s own UI round-trips too, and the three-step check-off works (supports_in_progress: true). Cancelled has no Vikunja equivalent (done = false,percent_done = 0) — the marker stays local. - Subtasks are task relations, not a task field: the child’s
parenttaskrelation (PUT /tasks/{child}/relations, removed viaDELETE /tasks/{child}/relations/parenttask/{parent}) maps ontoTask.parent_id; reads take the first non-zerorelated_tasks.parenttaskentry. Updates reconcile against an authoritativeGET /tasks/{id}— Vikunja populatesrelated_tasksonly on reads, never on the update echo — unlink every stale parent (Vikunja allows several), and treat PUT→409 (already linked) / DELETE→404 (already gone) as success.
Collaboration (assignment + membership)
Section titled “Collaboration (assignment + membership)”- Assignees (multi): read inline on the task; written via the bulk
endpoint
POST …/tasks/{id}/assignees/bulk(replace-semantics — the full desired set). The assigneeTaskUser.idis the numeric user id. - Member pool for the picker:
GET /projects/{id}/projectusers. - Own identity (“me”):
GET /user. - Membership/sharing:
GET /projects/{id}/userslists direct shares with rights (read/write/admin → 0/1/2); add/remove/change-right viaPUT/DELETE/POSTon/projects/{id}/users(Vikunja quirk: PUT = create, POST = update). Sharing is immediate to existing users — no invitation flow. Membership keys on the username, distinct from the numeric-id assignee key. - User search:
GET /users?s=for the add-member dialog.
Testing
Section titled “Testing”mockito with canned Vikunja JSON and the project/page pagination headers.
Tests cover list/project mapping, the date sentinel, the bucket→section
fallback, and the assignee/membership endpoints. Live testing: any Vikunja
instance with an API token.