Skip to main content

Source: ocean/docs/adr/008-simplified-graphql-provisioning.md | ✏️ Edit on GitHub

ADR-008: Simplified GraphQL Provisioning

Status

Accepted

Context

Our current user signup and organization provisioning flow has become increasingly complex:

  • Multiple database triggers and webhooks coordinate provisioning
  • Complex JSONB status tracking in the provisioning_status column
  • Frontend needs to poll for status updates and show progress UI
  • Race conditions between email verification and provisioning completion
  • Difficult to debug failures across multiple async processes
  • Poor user experience with loading screens and status indicators

The existing flow involves:

  1. User signs up via Supabase Auth
  2. Database trigger creates organization
  3. Multiple Edge Functions handle provisioning (Stripe, Neon, etc.)
  4. Frontend polls for status updates
  5. Complex error handling and retry logic spread across services

Decision

We will implement a simplified "fire-and-forget" provisioning model where:

  1. Single GraphQL mutation handles signup and initiates provisioning
  2. Background provisioning runs while user verifies email (30s-2min window)
  3. No status tracking UI - provisioning completes transparently
  4. Simple boolean flags replace complex JSONB status objects
  5. Automatic retry on login if resources aren't ready

Implementation Details

GraphQL Schema

mutation SignUpUser($input: SignUpInput!) {
signUp(input: $input) {
success
message
}
}

input SignUpInput {
email: String!
firstName: String!
lastName: String!
organizationName: String!
industry: String!
dataRegion: String!
}

Provisioning Flow

async function signUp(input) {
// 1. Create user synchronously
const user = await supabase.auth.signUp({
email,
metadata: { ...input },
})

// 2. Get organization (created by trigger)
const org = await getOrganizationByUserId(user.id)

// 3. Fire-and-forget provisioning
provisionResources(org.id, user).catch(logError)

// 4. Return immediately
return { success: true, message: 'Check email' }
}

Database Schema Changes

-- Remove complex tracking
ALTER TABLE organizations
DROP COLUMN provisioning_status,
DROP COLUMN provisioning_started_at,
DROP COLUMN provisioning_completed_at;

-- Add simple flags
ALTER TABLE organizations
ADD COLUMN neon_database_ready boolean DEFAULT false;

Consequences

Positive

  • Dramatically simpler architecture - removed 200+ lines of status tracking code
  • Better user experience - no loading screens or progress indicators
  • More reliable - fewer moving parts and race conditions
  • Easier to debug - provisioning logic consolidated in one place
  • Faster perceived performance - users can proceed immediately
  • Reduced frontend complexity - no polling or status UI components

Negative

  • Less visibility during provisioning - no real-time status updates
  • Potential confusion if provisioning fails silently
  • Harder to track provisioning metrics without detailed status
  • May need to handle edge cases where user logs in before provisioning completes

Mitigations

  • Health checks on login automatically retry failed provisioning
  • Comprehensive logging via Sentry for debugging
  • Provisioning events table retained for audit trail
  • 30s-2min email verification window provides ample provisioning time

Alternatives Considered

1. Keep Complex Status Tracking

  • Pros: Full visibility, detailed progress tracking
  • Cons: Complex implementation, poor UX, maintenance burden
  • Rejected: Complexity outweighs benefits for our use case

2. Synchronous Provisioning

  • Pros: Guaranteed resources ready on signup
  • Cons: 10-30 second signup time, poor UX, timeout risks
  • Rejected: Unacceptable user experience

3. Queue-Based Provisioning

  • Pros: Reliable, retryable, observable
  • Cons: Additional infrastructure (Redis/RabbitMQ), complexity
  • Rejected: Over-engineered for our scale

4. Lazy Provisioning

  • Pros: Provision only when needed
  • Cons: Delays on first use, complex coordination
  • Rejected: Poor first-use experience

Implementation Plan

Phase 1: Backend (Complete)

  • ✅ GraphQL schema updates
  • ✅ SignUp resolver implementation
  • ✅ Background provisioning logic
  • ✅ Database schema simplification
  • ✅ Health check system

Phase 2: Frontend (Pending)

  • Update signup form to use GraphQL mutation
  • Remove status tracking UI components
  • Update success messaging

Phase 3: Production (Pending)

  • Configure production API keys (Stripe, Neon)
  • Deploy database migrations
  • Monitor provisioning success rates

Metrics for Success

  • Signup completion rate > 95%
  • Provisioning success rate > 99%
  • Time to fully provisioned < 2 minutes
  • Support tickets related to provisioning < 1%

References

Decision Makers

  • Engineering Team
  • Product Team

Date

2025-08-06