Skip to content

Comments

feat(feedback-records): add submission_id for grouped submissions and idempotent ingestion#39

Open
xernobyl wants to merge 1 commit intomainfrom
feat/feedback-records-submission-id
Open

feat(feedback-records): add submission_id for grouped submissions and idempotent ingestion#39
xernobyl wants to merge 1 commit intomainfrom
feat/feedback-records-submission-id

Conversation

@xernobyl
Copy link
Contributor

What does this PR do?

Adds a submission_id field to feedback_records so that records belonging to one logical feedback submission can be grouped. This supports use cases like multi-field ingestion from a single event (e.g. Stripe cancellation: reason, comment, date) and simplifies:

  • Grouped reads: GET /v1/feedback-records?submission_id=...
  • Idempotent webhook retries: duplicate (tenant_id, submission_id, field_id) returns 409 Conflict
  • Partial-write reconciliation and correlation across ingestion pipelines

Changes:

  • Migration 003_add_feedback_records_submission_id.sql: adds nullable submission_id (VARCHAR 255), indexes for filtering, and partial unique index on (tenant_id, submission_id, field_id) where submission_id IS NOT NULL (one value per field per submission; backward compatible for rows without submission_id).
  • Models: FeedbackRecord and create/list request types include submission_id; list filters support submission_id.
  • Repository: Create/Get/List/Update read/write submission_id; Create maps PostgreSQL unique violation (23505) to huberrors.ConflictError.
  • Handler: Create responds with 409 Conflict and message when duplicate (tenant_id, submission_id, field_id).
  • OpenAPI: Create body and list params document submission_id; FeedbackRecordData includes submission_id; 409 response documented for create.
  • Tests: TestFeedbackRecordsSubmissionID (create with submission_id, list by submission_id), TestFeedbackRecordsSubmissionIDUniqueConstraint (duplicate create returns 409).

Existing integrations remain compatible: submission_id is optional on create; records without it are valid and the unique constraint does not apply to NULL.

Example – create with submission_id:

POST /v1/feedback-records
{
  "source_type": "formbricks",
  "submission_id": "550e8400-e29b-41d4-a716-446655440000",
  "tenant_id": "org-123",
  "field_id": "reason",
  "field_type": "text",
  "value_text": "cancelled"
}

Example – list by submission_id:

GET /v1/feedback-records?submission_id=550e8400-e29b-41d4-a716-446655440000&tenant_id=org-123

Example – duplicate create (same tenant_id, submission_id, field_id): returns 409 Conflict with body describing the conflict.

How should this be tested?

  • Unit tests: make test-unit (passes).
  • Integration tests: Start Postgres (make docker-up), then make tests. Covers create without/with submission_id, list by submission_id, and duplicate create → 409.
  • Build/lint: make build, make fmt, make lint (all pass).
  • Migrations: make init-db to apply migration; make migrate-validate to validate migration files.
  • Manual: Create two records with same tenant_id, submission_id, and field_id; second request should return 409. List with ?submission_id=... returns only records with that submission_id.

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read Repository Guidelines
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand bits
  • Ran make build
  • Ran make tests (integration tests require Postgres; unit tests and build pass)
  • Ran make fmt and make lint; no new warnings
  • Removed debug prints / temporary logging
  • Merged the latest changes from main onto my branch with git pull origin main
  • If database schema changed: added migration in migrations/ with goose annotations and ran make migrate-validate

Appreciated

  • If API changed: added or updated OpenAPI spec and ran contract tests (make tests or API contract workflow)
  • If API behavior changed: added request/response examples or Swagger UI screenshots to this PR
  • Updated docs in docs/ if changes were necessary
  • Ran make tests-coverage for meaningful logic changes

… idempotent ingestion

- Add migration 003: submission_id column, indexes, unique (tenant_id, submission_id, field_id) where submission_id IS NOT NULL
- Add submission_id to FeedbackRecord, CreateFeedbackRecordRequest, ListFeedbackRecordsFilters
- Repository: CRUD and list filter by submission_id; map unique violation to ConflictError
- Handler: respond 409 Conflict on duplicate (tenant_id, submission_id, field_id)
- OpenAPI: document submission_id on create, list, and response; document 409
- Add RespondConflict and ConflictError
- Integration tests: submission_id create/list and unique constraint 409

Co-authored-by: Cursor <cursoragent@cursor.com>
@github-actions
Copy link

github-actions bot commented Feb 23, 2026

✱ Stainless preview builds

This PR will update the hub SDKs with the following commit message.

feat(feedback-records): add submission_id for grouped submissions and idempotent ingestion

Edit this comment to update it. It will appear in the SDK's changelogs.

hub-openapi studio · code · diff

Your SDK built successfully.
generate ✅ (prev: generate ⚠️)

hub-typescript studio · code · diff

Your SDK built successfully.
generate ✅ (prev: generate ⚠️) → build ✅lint ✅test ✅

npm install https://pkg.stainless.com/s/hub-typescript/baf69bdec02831a4cb44b460606718b02eda3ffc/dist.tar.gz

This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
If you push custom code to the preview branch, re-run this workflow to update the comment.
Last updated: 2026-02-23 17:43:35 UTC

@xernobyl xernobyl requested a review from mattinannt February 23, 2026 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant