Repository navigation
fix(api): api v1 review follow-ups (round trip, key revocation, docs) - #230
Merged
Merged
Conversation
The template still carried the old form-level reveal (config.reveal plus triggersReveal), which the builder folds into a reveal step on open and an API key refuses. Author it in the builder's shape so a form made from it can be read and saved back unchanged with a key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Josue Hernandez <josue@daptatech.com>
With an API key, a form read with GET now saves back unchanged with PUT: - message and scheduler steps may have a blank title, like reveal (the editor saves them that way); - branding.clientLogos and a slider's sliderUnitLabel pass when they equal what the form already stores, so a brand kit changed after the form was made, or a template's slider unit, no longer breaks the round trip. A test walks every template, the seeded form and an untitled content form through GET then PUT with a key. Legacy fields still answer UNSUPPORTED_FIELD. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Josue Hernandez <josue@daptatech.com>
Disabling or removing a member, and the identity service's roster marking them inactive or no longer naming them, now revokes their API keys in the same transaction. Reactivating the member later does not bring the old keys back. The key list also hides keys of members who are not active. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Josue Hernandez <josue@daptatech.com>
- Error paths carry the body prefix (config.steps.N.flowGroup, and
destinations.N.settings.timeoutMs on the destinations route).
- The editor defaults are accepted (derived flowGroup, buttonText
"Continue", reveal.enabled, scheduler.prefill), and the JSON Schema
keeps them pinned to that value so a config read back validates.
- Reveal, message and scheduler steps need no question.
- PUT /v1/forms/{id} ignores destinations.
- previousPublishedAt on every form; revert takes no body and answers
200 with the form.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Josue Hernandez <josue@daptatech.com>
…api section
The "How to use the API" section of the Developers page gains two notes
(error paths with the body prefix; the editor defaults a key may send back
and the steps that need no question), says PUT /v1/forms/{id} ignores
destinations, and that a revert takes no body, answers 200 with the form
and that every form carries previousPublishedAt. English and Spanish.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Josue Hernandez <josue@daptatech.com>
Also names the key creation event as PostHog receives it, forms_api_key_created, in the API keys changeset. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Josue Hernandez <josue@daptatech.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Josue Hernandez <josue@daptatech.com>
Disabling a member through the identity service only reached the local row through the roster re-read that follows, which swallows its errors. When that read failed or lagged, the member stayed active here and their API keys kept working. Apply the disable locally right after the upstream write, so the keys are revoked in the same transaction. Also pin runAtomically's rollback with a test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Josue Hernandez <josue@daptatech.com>
…back A form made from a template carries sliderUnitLabel on its sliders, and the brand kit writes branding.clientLogos. The API takes both back as read and the skill tells the agent to send them back, but the shipped JSON Schema dropped them, so a config read from such a form failed validation. Keep their shape, with a description that says to send them back unchanged and never add or change them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Josue Hernandez <josue@daptatech.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-ups from the independent review of API v1 wave 2 (#227, #228, #229, all in
develop).messageandschedulersteps may have a blank title, likereveal. The editor never refuses a blank title (its only save gate isformConfigSchema, wherequestionis optional), so the line drawn is "steps that still make a whole screen without a title": a reveal has its headline, a message its body (helper), a scheduler the booking page. Justified in a comment onTITLE_OPTIONAL_TYPES.branding.clientLogospasses when it equals the kit OR what the form already stores (live or draft), so a kit changed after the form was made no longer breaks aGETthenPUT.sliderUnitLabel: three templates seed it and the canvas shows it, but no control edits it. A new or changed value is stillUNSUPPORTED_FIELD.config.reveal+triggersReveal), which a key refuses. It now carries a reveal step, the shape the builder folds it into on open.UNSUPPORTED_FIELD.runAtomically+revokeKeysOfInactiveMembersSql). Reactivating does not revive them.GET /v1/api-keysonly lists keys of active members.config.steps.N.flowGroup,destinations.N.settings.timeoutMs), accepted editor defaults (also pinned in the JSON Schema, so a config read back validates), steps that need no question,PUT /v1/forms/:idignoresdestinations,previousPublishedAt, revert with no body answering 200. Section in EN and ES. The API keys changeset now names the eventforms_api_key_created.How it was tested
apps/api/src/api-key-round-trip.spec.ts: every template inpackages/db/src/templates, the seeded form (before and after a publish) and a form with untitled message, reveal and scheduler steps makeGETthenPUTunchanged with a key (200); a kit change after creation still saves; legacy fields and a changed slider unit are still refused.packages/db/src/api-keys-members.spec.ts:setMemberStatus,removeMember,projectRosterandprojectMembershipsrevoke; reactivation does not revive; the list hides inactive members' keys. Controller test inapi-keys.controller.spec.ts.previousPublishedAt, revert, schema accepts a normalized config.pnpm typecheck,pnpm lint(2 pre-existing warnings) andpnpm testgreen on Node 22: api 823, web 1313, db 386, engine 436, destinations 125, types 59, shared 83, notifications 57.@quill/dbsuite on Postgres 16 (386/386).PUBLISH_GATE_LOCAL=1 pnpm run publish-gatepassed;scripts/dash-check.sh origin/developclean.Notes
forms_api_key_createdevent name is fixed in the changeset only: it is internal telemetry, so the customer-facing skill and section do not mention it.Review fixes (added after review)
fix(api): disabling a member through the identity service now disables the local row and revokes their API keys in the same step, instead of relying on the roster re-read. Covered by a test where the roster read fails.fix(web): the skill's JSON Schema acceptssteps[].sliderUnitLabelandbranding.clientLogosas read-back fields, so configs read from templates validate.runAtomicallyrolls back the member disable and the revoke together (SQLite and Postgres).Known follow-up: keys of members disabled before this change are not backfilled as revoked; that needs a separate migration.
🤖 Generated with Claude Code