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
|
||||
```
|
||||
|
||||
#### **tiers** - Tier-Konfiguration (Admin-editierbar)
|
||||
#### **tiers** - Tier-Konfiguration (vereinfacht)
|
||||
```sql
|
||||
id, slug, name, description, sort_order
|
||||
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
|
||||
id, slug, name, description, sort_order, active
|
||||
|
||||
Initial Tiers:
|
||||
- free: 30 Einträge, 0 KI, 5 Fotos, kein Export/Import
|
||||
- basic: unbegrenzt, 10 KI/Monat, 50 Fotos, Export/Import
|
||||
- premium: unbegrenzt, unbegrenzt KI, unbegrenzt Fotos, alle Features
|
||||
- selfhosted: unbegrenzt alles (für Lars)
|
||||
- free, basic, premium, selfhosted
|
||||
|
||||
Limits sind jetzt in tier_limits Tabelle (siehe unten)!
|
||||
```
|
||||
|
||||
#### **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
|
||||
|
|
@ -214,15 +266,6 @@ total_weight_entries, total_ai_analyses, total_exports
|
|||
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
|
||||
```sql
|
||||
tier, tier_locked (Admin kann Tier festnageln)
|
||||
|
|
@ -238,18 +281,38 @@ stripe_customer_id (vorbereitet für v9d)
|
|||
#### Neue Router (v9c):
|
||||
```
|
||||
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/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/registration.py - Registrierung + E-Mail-Verifizierung
|
||||
```
|
||||
|
||||
#### Neue Middleware:
|
||||
```python
|
||||
require_tier(min_tier) - Feature-Gate basierend auf Tier
|
||||
check_feature_limit(feature, action) - Limit-Prüfung (z.B. max_weight_entries)
|
||||
log_activity(type, details) - Activity-Logging
|
||||
check_feature_access(profile_id, feature_slug, action='use')
|
||||
"""
|
||||
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):
|
||||
|
|
@ -306,18 +369,23 @@ RegisterPage.jsx - Registrierung (Name, E-Mail, Passwort)
|
|||
VerifyEmailPage.jsx - E-Mail-Verifizierung (Token aus URL)
|
||||
RedeemCouponPage.jsx - Coupon-Eingabe (oder Modal)
|
||||
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)
|
||||
```
|
||||
|
||||
#### Neue Komponenten:
|
||||
```jsx
|
||||
<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
|
||||
<CouponInput onRedeem={...} /> // Coupon-Eingabefeld
|
||||
<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:
|
||||
|
|
@ -326,8 +394,87 @@ AdminUsersPage.jsx erweitert um:
|
|||
- Activity-Log Button → zeigt user_activity_log
|
||||
- Stats Button → zeigt user_stats
|
||||
- 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
|
||||
- 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