Skip to content

refactor(kit): prefer webhook events for dedup#245

Open
hyochan wants to merge 2 commits into
mainfrom
refactor/kit-webhook-event-dedup
Open

refactor(kit): prefer webhook events for dedup#245
hyochan wants to merge 2 commits into
mainfrom
refactor/kit-webhook-event-dedup

Conversation

@hyochan

@hyochan hyochan commented Jul 22, 2026

Copy link
Copy Markdown
Member

Summary

  • add a source-aware webhookEvents index for the full project/source/notification natural key while preserving the source-less SSE cursor index
  • prefer webhookEvents for Apple, Google, Google preflight, and Horizon dedup while retaining legacy key fallback and writes
  • cover cross-source and cross-project collisions, legacy adoption, Google preflight, Horizon, and source mismatch guards

Rollout

This is phase 1 of the staged migration in #241. It intentionally keeps webhookIdempotencyKeys reads, writes, pruning, and deletion cascades for rollback and retention drain. A later deploy can stop key writes after production observation; table removal must wait at least WEBHOOK_RETENTION_MS and an explicit zero-row check. The webhook event retention cron remains required.

Refs #241

Verification

  • Kit lint: TypeScript, Convex typecheck, ESLint
  • Kit tests: 63 files, 705 tests
  • Kit Prettier check
  • Kit production/server build and smoke probes
  • SDK parity audit
  • git diff --check

Summary by CodeRabbit

  • Bug Fixes
    • Improved webhook deduplication using a source-aware, project-scoped lookup so Apple, Google, and Meta notifications with the same id are no longer conflated.
    • Added phase-1 dedup behavior that can reuse an existing webhook event row when the source and notification id match.
    • Rejected source mismatches early to prevent incorrect inserts/updates.
    • Fixed Horizon status recording to reuse or insert events correctly based on notification source.
  • Tests
    • Added and expanded automated coverage for source-aware deduplication, preflight/idempotency behavior, and mismatch handling.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@hyochan hyochan added ፦ refactor 🚽 migration Activities due to changes in framework openiap-kit packages/kit (IAPKit SaaS) labels Jul 22, 2026
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 222f702a-90e0-4ef3-b12c-8f43d168a5ec

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Webhook deduplication now uses normalized source-aware event identity, with a composite schema index, event-first lookup and recording paths, expanded test harness support, and coverage for Google, Apple, and Meta notification scenarios.

Changes

Webhook deduplication

Layer / File(s) Summary
Source-aware deduplication core
packages/kit/convex/schema.ts, packages/kit/convex/webhooks/internal.ts
Adds the project/source/notification index, normalizes stored sources, prioritizes webhook event lookup, validates source mismatches, and stores normalized source values.
Deduplication test coverage
packages/kit/convex/test.setup.ts, packages/kit/convex/webhooks/internal.test.ts, packages/kit/convex/webhooks/google.test.ts, packages/kit/convex/webhooks/google.ts
Adds testableFunction, in-memory database utilities, and tests for event-first lookup, key fallback, source isolation, preflight deduplication, and mismatch rejection.
Horizon source-aware recording
packages/kit/convex/subscriptions/horizonInternal.ts, packages/kit/convex/subscriptions/horizonInternal.test.ts
Updates Horizon deduplication to require MetaHorizonReconciler and tests both insertion alongside another source and reuse of an existing Meta event.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GoogleRTDN
  participant ingestGoogleRtdn
  participant lookupExistingEvent
  participant ConvexDB
  GoogleRTDN->>ingestGoogleRtdn: notification payload
  ingestGoogleRtdn->>lookupExistingEvent: project, source, sourceNotificationId
  lookupExistingEvent->>ConvexDB: query source-aware webhookEvents index
  ConvexDB-->>lookupExistingEvent: existing event or no match
  lookupExistingEvent-->>ingestGoogleRtdn: event id or fallback result
  ingestGoogleRtdn-->>GoogleRTDN: deduped WebhookEvent or continue processing
Loading

Possibly related issues

Possibly related PRs

Suggested labels: kit

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly captures the main change: shifting deduplication to prefer webhook events.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/kit-webhook-event-dedup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/kit/convex/webhooks/internal.ts (1)

50-72: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate index-query construction between lookupExistingEvent and recordWebhookEvent.

The by_project_and_source_and_notification_id lookup (.eq("projectId", ...).eq("source", ...).eq("sourceNotificationId", ...)) is duplicated verbatim in both functions. Since this is the dedup-critical query, extracting a small shared helper (e.g. findWebhookEventBySource(ctx, projectId, storedSource, sourceNotificationId)) would prevent the two call sites drifting out of sync in a future edit.

♻️ Proposed helper extraction
+async function findWebhookEventBySource(
+  ctx: { db: DatabaseReader },
+  projectId: Id<"projects">,
+  storedSource: StoredWebhookSource,
+  sourceNotificationId: string,
+) {
+  return ctx.db
+    .query("webhookEvents")
+    .withIndex("by_project_and_source_and_notification_id", (q) =>
+      q
+        .eq("projectId", projectId)
+        .eq("source", storedSource)
+        .eq("sourceNotificationId", sourceNotificationId),
+    )
+    .unique();
+}

Then call findWebhookEventBySource(...) from both lookupExistingEvent and recordWebhookEvent.

Also applies to: 162-184

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/kit/convex/webhooks/internal.ts` around lines 50 - 72, Extract the
duplicated webhookEvents index query into a shared helper, such as
findWebhookEventBySource, accepting the context, projectId, stored source, and
sourceNotificationId. Replace the duplicated query construction in both
lookupExistingEvent and recordWebhookEvent with this helper, preserving the
existing storedSourceForDedupSource behavior and unique lookup semantics.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/kit/convex/webhooks/internal.ts`:
- Around line 50-72: Extract the duplicated webhookEvents index query into a
shared helper, such as findWebhookEventBySource, accepting the context,
projectId, stored source, and sourceNotificationId. Replace the duplicated query
construction in both lookupExistingEvent and recordWebhookEvent with this
helper, preserving the existing storedSourceForDedupSource behavior and unique
lookup semantics.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8ef4eeb8-a8d9-43f9-9a51-9bbd2677bc84

📥 Commits

Reviewing files that changed from the base of the PR and between dc17c54 and 62a6600.

📒 Files selected for processing (8)
  • packages/kit/convex/schema.ts
  • packages/kit/convex/subscriptions/horizonInternal.test.ts
  • packages/kit/convex/subscriptions/horizonInternal.ts
  • packages/kit/convex/test.setup.ts
  • packages/kit/convex/webhooks/google.test.ts
  • packages/kit/convex/webhooks/google.ts
  • packages/kit/convex/webhooks/internal.test.ts
  • packages/kit/convex/webhooks/internal.ts

@hyochan

hyochan commented Jul 22, 2026

Copy link
Copy Markdown
Member Author

Addressed the source-aware webhook event lookup duplication in 7f356e9. The shared typed helper preserves .unique() semantics and the event-first/legacy fallback behavior; focused tests, full Kit tests, lint, format, build/server smoke, parity, and diff-check all pass.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

@hyochan, reviewing the updated source-aware webhook lookup refactor now.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🚽 migration Activities due to changes in framework openiap-kit packages/kit (IAPKit SaaS) ፦ refactor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant