Membership & Quota System
Complete guide to membership plans, features, quota tracking, and usage logs
5 Tables
Quota Tracking
Usage Logging
π Overview
The Membership & Quota System manages subscription plans with feature-based quota tracking and usage logging. This enables tiered access control based on membership levels.
- Membership Plans - Define subscription tiers with pricing and duration
- Feature Limits - Configure what each plan includes (API calls, posts, storage)
- Quota Tracking - Real-time monitoring of current period usage
- Usage Logging - Complete audit trail of all usage transactions
ποΈ Architecture
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β MEMBERSHIP & QUOTA SYSTEM β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ β β β ββββββββββββββββ ββββββββββββββββββββββββ β β β memberships ββββββΆβmembership_features β β β β β β(Plan Definitions) β β β ββββββββ¬ββββββββ ββββββββββββββββββββββββ β β β β β βΌ β β ββββββββββββββββββββ β β βuser_memberships βββββ app_users.user_id β β β(Active Subs) β β β ββββββββββββββββββββ β β β β β βΌ β β ββββββββββββββββββββββββββββ β β βuser_membership_quotas β β Updated frequently β β β(Current Period Usage) β (after each action) β β β β β β β - feature_key β β β β - limit_value β NULL = unlimited β β β - used_value β Current usage count β β β - remaining_value β Auto-calculated β β β - period_start/end β For periodic resets β β ββββββββββ¬ββββββββββββββββββ β β β β β βΌ β β ββββββββββββββββββββ β β βuser_usage_logs β β Append-only audit trail β β β(Transaction Hist)β (Every usage event) β β β β β β β - action_type β api_call, post_create, etc. β β β - quantity β Number of units consumed β β β - resource_id β Reference to created item β β β - metadata β Context information β β ββββββββββββββββββββ β β β β QUOTA CHECK FLOW: β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β β 1. User initiates action (e.g., Create Post) β β β β 2. Get user's active membership β β β β 3. Get quota for feature_key='posts' β β β β 4. Check: remaining_value > 0 OR remaining_value IS NULL β β β β 5. If OK: β β β β - Log to user_usage_logs β β β β - Update user_membership_quotas (used_value++, remaining--) β β β β - Process request β β β β 6. If exceeded: Return error with upgrade suggestion β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β β β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
π Table Reference
memberships
Defines available membership plans with pricing and duration.
| Field | Type | Attributes | Description |
|---|---|---|---|
id | BIGINT | PK, Auto Increment | Primary key |
name | VARCHAR(100) | NOT NULL | Plan name (Basic, Pro, Premium) |
slug | VARCHAR(50) | UNIQUE | URL-friendly identifier (basic-plan) |
description | TEXT | NULLABLE | Plan description |
duration_days | INT | NULLABLE | Duration in days (NULL = lifetime) |
price | DECIMAL(10,2) | Default: 0 | Plan price |
currency | CHAR(3) | Default: INR | ISO currency code |
level | TINYINT | Default: 0 | Plan hierarchy level |
is_active | BOOLEAN | Default: true | Plan availability |
membership_features
Defines what features each membership plan includes and their limits.
| Field | Type | Attributes | Description |
|---|---|---|---|
id | BIGINT | PK, Auto Increment | Primary key |
membership_id | BIGINT | FK | References memberships.id |
feature_key | VARCHAR(50) | NOT NULL | Feature identifier (api_calls, posts, storage) |
feature_name | VARCHAR(100) | NOT NULL | Display name (API Calls) |
limit_value | INT | NULLABLE | NULL = unlimited |
period | ENUM | Default: lifetime | lifetime, monthly, yearly, daily |
user_memberships
User's active and historical subscriptions.
| Field | Type | Attributes | Description |
|---|---|---|---|
id | BIGINT | PK, Auto Increment | Primary key |
user_id | VARCHAR(32) | FK | References app_users.user_id |
membership_id | BIGINT | FK | References memberships.id |
status | ENUM | Default: active | active, expired, cancelled, pending |
start_date | DATE | NOT NULL | Subscription start date |
end_date | DATE | NULLABLE | Subscription end date (NULL = lifetime) |
auto_renew | BOOLEAN | Default: false | Auto-renewal enabled |
user_membership_quotas
Current period quota tracking. Updated after each usage.
| Field | Type | Attributes | Description |
|---|---|---|---|
id | BIGINT | PK, Auto Increment | Primary key |
user_id | VARCHAR(32) | FK | References app_users.user_id |
user_membership_id | BIGINT | FK | References user_memberships.id |
feature_key | VARCHAR(50) | NOT NULL | Feature identifier |
limit_value | INT | NULLABLE | NULL = unlimited |
used_value | INT | Default: 0 | Current usage count |
remaining_value | INT | NULLABLE | Auto-calculated (limit - used) |
period_start | DATE | NOT NULL | Period start date |
period_end | DATE | NOT NULL | Period end date |
user_usage_logs
Append-only transaction history. Complete audit trail of all usage.
| Field | Type | Attributes | Description |
|---|---|---|---|
id | BIGINT | PK, Auto Increment | Primary key |
user_id | VARCHAR(32) | FK | References app_users.user_id |
feature_key | VARCHAR(50) | NOT NULL | Feature being used |
action_type | VARCHAR(50) | NOT NULL | api_call, post_create, file_upload, etc. |
quantity | INT | Default: 1 | Units consumed |
resource_id | VARCHAR(100) | NULLABLE | Reference to created resource |
metadata | JSON | NULLABLE | Additional context |
created_at | TIMESTAMP | Auto | Usage timestamp |
π Default Membership Plans
Free
βΉ0 β’ Lifetime
- β’ 100 API calls/month
- β’ 10 posts/month
- β’ 100MB storage
Basic
βΉ199/month β’ 30 days
- β’ 1,000 API calls/month
- β’ 50 posts/month
- β’ 500MB storage
Pro
βΉ499/month β’ 30 days
- β’ 10,000 API calls/month
- β’ 500 posts/month
- β’ 2GB storage
Premium
βΉ999/month β’ 30 days
- β’ 50,000 API calls/month
- β’ 2,000 posts/month
- β’ 10GB storage
Enterprise
βΉ9,999/year β’ 365 days
- β’ Unlimited API calls
- β’ Unlimited posts
- β’ Unlimited storage
π» Usage Examples
// Check quota before allowing action
$quota = UserMembershipQuota::where('user_id', $userId)
->where('feature_key', 'posts')
->where('period_start', '<=', now())
->where('period_end', '>', now())
->first();
if ($quota && ($quota->remaining_value > 0 || $quota->remaining_value === null)) {
// Allow action
} else {
// Quota exceeded
return response()->json([
'error' => 'Quota exceeded',
'message' => 'You have reached your monthly post limit.',
'upgrade_suggestion' => 'Upgrade to Pro plan for 500 posts/month',
], 429);
}
// Log usage and update quota
DB::transaction(function() use ($userId, $featureKey) {
// Log the usage
UserUsageLog::create([
'user_id' => $userId,
'feature_key' => $featureKey,
'action_type' => 'post_create',
'quantity' => 1,
'resource_id' => $postId,
'metadata' => ['title' => $post->title],
]);
// Update quota
$quota = UserMembershipQuota::where('user_id', $userId)
->where('feature_key', $featureKey)
->first();
$quota->increment('used_value');
if ($quota->limit_value !== null) {
$quota->update(['remaining_value' => $quota->limit_value - $quota->used_value]);
}
});
// Get user's current membership with features
$membership = UserMembership::where('user_id', $userId)
->where('status', 'active')
->where(function($q) {
$q->whereNull('end_date')
->orWhere('end_date', '>', now());
})
->with('membership.features')
->first();