4.3 KiB
4.3 KiB
| summary | tags | scope | source | date | last_updated | ||||
|---|---|---|---|---|---|---|---|---|---|
| Planka v2.1.1 API and Docker behaviors that differ from or are absent in its docs — auth/PAT limits, first-login terms flow, card-move and project-delete quirks, container uid — plus service-account credentials location for planka.hyperthrive.io. |
|
global | ovh-prod Planka deploy, 2026-07-08 | 2026-07-08 | 2026-07-10 |
Planka v2 API Gotchas (verified on v2.1.1)
Discovered during the ovh-prod deploy (2026-07-08), verified against a live v2.1.1 instance.
Directly relevant to the backlog CLI in ~/dev/ruby-gems and any Planka automation.
- No scoped API keys / PATs. Only
POST /api/access-tokenswith{emailOrUsername, password}→ bearer JWT. Upstream issue #945 still open as of v2.1.1. Automation must hold real user credentials; a scoped-token proxy is the workaround. - First-ever login requires terms acceptance. The first
POST /api/access-tokensreturnsE_FORBIDDENwith apendingTokenandstep: "accept-terms". Flow:GET /api/terms→ takeitem.signature→POST /api/access-tokens/accept-termswith{pendingToken, signature}→ real token. Subsequent logins are normal. - Card move needs both fields.
PATCH /api/cards/:idrequires bothlistIdandposition;listIdalone returnsE_MISSING_OR_INVALID_PARAMS. - Project delete is not cascading.
DELETE /api/projects/:idreturns 422"Must not have boards"— delete each board first. The web UI hits the same constraint but fails silently: the project vanishes locally, then reappears on reload with no error shown (confirmed 2026-07-10 on the personal-account project). A non-manager attempting the delete gets a 404 (existence hidden, same as gotcha #6). Escape hatch when no manager creds are at hand: insert a row intoproject_managerdirectly in Postgres (docker exec planka-postgres psql -U planka), then delete boards + project via the API as that user. - Sails literal-alias routes. Some delete routes embed a literal parameter-name
segment: card-label detach is
DELETE /api/cards/:cardId/card-labels/labelId::labelId(the path literally containslabelId:before the id). Normal REST-shaped guesses 404. When a route 404s unexpectedly, checkserver/config/routes.jsin the Planka source. Related:GET /api/tasks/:iddoesn't exist (404s to SPA HTML — check Content-Type); cross-board card move needsboardIdin the PATCH on top oflistId+position. - Webhooks are instance-level and admin-only.
GET/POST /api/webhooksetc.; a non-admin gets 404 (Sails hides existence, not 403). Not board/project-scoped;eventsare comma-separated strings in, arrays out. - Attachment download auth differs.
GET /attachments/:id/download/:filename(outside/api) authenticates viaCookie: accessToken=<jwt>(orx-api-key) —Authorization: Bearer401s on this route. Also means VCR/webmock setups must filter Cookie headers, not just Authorization, or the JWT leaks into cassettes. - Container uid. The
ghcr.io/plankanban/plankaimage runs as uid 1000 (node). A bind-mounted/app/datamust bechown 1000or attachment/avatar uploads fail (container starts healthy either way — the failure is silent until first upload).
Service accounts (planka.hyperthrive.io)
Created 2026-07-08 because of gotcha #1 (no PATs — automation holds real user creds).
Credentials live on the OVH server (ssh alias ovh-vps) at
~/services/planka/bot-credentials.env (mode 600); admin creds remain in
~/services/planka/.env. Copy to Bitwarden.
planka_bot— roleprojectOwner; for the planka-api gem /backlogCLI / cron tick. Env vars:PLANKA_BASE_URL,PLANKA_USERNAME,PLANKA_PASSWORD.hermes— roleboardUser(deliberately restricted; Hermes agent is less trusted). Env vars:HERMES_PLANKA_USERNAME,HERMES_PLANKA_PASSWORD.- Usernames must match
/^[a-zA-Z0-9]+((_|\.)?[a-zA-Z0-9])*$/— no hyphens (henceplanka_bot, notplanka-bot).
Deploy as-built details live in the repo: ovh-prod/docs/planka-deploy-prd.md.
Related: vault-backlog-pilot-plan, backlog-system-options-research.