H3: Tuvens S2S event create/link + promo push - #27
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
tuvens
left a comment
There was a problem hiding this comment.
Coordinator review — APPROVED (approval of record), contract-conformant to 04469c48
Verified: TuvensInternalApiMiddleware fails closed on missing secret, digit-checks the timestamp, enforces the ±window, recomputes HMAC over the RAW body and compares with hash_equals, and passes X-On-Behalf-Of through as an attribute resolved against users.external_user_id. Create is idempotent (replay returns the originally-registered webhook secret), unknown user → 422 USER_NOT_PROVISIONED, promo PUT honors X-Idempotency-Key with TTL'd replay. 9 feature tests + full suite green per the gate report. Your two contract asks (optional user:{email,name} on create; S2S mount path note) are being relayed to the api session for a contract revision — pin any follow-up commits to that rev.
Implements the server-to-server surface per the ratified contract (tuvens-api docs/integrations/hi-events-contract.md @ 04469c48; #16, #19): - TuvensInternalApiMiddleware: X-Tuvens-Timestamp (±5 min) + X-Tuvens-Signature = HMAC-SHA256(secret, timestamp + "." + rawBody), constant-time compare; X-On-Behalf-Of passed through for user resolution. - POST /tuvens/events (contract §3): provisions/resolves the on-behalf-of user (optional body.user {email, name} identity for first contact), creates a DRAFT event with attributes[{name: tuvens_event_id}], auto- registers a per-event outgoing webhook at {main_backend.url}/api/webhooks/ticketing/hi-events subscribed to product.*, order.created/refunded/cancelled, event.updated/archived, and responds {event_id, event_url, widget_embed_url, webhook_secret}. Idempotent per (account, tuvens_event_id) — repeats return the existing link with the original webhook secret. - PUT /tuvens/events/{event_id} (contract §5): tuvens-owned promo fields only (title, description, dates, timezone, venue); ticketing fields such as currency are never writable through this channel. Honors X-Idempotency-Key with 24h replay. - CrossAppAccountMappingService now creates default organizer settings for auto-created organizers — without them, the first event creation for a provisioned account 500s (affects the SSO flow too). Feature tests: 9 tests covering signature/timestamp rejection, create + webhook registration + provisioning, idempotent create, USER_NOT_PROVISIONED, missing X-On-Behalf-Of, promo-only field ownership, idempotent replay, 404 for non-linked events. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RrKvdjja8NtzqRKJnX7sA1
05f18f6 to
c6bba77
Compare
Implements #19 against the ratified contract (tuvens-api
docs/integrations/hi-events-contract.md@ 04469c48). Stacked on #22 (H1a) — retarget todevelopafter it merges.What's here
TuvensInternalApiMiddleware(contract §1.2 scheme): ±5 min timestamp window, HMAC-SHA256 overtimestamp + "." + rawBody,hash_equalscompare, 503 if the secret is unconfigured,X-On-Behalf-Ofpassthrough.POST /tuvens/events(§3): resolves the on-behalf-of user viausers.external_user_id, creates a DRAFT event withattributes: [{name: "tuvens_event_id", value, is_public: false}], auto-registers a per-event webhook at{main_backend.url}/api/webhooks/ticketing/hi-events(subscribed:product.*,order.created/refunded/cancelled,event.updated,event.archived), responds{event_id, event_url, widget_embed_url, webhook_secret}. Idempotent per(account, tuvens_event_id)— a repeat create returns the existing event and its original webhook secret (200 vs 201).PUT /tuvens/events/{event_id}(§5): promo fields only; currency and all ticketing fields are unwritable through this channel (test-pinned).X-Idempotency-Keyhonored with a 24h replay window and anX-Idempotent-Replayheader.CrossAppAccountMappingServicenow creates default organizer settings for auto-created organizers (viaCreateDefaultOrganizerSettingsService) — without them the first event creation for any provisioned account 500s (getHomepageThemeSettings() on null), which would have hit the SSO flow too.Contract notes for tuvens-api (also on #16)
user: {email, name}object and returns422 USER_NOT_PROVISIONEDwhen the user is unknown and no identity is supplied. Please adduserto the §3 body in the contract doc.POST/PUT {hievents}/tuvens/events[...]— with the deployment's/apiproxy prefix this externally matches the contract's/api/tuvens/events. The promo push lives on the same S2S prefix rather than the general/api/events/{id}(§5's sketch), keeping the HMAC surface in one route group.event_urlis the organiser manage deep-link (/manage/event/{id}),widget_embed_urlis the public/widget/{id}route.Tests
9 feature tests green (signature/timestamp rejection, create+webhook+provisioning, idempotency, USER_NOT_PROVISIONED, field ownership, replay, 404) plus the full unit suite (435 tests) on this branch.
🤖 Generated with Claude Code
https://claude.ai/code/session_01RrKvdjja8NtzqRKJnX7sA1