Skip to main content

Premium Subscription System

This document describes the Aleteia Premium subscription system, which integrates Stripe for payment processing, Firebase Authentication for user management, and Firestore for premium status persistence. The system enables seamless premium subscription lifecycle management with automated user provisioning and email notifications.

Architecture Overview​

The premium system operates as a standalone module within the Rails application, processing Stripe webhook events to manage Firebase users and their premium status.

Key Features​

FeatureDescription
Automated User ProvisioningCreates Firebase Auth users automatically when subscriptions are created
Premium Status ManagementTracks premium status and plan tier in Firestore
Newsletter Auto-SubscriptionAutomatically subscribes new users to daily and vatican newsletter segments
Multi-Language SupportAll communications respect subscriber's locale preference
Password Reset LinksGenerates secure password reset links with custom parameters for frontend detection
Email NotificationsSends welcome and goodbye emails via SendGrid templates
Idempotent ProcessingAll webhook handlers are safely re-runnable

System Components​

Services​

ServicePurposeLocation
Premium::StripeServiceHandles Stripe subscription eventsapp/services/premium/stripe_service.rb
Premium::UsersServiceManages Firebase users and Firestore dataapp/services/premium/users_service.rb
Premium::SendgridServiceSends templated emailsapp/services/premium/sendgrid_service.rb

Background Jobs​

JobQueuePurpose
StripeWebhookJobdefaultRoutes all Stripe events to appropriate handlers
Premium::StripeEventJobdefaultProcesses premium-specific subscription events
Premium::SendEmailJobemailSends welcome/goodbye emails asynchronously

Data Structures​

The system uses Ruby Data classes for immutable value objects:

# Plan information from Stripe product metadata
Plan = Data.define(:id, :name, :tier, :platform, :locale)

# Result of user creation/lookup
UserResult = Data.define(:uid, :email, :display_name, :new_user, :password_generation_link)

Event Routing​

The system uses a unified webhook entry point that intelligently routes events based on product metadata:

Supported Events​

EventHandlerAction
customer.subscription.createdPremium::StripeServiceCreates/updates user, enables premium
customer.subscription.deletedPremium::StripeServiceDisables premium status

User Lifecycle​

New Premium Subscriber​

Premium Cancellation​

Firestore Data Model​

Premium user data is stored in the users collection:

Example Document​

{
"email": "[email protected]",
"display_name": "John Doe",
"first_name": "John",
"last_name": "Doe",
"premium": true,
"plan": "essential",
"plan_name": "Premium Essential",
"plan_monthly_fee": 6.90,
"premium_started_at": "2024-01-15T10:30:00Z",
"premium_ended_at": null,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}

Stripe Product Configuration​

Premium products in Stripe must include specific metadata for proper routing:

Metadata KeyRequiredDescriptionExample
platformYesMust be "premium" for premium routingpremium
tierYesPlan tier identifieressential
nameNoDisplay name for emailsPremium Essential
localeNoDefault locale for communicationsit

Example Product Metadata​

{
"platform": "premium",
"tier": "essential",
"name": "Premium Essential",
"locale": "it"
}

Integration Points​

The premium system integrates with several external services:

ServiceIntegration TypePurpose
StripeWebhooksPayment processing, subscription lifecycle
Firebase AuthAdmin SDKUser creation, email verification
FirestoreClient SDKPremium status persistence
SendGridREST APITransactional email delivery

Security Considerations​

  1. Webhook Verification: All Stripe webhooks are verified using the signing secret
  2. Service Account: Firebase operations use scoped service account credentials
  3. Password Reset: Links generated with 30-second timeout and specific continue URL
  4. Logging: Structured logs avoid accidentally logging sensitive data
  5. Idempotency: All handlers are safely re-runnable without side effects