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
| Feature | Description |
|---|---|
| Automated User Provisioning | Creates Firebase Auth users automatically when subscriptions are created |
| Premium Status Management | Tracks premium status and plan tier in Firestore |
| Newsletter Auto-Subscription | Automatically subscribes new users to daily and vatican newsletter segments |
| Multi-Language Support | All communications respect subscriber's locale preference |
| Password Reset Links | Generates secure password reset links with custom parameters for frontend detection |
| Email Notifications | Sends welcome and goodbye emails via SendGrid templates |
| Idempotent Processing | All webhook handlers are safely re-runnable |
System Components
Services
| Service | Purpose | Location |
|---|---|---|
Premium::StripeService | Handles Stripe subscription events | app/services/premium/stripe_service.rb |
Premium::UsersService | Manages Firebase users and Firestore data | app/services/premium/users_service.rb |
Premium::SendgridService | Sends templated emails | app/services/premium/sendgrid_service.rb |
Background Jobs
| Job | Queue | Purpose |
|---|---|---|
StripeWebhookJob | default | Routes all Stripe events to appropriate handlers |
Premium::StripeEventJob | default | Processes premium-specific subscription events |
Premium::SendEmailJob | email | Sends 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
| Event | Handler | Action |
|---|---|---|
customer.subscription.created | Premium::StripeService | Creates/updates user, enables premium |
customer.subscription.deleted | Premium::StripeService | Disables 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 Key | Required | Description | Example |
|---|---|---|---|
platform | Yes | Must be "premium" for premium routing | premium |
tier | Yes | Plan tier identifier | essential |
name | No | Display name for emails | Premium Essential |
locale | No | Default locale for communications | it |
Example Product Metadata
{
"platform": "premium",
"tier": "essential",
"name": "Premium Essential",
"locale": "it"
}
Integration Points
The premium system integrates with several external services:
| Service | Integration Type | Purpose |
|---|---|---|
| Stripe | Webhooks | Payment processing, subscription lifecycle |
| Firebase Auth | Admin SDK | User creation, email verification |
| Firestore | Client SDK | Premium status persistence |
| SendGrid | REST API | Transactional email delivery |
Security Considerations
- Webhook Verification: All Stripe webhooks are verified using the signing secret
- Service Account: Firebase operations use scoped service account credentials
- Password Reset: Links generated with 30-second timeout and specific continue URL
- Logging: Structured logs avoid accidentally logging sensitive data
- Idempotency: All handlers are safely re-runnable without side effects
Related Documentation
- Firebase Integration - Detailed Firebase Auth and Firestore setup
- Stripe Integration - Webhook handling and event processing
- Email Notifications - SendGrid template configuration
- Setup Guide - Complete installation and configuration guide