Skip to content

Opaque ids for connections/webhooks; flat run routes; drop run_number#155

Merged
martsokha merged 4 commits into
mainfrom
refactor/opaque-config-ids
Jul 20, 2026
Merged

Opaque ids for connections/webhooks; flat run routes; drop run_number#155
martsokha merged 4 commits into
mainfrom
refactor/opaque-config-ids

Conversation

@martsokha

Copy link
Copy Markdown
Member

Summary

Refines the resource-identity model after an API-shape review, applying one discriminator consistently: does a human type or cite the identifier? Human-operated resources keep slugs; machine-referenced ones move to server-generated opaque ids. Also flattens run addressing and removes the now-unused per-parent run numbers.

Identity model

Resource Address Rationale
workspace, pipeline, policy, context slug Human-operated / cited by name (policies & contexts are referenced by slug inside pipeline definitions)
connection, webhook conn_<uuid> / whk_<uuid> Configured once, machine-referenced (sync engine / dispatcher)
pipeline run run_<uuid> Transient execution record, machine-referenced

Researched against GitHub/Stripe/Svix/etc. (cited in-thread): opaque-id-as-URL-key is the norm for machine-referenced resources; GitHub keeps /user + /users/{login} split and addresses workflow runs by flat global id — the model followed here.

Changes

  • New PrefixedId macro → distinct ConnectionId, WebhookId, RunId newtypes. Boundary-only: they wrap the existing UUID PK and validate the <prefix>_<uuid> shape on parse, so the DB column stays Uuid (no new columns, no data backfill). Distinct types prevent cross-wiring (e.g. a WebhookId won't parse on a connection route → 400).
  • connections + webhooks: slug dropped (column, UNIQUE(ws, slug), length/format CHECKs, and the UNIQUE(ws, lower(name)) index); server-generated ids; name/display_name now mutable and non-unique. Routes {connectionSlug}/{webhookSlug}{connectionId}/{webhookId}.
  • pipeline runs flattened: item routes move from /pipelines/{pipelineSlug}/runs/{runNumber}/… to /workspaces/{ws}/runs/{runId}/, /detections/, /redactions/ — removing the only 3-parameter routes. Create/list stay nested under the pipeline (create is naturally per-pipeline).
  • run_number removed from both pipeline and connection run tables (column, per-parent unique constraint, gap-free counter function + trigger). Runs are identified by their UUID.
  • connection sync-run HTTP endpoints removed; the table, model, and query layer are retained for internal per-run data (e.g. last-synced state).

Pipelines' policySlugs/contextSlugs references are untouched — policies and contexts stay slug-addressed.

Verification

  • Full gate green: check / clippy --all-targets -D warnings / nightly fmt / rustdoc -D warnings / test (13 suites). Migrations reset+reapplied; schema.rs regenerated and idempotent.
  • Live E2E: connection/webhook create returns conn_/whk_<uuid> with no slug; CRUD by prefixed id; wrong-prefix id on a route → 400; detect returns run_<uuid>; run GET/detections/redactions resolve flat at /runs/{runId}/. OpenAPI confirmed: no connectionSlug/webhookSlug/{runNumber} routes remain; flat /runs/{runId}/* present; pipelines still slug-addressed.

🤖 Generated with Claude Code

martsokha and others added 2 commits July 19, 2026 22:57
WIP checkpoint. Adds ConnectionId/PipelineId/WebhookId prefixed-id newtypes
(boundary-only, wrap the UUID PK). Converts connections off slug: drop slug
column/constraints/name-unique index, model+constraint enum, by-id creator
finder, connection-run _all list returns connection id, Connection response
exposes id. Establishes the template for webhooks + pipelines.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Address API-shape review of config identity:
- connections + webhooks addressed by server-generated prefixed opaque ids
  (conn_<uuid>, whk_<uuid>); slug dropped (column, constraints, name-unique
  index); name is now mutable and non-unique. pipelines/policies/contexts keep
  slugs (human-cited in pipeline definitions).
- pipeline runs addressed by their own opaque id (run_<uuid>) at a flat
  /workspaces/{ws}/runs/{runId}/ (+ /detections/, /redactions/); removes the
  3-parameter run item routes. create/list stay nested under the pipeline.
- run_number removed from both pipeline and connection run tables (column,
  unique constraint, gap-free counter function + trigger); runs are identified
  by their UUID.
- connection sync-run HTTP endpoints removed; the table, model, and query layer
  are retained for internal per-run data (e.g. last-synced state).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@martsokha martsokha added refactor code restructuring without behavior change server API handlers, middleware, auth postgres ORM, models, queries, migrations labels Jul 19, 2026
martsokha and others added 2 commits July 19, 2026 23:27
… cleanup

- Restore per-workspace connection name uniqueness (UNIQUE(ws, lower(trim(name))))
  dropped alongside slug; add NameUnique constraint arm -> 409 with a clear message.
- find_workspace_run_by_id now filters the owning pipeline's deleted_at and returns
  the pipeline alongside the run, so the handler drops its redundant second lookup
  and a soft-deleted pipeline hides its runs consistently.
- Scope find_connection_run_by_id through the owning connection's workspace (was
  unscoped) to prevent a future cross-tenant leak.
- Remove dead pipeline-run finders (find_workspace_pipeline_run_by_id,
  find_pipeline_run_in_workspace) superseded by find_workspace_run_by_id.
- Drop stale DROP FUNCTION set_*_run_number() from both down.sql; fix comments
  that still described (pipeline/connection, number) run addressing.
- Rename the pipeline-run handler + response modules to `runs` to match the flat
  /workspaces/{ws}/runs/{runId} resource.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A connection's last_synced is the completed_at of its most recent successful
(status=completed) sync run, derived rather than stored (consistent with the
existing sync-state view). Adds last_successful_sync_at as a single grouped
query so a page of connections costs one round-trip (no N+1); a failed or
cancelled run does not move the timestamp. This wires the previously-dormant
connection-run query layer to its first consumer.

Verified live: last_synced is absent until a completed run exists, then reflects
the completed run's time and ignores a later failed run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@martsokha martsokha self-assigned this Jul 19, 2026
@martsokha
martsokha merged commit b8baac6 into main Jul 20, 2026
7 checks passed
@martsokha
martsokha deleted the refactor/opaque-config-ids branch July 20, 2026 08:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

postgres ORM, models, queries, migrations refactor code restructuring without behavior change server API handlers, middleware, auth

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant