Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix: send subscriber verification in signup service - #2572

Open
jiggyjigsj wants to merge 7 commits into
openstatusHQ:mainfrom
Cooklist:codex/status-subscriber-email-service
Open

fix: send subscriber verification in signup service#2572
jiggyjigsj wants to merge 7 commits into
openstatusHQ:mainfrom
Cooklist:codex/status-subscriber-email-service

Conversation

@jiggyjigsj

@jiggyjigsj jiggyjigsj commented Aug 11, 2026

Copy link
Copy Markdown

Summary

  • move public status-page email signup into a service-layer workflow
  • create the pending subscriber and send its verification email in one server request
  • remove the client-side follow-up mutation and redundant public email endpoint
  • stop returning subscriber verification tokens to the browser

Root cause

The status-page UI first created a pending subscriber, then relied on a second client-side tRPC mutation to send the verification email. If that follow-up request did not run or failed, the subscriber remained pending without receiving a link, and the pending guard blocked another attempt.

Validation

  • pnpm --filter @openstatus/services check
  • changed-file oxlint
  • focused service test against the libSQL image pinned by upstream CI: 5 steps passed
  • formatting and documentation-reference checks passed as part of pnpm verify

The repository-wide verifier still fails on pre-existing Deno type errors involving Buffer in apps/workflows/src/cron/checker.ts and packages/api; the affected service package type-checks cleanly.

Review in cubic

@vercel

vercel Bot commented Aug 11, 2026

Copy link
Copy Markdown

@jiggyjigsj is attempting to deploy a commit to the OpenStatus Team on Vercel.

A member of the Team first needs to authorize it.

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 6 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/services/src/page-subscriber/subscribe.ts Outdated
Comment thread packages/services/src/page-subscriber/subscribe.ts Outdated
@mxkaske

mxkaske commented Aug 11, 2026

Copy link
Copy Markdown
Member

@claude review

@claude

claude Bot commented Aug 11, 2026

Copy link
Copy Markdown

Claude finished @mxkaske's task in 2m 51s —— View job


Claude's Review

Todos:

  • Gather context (read diff, changed files)
  • Understand request (code review requested)
  • Review packages/services/src/page-subscriber/subscribe.ts
  • Review router changes (email/index.ts, statusPage.ts)
  • Review test file and client-side changes
  • Evaluate cubic-dev-ai's two flagged issues (TOCTOU race, email-failure rollback)
  • Post final review

Solid refactor overall — consolidating the create + verification-send into one server-side transaction closes the original client-round-trip gap, and the router/UI cleanup is consistent (no leftover consumers of the removed id/token fields or the deleted sendPageSubscriptionVerification endpoint; form-subscribe-email.tsx's toast.promise already surfaces errors from the single mutation, so dropping the header's redundant onError is safe).

On cubic-dev-ai's two findings:

#2 (P1, subscribe.ts:51, email-provider failure) — confirmed, real regression risk. upsertSelfSignupSubscriber's transaction commits before channel.sendVerification is called. If the provider call throws (rate limit, transient 5xx, invalid domain config, etc.), the pending row is already durable, and hasPendingSubscriber will block the same email/page pair for up to 7 days (VERIFICATION_EXPIRY_MS) with no path to retry. That's the exact "stuck pending, no link" failure mode the PR's own root-cause section describes — it's just moved from "client mutation didn't fire" to "provider call failed." Worth at least catching the send failure and clearing/expiring the row (or deleting it if newly created) so the user can immediately retry, rather than leaving them locked out for a week.

#1 (P2, subscribe.ts:22, TOCTOU on the pending check) — the race is real, but the stated consequence is partly wrong. hasPendingSubscriber reads outside the transaction that upsertSelfSignupSubscriber opens, so two near-simultaneous requests for the same (email, page) can both pass the guard and both reach the upsert. However, the table has a partial unique index (idx_page_subscriber_email_page_active in packages/db/src/schema/page_subscribers/page_subscribers.ts:69) enforcing one active email subscriber per page, and SQLite/libSQL serializes concurrent writers — so this cannot create two pending rows as the comment claims. What can happen: request A inserts and sends a verification email; request B's transaction then finds A's just-committed row, takes the "merge pending" branch (refreshes expiresAt, reuses the same token), and subscribeSelfSignupSubscriber sends a second verification email for that same token. So the real, narrower bug is a duplicate-email race, not duplicate rows. Given this is a public/unauthenticated endpoint, moving the pending check inside the same transaction as the upsert (or having the merge branch short-circuit the caller's send when it just refreshed an already-pending row) would close it.

No other correctness issues found in the diff. One minor note: there's no test exercising the concurrent-request race for issue #1, understandably hard to do reliably against libSQL — not a blocker, just noting the gap given the guard's stated purpose is anti-spam.

@cubic-dev-ai cubic-dev-ai 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.

1 issue found across 6 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="packages/services/src/page-subscriber/expire-verification.ts">

<violation number="1" location="packages/services/src/page-subscriber/expire-verification.ts:33">
P2: A delayed failure from an older verification send can invalidate a newer resend, leaving the user with an unusable link. The compensation needs an attempt/version guard (or a rotated token per resend) before expiring the row.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread packages/services/src/page-subscriber/expire-verification.ts
Comment thread packages/services/src/page-subscriber/upsert.ts Outdated
Comment thread packages/services/src/page-subscriber/subscribe.ts Outdated

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 4 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/services/src/page-subscriber/upsert.ts Outdated
Comment thread packages/services/src/page-subscriber/subscribe.ts Outdated
Comment thread packages/services/src/page-subscriber/upsert.ts Outdated
Comment thread packages/services/src/page-subscriber/__tests__/page-subscriber.test.ts Outdated

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 4 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/services/src/page-subscriber/upsert.ts
Comment thread packages/services/src/page-subscriber/upsert.ts

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 5 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/services/src/page-subscriber/upsert.ts Outdated
@jiggyjigsj

Copy link
Copy Markdown
Author

@mxkaske This should be ready to review.

@jiggyjigsj
jiggyjigsj force-pushed the codex/status-subscriber-email-service branch from bc48542 to eb3a311 Compare August 18, 2026 05:45
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.

2 participants