14 KiB
Membership Status Definitions & Transitions
This document defines all user membership statuses, their meanings, valid transitions, and automated rules.
Status Overview
| Status | Type | Description | Member Access |
|---|---|---|---|
pending_email |
Registration | User registered, awaiting email verification | None |
pending_validation |
Registration | Email verified, awaiting event attendance | Newsletter only |
pre_validated |
Registration | Attended event or referred, ready for admin validation | Newsletter only |
payment_pending |
Registration | Admin validated, awaiting payment | Newsletter only |
active |
Active | Payment completed, full member access | Full access |
inactive |
Inactive | Membership deactivated manually | None |
canceled |
Terminated | User or admin canceled membership | None |
expired |
Terminated | Subscription ended without renewal | Limited (historical) |
abandoned |
Terminated | Incomplete registration after reminders | None |
Detailed Status Definitions
1. pending_email
Definition: User has registered but not verified their email address.
How User Enters:
- User completes registration form (Step 1-4)
- System creates user account with
pending_emailstatus
Valid Transitions:
- →
pending_validation(email verified) - →
pre_validated(email verified + referred by member) - →
abandoned(optional: 30 days without verification after reminders)
Member Access:
- Cannot login
- Cannot access any member features
- Not subscribed to newsletter
Reminder Schedule:
- Day 3: First reminder email
- Day 7: Second reminder email
- Day 14: Third reminder email
- Day 30: Final reminder (optional: transition to abandoned)
Admin Actions:
- Can manually resend verification email
- Can manually verify email (bypass)
- Can delete user account
2. pending_validation
Definition: Email verified, user needs to attend an event within 90 days (per LOAF policy).
How User Enters:
- Email verification successful (from
pending_email) - 90-day countdown timer starts
Valid Transitions:
- →
pre_validated(attended event marked by admin) - →
abandoned(90 days without event attendance - per policy)
Member Access:
- Can login to view dashboard
- Subscribed to newsletter
- Cannot access member-only features
- Can view public events
Reminder Schedule:
- Day 30: "You have 60 days remaining to attend an event"
- Day 60: "You have 30 days remaining to attend an event"
- Day 80: "Reminder: 10 days left to attend an event"
- Day 85: "Final reminder: 5 days left"
- Day 90: Transition to
abandoned, remove from newsletter
Admin Actions:
- Can mark event attendance (triggers transition to
pre_validated) - Can manually transition to
pre_validated(bypass event requirement) - Can extend deadline
3. pre_validated
Definition: User attended event or was referred, awaiting admin validation.
How User Enters:
- Admin marked event attendance (from
pending_validation) - User registered with valid member referral (skipped
pending_validation)
Valid Transitions:
- →
payment_pending(admin validates application) - →
inactive(admin rejects application - rare)
Member Access:
- Can login to view dashboard
- Subscribed to newsletter
- Cannot access member-only features
- Can view public events
Automated Rules:
- None (requires admin action)
Admin Actions:
- Review application in Validation Queue
- Validate → transition to
payment_pending(sends payment email) - Reject → transition to
inactive(sends rejection email)
4. payment_pending
Definition: Admin validated application, user needs to complete payment.
How User Enters:
- Admin validates application (from
pre_validated) - Payment email sent with Stripe Checkout link
Valid Transitions:
- →
active(payment successful via Stripe webhook) - →
abandoned(optional: 60 days without payment after reminders)
Member Access:
- Can login to view dashboard
- Subscribed to newsletter
- Cannot access member-only features
- Can view subscription plans page
Reminder Schedule:
- Day 7: First payment reminder
- Day 14: Second payment reminder
- Day 21: Third payment reminder
- Day 30: Fourth payment reminder
- Day 45: Fifth payment reminder
- Day 60: Final reminder (optional: transition to abandoned)
Note: Since admin already validated this user, consider keeping them in this status indefinitely rather than auto-abandoning.
Admin Actions:
- Can manually activate membership (for offline payments: cash, check, bank transfer)
- Can resend payment email
5. active
Definition: Payment completed, full membership access granted.
How User Enters:
- Stripe payment successful (from
payment_pending) - Admin manually activated (offline payment)
Valid Transitions:
- →
expired(subscription end date reached without renewal) - →
canceled(user or admin cancels membership) - →
inactive(admin manually deactivates)
Member Access:
- Full member dashboard access
- All member-only features
- Event RSVP and attendance tracking
- Member directory listing
- Newsletter subscribed
Renewal Reminder Schedule:
- 60 days before expiration: First renewal reminder
- 30 days before expiration: Second renewal reminder
- 14 days before expiration: Third renewal reminder
- 7 days before expiration: Final renewal reminder
- On expiration: Transition to
expired
Admin Actions:
- Can cancel membership →
canceled - Can manually deactivate →
inactive - Can extend subscription end_date
6. inactive
Definition: Membership manually deactivated by admin.
How User Enters:
- Admin manually sets status to
inactive - Used for temporary suspensions or admin rejections
Valid Transitions:
- →
active(admin reactivates) - →
payment_pending(admin prompts for payment)
Member Access:
- Can login but no member features
- Not subscribed to newsletter
- Cannot access member-only content
Automated Rules:
- None (requires admin action to exit)
Admin Actions:
- Reactivate membership →
active - Prompt for payment →
payment_pending - Delete user account
7. canceled
Definition: Membership canceled by user or admin.
How User Enters:
- User cancels subscription via Stripe portal
- Admin cancels membership
- Stripe webhook:
customer.subscription.deleted
Valid Transitions:
- →
payment_pending(user requests to rejoin) - →
active(admin reactivates with new subscription)
Member Access:
- Can login to view dashboard (historical data)
- Not subscribed to newsletter
- Cannot access current member-only features
- Can view historical event attendance
Automated Rules:
- Stripe webhook triggers automatic transition
Admin Actions:
- Can invite user to rejoin →
payment_pending - Can manually reactivate →
active(if subscription still valid)
8. expired
Definition: Subscription ended without renewal.
How User Enters:
- Subscription
end_datereached without renewal - Automated check runs daily
Valid Transitions:
- →
payment_pending(user chooses to renew) - →
active(admin manually renews/extends)
Member Access:
- Can login to view dashboard (historical data)
- Not subscribed to newsletter
- Cannot access current member-only features
- Can view historical event attendance
- Shown renewal prompts
Automated Rules:
- Daily check for subscriptions past
end_date→ transition toexpired - Send renewal invitation email on transition
Post-Expiration Reminders:
- Immediate: Expiration notification + renewal link
- 7 days after: Renewal reminder
- 30 days after: Final renewal reminder
- 90 days after: Optional cleanup/archive
Admin Actions:
- Manually extend subscription →
active - Send renewal invitation →
payment_pending
9. abandoned
Definition: User failed to complete registration process after multiple reminders.
How User Enters:
- From
pending_email: 30 days without verification (optional - after 4 reminders) - From
pending_validation: 90 days without event attendance (after 4 reminders) - From
payment_pending: 60 days without payment (optional - after 6 reminders)
Valid Transitions:
- →
pending_email(admin resets application, resends verification) - →
pending_validation(admin resets, manually verifies email) - →
payment_pending(admin resets, bypasses requirements)
Member Access:
- Cannot login
- Not subscribed to newsletter
- All access revoked
Automated Rules:
- Send "incomplete application" notification email on transition
- Optional: Purge from database after 180 days (configurable)
Admin Actions:
- Can reset application → return to appropriate pending state
- Can delete user account
- Can view abandoned applications in admin dashboard
State Transition Diagram
┌──────────────┐
│ Registration │
│ (Guest) │
└──────────────┘
│
↓
┌───────────────┐ (30 days) ┌──────────┐
│ pending_email │──────────────────→│abandoned │
└───────────────┘ └──────────┘
│ ↑
(verify email) │
│ │
↓ │
┌────────────────────┐ (90 days) │
│pending_validation │───────────────────┘
│ (or pre_validated) │
└────────────────────┘
│
(event/admin)
│
↓
┌────────────────┐
│ pre_validated │
└────────────────┘
│
(admin validates)
│
↓
┌─────────────────┐ (60 days) ┌──────────┐
│payment_pending │──────────────────→│abandoned │
└─────────────────┘ └──────────┘
│
(payment)
│
↓
┌─────────┐
│ active │←────────────┐
└─────────┘ │
│ │
├────(expires)────→┌─────────┐
│ │expired │
├────(cancels)────→├─────────┤
│ │canceled │
└──(deactivate)───→├─────────┤
│inactive │
└─────────┘
│
(renew/reactivate)
│
└──────────┘
Email Notification Summary
| Trigger | Emails Sent |
|---|---|
| Registration complete | Verification email (immediate) |
| pending_email day 3, 7, 14, 30 | Verification reminders |
| Email verified | Welcome + event attendance instructions |
| pending_validation day 30, 60, 80, 85 | Event attendance reminders |
| Admin validates | Payment instructions |
| payment_pending day 7, 14, 21, 30, 45, 60 | Payment reminders |
| Payment successful | Membership activation confirmation |
| active: 60, 30, 14, 7 days before expiry | Renewal reminders |
| Subscription expires | Expiration notice + renewal link |
| expired: 7, 30, 90 days after | Post-expiration renewal reminders |
| Status → abandoned | Incomplete application notice |
| Admin cancels | Cancellation confirmation |
Implementation Notes
Configuration Options
All timeout periods should be configurable via environment variables:
# Abandonment timeouts (in days, 0 = never auto-abandon)
EMAIL_VERIFICATION_TIMEOUT=30
EVENT_ATTENDANCE_TIMEOUT=90
PAYMENT_TIMEOUT=0 # Don't auto-abandon payment_pending
# Reminder schedules (comma-separated days)
EMAIL_REMINDERS=3,7,14,30
EVENT_REMINDERS=30,60,80,85
PAYMENT_REMINDERS=7,14,21,30,45,60
RENEWAL_REMINDERS=60,30,14,7
EXPIRED_REMINDERS=7,30,90
Background Jobs Required
-
Daily Status Check (runs at 00:00 UTC)
- Check for expired subscriptions →
expired - Check for abandonment timeouts (if enabled)
- Check for expired subscriptions →
-
Hourly Reminder Check (runs every hour)
- Calculate days since status change
- Send appropriate reminder emails based on schedule
Database Indexes
CREATE INDEX idx_users_status ON users(status);
CREATE INDEX idx_users_created_at ON users(created_at);
CREATE INDEX idx_users_updated_at ON users(updated_at);
CREATE INDEX idx_subscriptions_end_date ON subscriptions(end_date) WHERE status = 'active';
Testing Checklist
- Reminder emails sent on correct schedule
- Abandonment timeouts respect configuration
- Manual status transitions work correctly
- Role updates on status change
- Newsletter subscription/unsubscription on status change
- Email notifications use correct templates
- Stripe webhook integration for cancellations/expirations
- Admin can bypass requirements and manually transition
- Users can complete registration even after reminders stop
Future Enhancements
- Audit Logging: Create
user_status_logtable to track all transitions - Re-engagement Campaigns: Target abandoned users with special offers
- Flexible Timeout Periods: Per-user timeout overrides for special cases
- A/B Testing: Test different reminder schedules for better completion rates
- SMS Reminders: Optional SMS for critical reminders (payment due, expiration)