docs: add Feature-Registry Pattern architecture for v9c
Replaced hardcoded tier limits with flexible Feature-Registry Pattern: - features table: All limitable features (weight, AI, photos, export, etc.) - tier_limits: Tier x Feature matrix (admin-configurable) - user_feature_restrictions: Individual user overrides - user_feature_usage: Usage tracking with configurable reset periods Key capabilities: - Add new limitable features without schema changes - Admin UI for matrix-based limit configuration - User-level overrides for specific restrictions - Access hierarchy: User restriction > Tier limit > Feature default Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
95c57de8d0
commit
26f8bcf86d
199
CLAUDE.md
199
CLAUDE.md
|
|
@ -151,18 +151,70 @@ Beispiele:
|
||||||
- gift_coupons_per_month: 3
|
- gift_coupons_per_month: 3
|
||||||
```
|
```
|
||||||
|
|
||||||
#### **tiers** - Tier-Konfiguration (Admin-editierbar)
|
#### **tiers** - Tier-Konfiguration (vereinfacht)
|
||||||
```sql
|
```sql
|
||||||
id, slug, name, description, sort_order
|
id, slug, name, description, sort_order, active
|
||||||
max_weight_entries, max_ai_calls_month, max_photos (NULL = unbegrenzt)
|
|
||||||
allow_export, allow_activity_import, allow_nutrition_import
|
|
||||||
allow_fitness_connectors, allow_gift_coupons
|
|
||||||
|
|
||||||
Initial Tiers:
|
Initial Tiers:
|
||||||
- free: 30 Einträge, 0 KI, 5 Fotos, kein Export/Import
|
- free, basic, premium, selfhosted
|
||||||
- basic: unbegrenzt, 10 KI/Monat, 50 Fotos, Export/Import
|
|
||||||
- premium: unbegrenzt, unbegrenzt KI, unbegrenzt Fotos, alle Features
|
Limits sind jetzt in tier_limits Tabelle (siehe unten)!
|
||||||
- selfhosted: unbegrenzt alles (für Lars)
|
```
|
||||||
|
|
||||||
|
#### **features** - Feature-Registry (alle limitierbaren Features)
|
||||||
|
```sql
|
||||||
|
id, slug, name, category, description, unit
|
||||||
|
default_limit (NULL = unbegrenzt)
|
||||||
|
reset_period ('monthly' | 'daily' | 'never')
|
||||||
|
visible_in_admin, sort_order, active
|
||||||
|
|
||||||
|
Initial Features:
|
||||||
|
- weight_entries: Gewichtseinträge, default: 30, never
|
||||||
|
- circumference_entries: Umfangsmessungen, default: 30, never
|
||||||
|
- caliper_entries: Caliper-Messungen, default: 30, never
|
||||||
|
- nutrition_entries: Ernährungseinträge, default: 30, never
|
||||||
|
- activity_entries: Aktivitäten, default: 30, never
|
||||||
|
- photos: Progress-Fotos, default: 5, never
|
||||||
|
- ai_calls: KI-Analysen, default: 0, monthly
|
||||||
|
- ai_pipeline: KI-Pipeline, default: 0, monthly
|
||||||
|
- csv_import: CSV-Importe, default: 0, monthly
|
||||||
|
- data_export: Daten-Exporte, default: 0, monthly
|
||||||
|
- fitness_connectors: Fitness-Connectoren, default: 0, never
|
||||||
|
|
||||||
|
Neue Features einfach per INSERT hinzufügen - kein Schema-Change!
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **tier_limits** - Limits pro Tier + Feature
|
||||||
|
```sql
|
||||||
|
id, tier_slug, feature_slug, limit_value, enabled
|
||||||
|
|
||||||
|
Beispiel Free Tier:
|
||||||
|
- ('free', 'weight_entries', 30, true)
|
||||||
|
- ('free', 'ai_calls', 0, false) -- KI deaktiviert
|
||||||
|
- ('free', 'data_export', 0, false)
|
||||||
|
|
||||||
|
Beispiel Premium:
|
||||||
|
- ('premium', 'weight_entries', NULL, true) -- unbegrenzt
|
||||||
|
- ('premium', 'ai_calls', NULL, true) -- unbegrenzt
|
||||||
|
|
||||||
|
Admin kann in UI Matrix bearbeiten: Tier x Feature
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **user_feature_restrictions** - Individuelle User-Limits
|
||||||
|
```sql
|
||||||
|
id, profile_id, feature_slug, limit_value, enabled
|
||||||
|
reason, set_by (admin_id)
|
||||||
|
|
||||||
|
Überschreibt Tier-Limits für spezifische User.
|
||||||
|
Admin kann jeden User individuell einschränken oder erweitern.
|
||||||
|
```
|
||||||
|
|
||||||
|
#### **user_feature_usage** - Nutzungs-Tracking
|
||||||
|
```sql
|
||||||
|
id, profile_id, feature_slug, period_start, usage_count, last_used
|
||||||
|
|
||||||
|
Für Features mit reset_period (z.B. ai_calls monthly).
|
||||||
|
Wird automatisch zurückgesetzt am Monatsanfang.
|
||||||
```
|
```
|
||||||
|
|
||||||
#### **coupons** - Coupon-Verwaltung
|
#### **coupons** - Coupon-Verwaltung
|
||||||
|
|
@ -214,15 +266,6 @@ total_weight_entries, total_ai_analyses, total_exports
|
||||||
bonus_points (später), gift_coupons_available (später)
|
bonus_points (später), gift_coupons_available (später)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### **user_restrictions** - Individuelle Einschränkungen
|
|
||||||
```sql
|
|
||||||
profile_id, max_ai_calls_month, max_weight_entries, max_photos
|
|
||||||
block_export, block_ai, block_import
|
|
||||||
reason, set_by (admin_id)
|
|
||||||
|
|
||||||
Überschreibt Tier-Limits für spezifische User
|
|
||||||
```
|
|
||||||
|
|
||||||
#### **profiles** - Erweiterte Spalten
|
#### **profiles** - Erweiterte Spalten
|
||||||
```sql
|
```sql
|
||||||
tier, tier_locked (Admin kann Tier festnageln)
|
tier, tier_locked (Admin kann Tier festnageln)
|
||||||
|
|
@ -238,18 +281,38 @@ stripe_customer_id (vorbereitet für v9d)
|
||||||
#### Neue Router (v9c):
|
#### Neue Router (v9c):
|
||||||
```
|
```
|
||||||
routers/tiers.py - Tier-Verwaltung (List, Edit, Create)
|
routers/tiers.py - Tier-Verwaltung (List, Edit, Create)
|
||||||
|
routers/features.py - Feature-Registry (List, Add, Edit, Delete) ⭐ NEU
|
||||||
|
routers/tier_limits.py - Tier-Limits-Matrix (Admin bearbeitet Tier x Feature) ⭐ NEU
|
||||||
routers/coupons.py - Coupon-System (Redeem, Admin CRUD)
|
routers/coupons.py - Coupon-System (Redeem, Admin CRUD)
|
||||||
routers/access_grants.py - Zugriffs-Verwaltung (Current, Grant, Revoke)
|
routers/access_grants.py - Zugriffs-Verwaltung (Current, Grant, Revoke)
|
||||||
routers/user_admin.py - Erweiterte User-Verwaltung (Activity, Stats, Restrictions)
|
routers/user_admin.py - Erweiterte User-Verwaltung (Activity, Stats, Feature-Restrictions)
|
||||||
routers/settings.py - App-Einstellungen (Admin)
|
routers/settings.py - App-Einstellungen (Admin)
|
||||||
routers/registration.py - Registrierung + E-Mail-Verifizierung
|
routers/registration.py - Registrierung + E-Mail-Verifizierung
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Neue Middleware:
|
#### Neue Middleware:
|
||||||
```python
|
```python
|
||||||
require_tier(min_tier) - Feature-Gate basierend auf Tier
|
check_feature_access(profile_id, feature_slug, action='use')
|
||||||
check_feature_limit(feature, action) - Limit-Prüfung (z.B. max_weight_entries)
|
"""
|
||||||
log_activity(type, details) - Activity-Logging
|
Zentrale Feature-Access-Prüfung.
|
||||||
|
Hierarchie:
|
||||||
|
1. User-Restriction (höchste Priorität)
|
||||||
|
2. Tier-Limit
|
||||||
|
3. Feature-Default
|
||||||
|
|
||||||
|
Returns: {'allowed': bool, 'limit': int, 'used': int, 'remaining': int, 'reason': str}
|
||||||
|
"""
|
||||||
|
|
||||||
|
increment_feature_usage(profile_id, feature_slug)
|
||||||
|
"""
|
||||||
|
Inkrementiert Nutzungszähler.
|
||||||
|
Berücksichtigt reset_period (monthly, daily, never).
|
||||||
|
"""
|
||||||
|
|
||||||
|
log_activity(profile_id, activity_type, details=None)
|
||||||
|
"""
|
||||||
|
Loggt User-Aktivitäten in user_activity_log.
|
||||||
|
"""
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Hintergrund-Tasks (Cron):
|
#### Hintergrund-Tasks (Cron):
|
||||||
|
|
@ -306,18 +369,23 @@ RegisterPage.jsx - Registrierung (Name, E-Mail, Passwort)
|
||||||
VerifyEmailPage.jsx - E-Mail-Verifizierung (Token aus URL)
|
VerifyEmailPage.jsx - E-Mail-Verifizierung (Token aus URL)
|
||||||
RedeemCouponPage.jsx - Coupon-Eingabe (oder Modal)
|
RedeemCouponPage.jsx - Coupon-Eingabe (oder Modal)
|
||||||
AdminCouponsPage.jsx - Coupon-Verwaltung (Admin)
|
AdminCouponsPage.jsx - Coupon-Verwaltung (Admin)
|
||||||
AdminTiersPage.jsx - Tier-Konfiguration (Admin)
|
AdminTiersPage.jsx - Tier-Verwaltung (CRUD) (Admin)
|
||||||
|
AdminFeaturesPage.jsx - Feature-Registry (List, Add, Edit) ⭐ NEU
|
||||||
|
AdminTierLimitsPage.jsx - Tier x Feature Matrix (bearbeiten) ⭐ NEU
|
||||||
|
AdminUserRestrictionsPage.jsx - User-spezifische Limits (bearbeiten) ⭐ NEU
|
||||||
AdminSettingsPage.jsx - App-Einstellungen (Admin)
|
AdminSettingsPage.jsx - App-Einstellungen (Admin)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Neue Komponenten:
|
#### Neue Komponenten:
|
||||||
```jsx
|
```jsx
|
||||||
<TierBadge tier="premium" /> // Tier-Anzeige mit Icon
|
<TierBadge tier="premium" /> // Tier-Anzeige mit Icon
|
||||||
<FeatureGate tier="basic">...</> // Feature nur für Basic+ zeigen
|
<FeatureGate feature="ai_calls">...</> // Feature-basierte Sichtbarkeit ⭐ GEÄNDERT
|
||||||
<AccessStatus /> // "Trial endet in 5 Tagen" Banner
|
<AccessStatus /> // "Trial endet in 5 Tagen" Banner
|
||||||
<CouponInput onRedeem={...} /> // Coupon-Eingabefeld
|
<CouponInput onRedeem={...} /> // Coupon-Eingabefeld
|
||||||
<ActivityTimeline activities={...} /> // User-Activity-Log
|
<ActivityTimeline activities={...} /> // User-Activity-Log
|
||||||
<StreakCounter days={7} /> // Login-Streak Anzeige (später)
|
<FeatureLimitBadge feature="ai_calls" /> // "5/10 verwendet" Anzeige ⭐ NEU
|
||||||
|
<TierLimitsMatrix tiers={...} features={...}/> // Matrix-Editor ⭐ NEU
|
||||||
|
<StreakCounter days={7} /> // Login-Streak (später)
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Erweiterte Admin-Seiten:
|
#### Erweiterte Admin-Seiten:
|
||||||
|
|
@ -326,8 +394,87 @@ AdminUsersPage.jsx erweitert um:
|
||||||
- Activity-Log Button → zeigt user_activity_log
|
- Activity-Log Button → zeigt user_activity_log
|
||||||
- Stats Button → zeigt user_stats
|
- Stats Button → zeigt user_stats
|
||||||
- Access-Grants Button → zeigt aktive/abgelaufene Zugriffe
|
- Access-Grants Button → zeigt aktive/abgelaufene Zugriffe
|
||||||
- Restrictions Button → individuelle Limits setzen
|
- Feature-Restrictions Button → individuelle Feature-Limits setzen ⭐ GEÄNDERT
|
||||||
- Grant Access Button → manuell Tier-Zugriff gewähren
|
- Grant Access Button → manuell Tier-Zugriff gewähren
|
||||||
|
- Usage-Overview → zeigt user_feature_usage für alle Features ⭐ NEU
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Admin-Interface-Details:
|
||||||
|
|
||||||
|
**AdminFeaturesPage.jsx** - Feature-Registry verwalten
|
||||||
|
```jsx
|
||||||
|
// Alle Features auflisten + neue hinzufügen
|
||||||
|
<FeatureList>
|
||||||
|
{features.map(f => (
|
||||||
|
<FeatureRow>
|
||||||
|
<Name>{f.name}</Name>
|
||||||
|
<Category>{f.category}</Category>
|
||||||
|
<Unit>{f.unit}</Unit>
|
||||||
|
<ResetPeriod>{f.reset_period}</ResetPeriod>
|
||||||
|
<DefaultLimit>{f.default_limit ?? '∞'}</DefaultLimit>
|
||||||
|
<Actions>
|
||||||
|
<EditButton />
|
||||||
|
<DeleteButton />
|
||||||
|
</Actions>
|
||||||
|
</FeatureRow>
|
||||||
|
))}
|
||||||
|
</FeatureList>
|
||||||
|
<AddFeatureButton />
|
||||||
|
```
|
||||||
|
|
||||||
|
**AdminTierLimitsPage.jsx** - Matrix-Editor
|
||||||
|
```jsx
|
||||||
|
// Matrix-View: Tiers (Spalten) x Features (Zeilen)
|
||||||
|
<TierLimitsMatrix>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Feature</th>
|
||||||
|
<th>Free</th>
|
||||||
|
<th>Basic</th>
|
||||||
|
<th>Premium</th>
|
||||||
|
<th>Selfhosted</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Gewichtseinträge</td>
|
||||||
|
<td><Input value="30" /></td>
|
||||||
|
<td><Input value="" placeholder="∞" /></td>
|
||||||
|
<td><Input value="" placeholder="∞" /></td>
|
||||||
|
<td><Input value="" placeholder="∞" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>KI-Analysen/Monat</td>
|
||||||
|
<td><Checkbox disabled /> 0</td>
|
||||||
|
<td><Checkbox checked /> <Input value="10" /></td>
|
||||||
|
<td><Checkbox checked /> ∞</td>
|
||||||
|
<td><Checkbox checked /> ∞</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</TierLimitsMatrix>
|
||||||
|
```
|
||||||
|
|
||||||
|
**AdminUserRestrictionsPage.jsx** - Individuelle User-Limits
|
||||||
|
```jsx
|
||||||
|
<UserSelect onChange={loadUser} />
|
||||||
|
|
||||||
|
<CurrentTier badge={user.tier} />
|
||||||
|
<CurrentUsage>
|
||||||
|
{features.map(f => (
|
||||||
|
<FeatureUsageRow key={f.slug}>
|
||||||
|
<Name>{f.name}</Name>
|
||||||
|
<TierLimit>{getTierLimit(user.tier, f.slug)}</TierLimit>
|
||||||
|
<CurrentUsage>{getUsage(user.id, f.slug)}</CurrentUsage>
|
||||||
|
<Override>
|
||||||
|
<Input
|
||||||
|
value={getUserRestriction(user.id, f.slug)}
|
||||||
|
placeholder="Tier-Standard"
|
||||||
|
/>
|
||||||
|
</Override>
|
||||||
|
<SaveButton />
|
||||||
|
</FeatureUsageRow>
|
||||||
|
))}
|
||||||
|
</CurrentUsage>
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user