Skip to content

feat(auth+queue+jobs): add email verification job, split queue roles, fix query keys and a lot of small fixes#23

Merged
kegren merged 1 commit intomainfrom
feat/add-email-verification-job
Jan 4, 2026
Merged

feat(auth+queue+jobs): add email verification job, split queue roles, fix query keys and a lot of small fixes#23
kegren merged 1 commit intomainfrom
feat/add-email-verification-job

Conversation

@kegren
Copy link
Owner

@kegren kegren commented Jan 4, 2026

Enable email verification and enqueue sending via job producer

  • Require email verification for email/password signups and enable
    send-on-sign-in. Hook better-auth's sendVerificationEmail to the
    new enqueueSendVerificationEmail producer so verification emails
    are processed asynchronously.

Introduce typed job payload and robust worker handler

  • Change SendVerificationEmailPayload to include a nested user object
    (id, email, name) to carry user details instead of separate fields.
  • Wrap sendEmail call in try/catch and rethrow errors to surface job
    failures to the worker/pg-boss retry mechanism.

Split pg-boss client roles and lifecycle management

  • Replace single boss with separate producerClient and workerClient.
  • Add getQueueClient() for lightweight enqueueing in the main app
    process and initQueueWorker() to start a worker and register jobs.
  • Add shutdownQueue() to gracefully stop clients on process exit.
  • Add runtime checks for DATABASE_URL and improved error logging.

Misc

  • Add import of enqueueSendVerificationEmail in auth integration.
  • Adjust logging messages to clarify producer vs worker startup.

… fix query keys and a lot of small fixes

Enable email verification and enqueue sending via job producer
- Require email verification for email/password signups and enable
  send-on-sign-in. Hook better-auth's sendVerificationEmail to the
  new enqueueSendVerificationEmail producer so verification emails
  are processed asynchronously.

Introduce typed job payload and robust worker handler
- Change SendVerificationEmailPayload to include a nested user object
  (id, email, name) to carry user details instead of separate fields.
- Wrap sendEmail call in try/catch and rethrow errors to surface job
  failures to the worker/pg-boss retry mechanism.

Split pg-boss client roles and lifecycle management
- Replace single boss with separate producerClient and workerClient.
- Add getQueueClient() for lightweight enqueueing in the main app
  process and initQueueWorker() to start a worker and register jobs.
- Add shutdownQueue() to gracefully stop clients on process exit.
- Add runtime checks for DATABASE_URL and improved error logging.

Misc
- Add import of enqueueSendVerificationEmail in auth integration.
- Adjust logging messages to clarify producer vs worker startup.
@greptile-apps
Copy link

greptile-apps bot commented Jan 4, 2026

Greptile Summary

This PR adds email verification for new signups and restructures the pg-boss queue architecture for better scalability and separation of concerns.

Key changes:

  • Split pg-boss into separate producer and worker clients with dedicated lifecycle management
  • Email verification now required for email/password signups, with verification emails sent asynchronously via job queue
  • Changed from invalidateQueries to removeQueries for session cache management on auth state changes
  • Added graceful shutdown handlers for the worker process
  • Added postgres connection configuration optimized for serverless environments

Issues found:

  • Missing USESEND_FROM_EMAIL and USESEND_BASE_URL in env.ts schema (will cause runtime errors)
  • Error handling in email job wraps and re-throws, losing stack trace

Architecture improvements:

  • getQueueClient() for lightweight job enqueueing in main app
  • initQueueWorker() for worker process with job handler registration
  • shutdownQueue() for graceful cleanup
  • Better separation allows scaling workers independently from the main application

Confidence Score: 4/5

  • Safe to merge with one environment configuration issue that needs immediate attention
  • The PR implements a well-architected queue system with proper separation of concerns between producer and worker roles. The email verification flow is correctly integrated with better-auth. However, there's a critical issue: USESEND_FROM_EMAIL and USESEND_BASE_URL environment variables are used in the code but not defined in the env schema, which will cause runtime errors. Once the env schema is updated, this PR will be safe to merge.
  • src/lib/server/env.ts requires immediate attention to add missing environment variables

Important Files Changed

Filename Overview
src/lib/server/env.ts Missing USESEND_FROM_EMAIL and USESEND_BASE_URL environment variable definitions
src/features/jobs/definitions/email.job.tsx Error handling wraps and re-throws, losing stack trace information
src/lib/server/queue.ts Clean separation of producer and worker clients with proper lifecycle management
src/features/jobs/producers/email.producer.ts New producer function properly uses getQueueClient for lightweight enqueueing
src/lib/server/auth.ts Email verification enabled with async job enqueueing via better-auth hook

Sequence Diagram

sequenceDiagram
    participant User
    participant SignUpForm
    participant AuthClient
    participant BetterAuth
    participant EmailProducer
    participant PgBoss
    participant Worker
    participant EmailJob
    participant UseSend

    User->>SignUpForm: Submit signup form
    SignUpForm->>AuthClient: signUp.email()
    AuthClient->>BetterAuth: Create user account
    BetterAuth->>BetterAuth: Check requireEmailVerification=true
    BetterAuth->>EmailProducer: sendVerificationEmail hook
    EmailProducer->>PgBoss: getQueueClient()
    PgBoss-->>EmailProducer: Return producer client
    EmailProducer->>PgBoss: send(SEND_VERIFICATION_EMAIL, payload)
    PgBoss-->>EmailProducer: Job enqueued
    EmailProducer-->>BetterAuth: Job queued
    BetterAuth-->>AuthClient: User created
    AuthClient-->>SignUpForm: Success
    SignUpForm->>SignUpForm: removeQueries(session)
    SignUpForm->>User: Navigate to /auth/verify-email

    Note over Worker,EmailJob: Separate worker process
    Worker->>PgBoss: Poll for jobs
    PgBoss-->>Worker: Return SEND_VERIFICATION_EMAIL job
    Worker->>EmailJob: Execute job handler
    EmailJob->>EmailJob: Validate payload schema
    EmailJob->>UseSend: sendEmail()
    UseSend-->>EmailJob: Email sent
    EmailJob-->>Worker: Return success
    Worker->>PgBoss: Mark job complete
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Additional Comments (1)

  1. src/lib/server/env.ts, line 8-9 (link)

    logic: USESEND_FROM_EMAIL and USESEND_BASE_URL used in send-email.ts and use-send.ts but not defined in env schema

13 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +47 to +48
} catch (error) {
throw new Error((error as Error).message);
Copy link

Choose a reason for hiding this comment

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

style: Wrapping error loses stack trace - just rethrow the original error

Suggested change
} catch (error) {
throw new Error((error as Error).message);
} catch (error) {
throw error;
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/features/jobs/definitions/email.job.tsx
Line: 47:48

Comment:
**style:** Wrapping error loses stack trace - just rethrow the original error

```suggestion
      } catch (error) {
        throw error;
```

How can I resolve this? If you propose a fix, please make it concise.

@kegren kegren merged commit 48df065 into main Jan 4, 2026
2 checks passed
@kegren kegren deleted the feat/add-email-verification-job branch January 4, 2026 19:22
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