Plane connector¶
Built-in plane connector. Floh stays the ticket of record. A Plane work item is created only when a catalog (or other) workflow includes an explicit connector step: type plane, command createWorkItem. There is no automatic create on every Floh ticket, and there is no inbound sync from Plane in this story.
Connection fields¶
| Field | Required | Notes |
|---|---|---|
baseUrl |
no | Default https://api.plane.so. Self-hosted: https://{host} or https://{host}/api/v1. No embedded credentials. Private/RFC1918 hosts require allowPrivateNetworkEndpoint. |
apiKey |
yes | Plane personal access token. Encrypted at rest. Sent only as X-API-Key. Never logged or returned in API errors. |
workspaceSlug |
yes | Plane workspace slug. |
projectId |
yes | Plane project UUID that receives work items. |
stateMap |
no | Optional JSON map of Floh ticket status → Plane state UUID. Unused on create; reserved if product later asks for outbound status. |
allowPrivateNetworkEndpoint |
no | Allow baseUrl to target localhost / RFC1918 / Docker-internal hosts. |
Do not put a webhook secret on this connector. Inbound HMAC webhooks are parked (LSA-9895) — Phase 3 v1 is one-way and opt-in.
Commands¶
| Command | Purpose |
|---|---|
test |
Probe the configured workspace and project with the PAT. |
createWorkItem |
Create (or adopt on 409) a work item keyed by Floh ticket id. This is the catalog path. |
listStates |
List project states (for operators preparing a future stateMap). |
Catalog setup¶
- Create a built-in connector instance of type
planeand fill PAT / workspace / project. Use Test to confirm. - On the catalog workflow, keep
create_ticketso a Floh ticket is created. - Add a Connector step after
create_ticket(or rely on the reserved{{ticket.*}}snapshot injected at catalog submit): - Connector: the
planeinstance - Command:
createWorkItem name: e.g.{{title}}(or the form field that holds the request title)description: optionalpriority: optional (criticalmaps to Planeurgent)externalId:{{ticket.id}}ticketNumber:{{ticket.ticketNumber}}
The engine overwrites interpolated externalId / ticketNumber from the reserved {{ticket.*}} snapshot before calling Plane. A caller-controlled binding cannot attach the link to another Floh ticket. Missing or non-UUID ticket.id fails the step with no outbound POST.
If a plane row already exists for that Floh ticket, the step completes with the stored Plane id / key and does not call Plane again.
On success the step writes ticket_external_link including a snapshot browser URL from the connector config at create time. Later edits to the connector's workspace or project do not rewrite historical links. Admin ticket detail shows External ticket (external_key + that URL). Email inbound and POST /api/tickets do not create Plane work items.
{{ticket.id}} and {{ticket.ticketNumber}} are a reserved runtime snapshot. Authors cannot declare a workflow variable named ticket.
What this story does not do¶
- Automatic Plane create for every Floh ticket
- Inbound Plane webhooks / CSRF-exempt routes (parked: LSA-9895)
- Outbound status or priority PATCH (parked: LSA-9895)
- Bidirectional comments (parked: LSA-9896)
- Creating Floh tickets from Plane (
source=itsm) - Portal My Tickets Plane URL
- Per-queue Plane project binding
- Assignee, attachments, or OAuth Plane-app auth
Rollback¶
- Migration
down()dropsticket_external_link. - Remove the Plane connector step from the catalog workflow, or disable the connector instance, to stop new Plane creates. A disabled instance fails the workflow step before any Plane HTTP. Existing Floh tickets and stored snapshot URLs are unchanged.
Security¶
- Outbound HTTP uses
connectorHttpRequestonly (X-API-Key, no rawfetch()). baseUrlis validated like Vault/S3 (validateConnectorEndpoint): http/https only, no userinfo, private nets require the flag.- Structured logs carry connector id, ticket id, and Plane work-item id /
external_key— never title, description, or the PAT.