# Feature Entitlement Engine

## Overview
A centralized service layer that checks whether a subscriber (program, teacher, or student) is entitled to use a feature based on their active subscription plan. Features can be numeric limits, boolean toggles, storage quotas, rate limits, or seat-based limits.

## Architecture

```
config/features.php (Feature Definitions)
    │
    ▼
FeatureDefinition (reads & interprets feature config)
    │
    ▼
FeatureGate (central facade)
    │
    ├── FeatureResolver (resolve feature value from plan/subscription)
    ├── UsageTracker (track consumption/release)
    └── FeatureValue (resolved value + limit)
         │
         └── FeatureResult (allowed/denied + context)
```

## Feature Definitions (`config/features.php`)

Each feature is defined with:
- `name` — Human-readable name
- `description` — What the feature controls
- `type` — `numeric`, `boolean`, `storage`, `rate`, `seats`
- `scope` — `program`, `teacher`, `student` (determines which subscription to check)
- `hard_limit` — Maximum value (subscription plan's limit overrides this)
- `soft_limit` — Warning threshold below hard limit
- `default` — Default value when no subscription
- `unlimited_value` — Value representing unlimited (-1)
- `reset_period` — `monthly`, `daily`, `null`
- `usage_tracking` — Whether to track consumption
- `decrement_on_delete` — Whether to release usage on delete
- `notify_at` — Percentage threshold for notification

### Feature Categories

**Program Scope:**
- `no_of_teachers`, `no_of_marathons`, `no_of_competition_per_marathon`
- `no_of_announcements`, `assessments_enabled`, `certificates_enabled`
- `whatsapp_notifications`, `email_notifications`, `api_access`, `api_rate_limit`

**Teacher Scope:**
- `no_of_courses`, `no_of_lessons`, `no_of_groups`, `no_of_students_per_group`
- `no_of_competitions`, `no_of_exams`, `no_of_trainings`
- `no_of_students_program_competitions_exams`, `no_of_students_system_competitions_exams`
- `no_of_level_classifications`, `no_of_ranking_titles`
- `no_of_announcements_per_teacher`, `available_storage_videos`
- `no_of_allowed_homework_group`, `no_of_allowed_assignment_group`, `no_of_allowed_exams_group`
- `no_of_edits_competition_problems`, `no_of_edits_exam_problems`, `no_of_edits_training_problems`

**Student Scope:**
- `no_of_available_self_training`, `no_of_edits_self_training_problems`
- `no_of_attempts_per_self_training`

## Key Files

### FeatureGate (`app/Services/FeatureEntitlement/FeatureGate.php`)
- Central service that checks feature entitlements
- `allows($subscriber, $feature)` — Check if feature is available
- `consume($subscriber, $feature, $amount)` — Check and consume usage
- `release($subscriber, $feature, $amount)` — Release usage
- Resolves the correct subscription based on feature scope

### FeatureResolver (`app/Services/FeatureEntitlement/FeatureResolver.php`)
- Resolves feature value from:
  1. Plan snapshot on active subscription (historical)
  2. Current plan model (latest definition)
  3. Default values from config
- Handles unlimited values, soft/hard limits

### FeatureDefinition (`app/Services/FeatureEntitlement/FeatureDefinition.php`)
- Reads feature definitions from `config/features.php`
- Provides typed access to feature properties (type, scope, limits)
- Throws `FeatureNotDefinedException` for unknown features

### FeatureResult (`app/Services/FeatureEntitlement/FeatureResult.php`)
- Value object representing check outcome
- Properties: `allowed` (bool), `reason`, `current_usage`, `limit`

### FeatureValue (`app/Services/FeatureEntitlement/FeatureValue.php`)
- Resolved value with limit, type, and scope
- Used by FeatureGate to compare against usage

### UsageTracker (`app/Services/FeatureEntitlement/UsageTracker.php`)
- Centralizes usage counter operations
- `increment()`, `decrement()`, `reset()`, `getCurrentUsage()`
- Handles reset periods (monthly/daily)

### Service Provider (`FeatureEntitlementServiceProvider.php`)
- Registers all feature entitlement services
- Defines `@feature` Blade directive

### Exceptions
- `FeatureNotDefinedException` — Unknown feature key
- `FeatureLimitExceededException` — Subscriber exceeded limit

## Integration with Subscription System

### SubscriptionUsageObserver
Registered on 13+ models in `AppServiceProvider`:
- `Course`, `Lesson`, `Team`, `Video`, `Assessment`, `Marathon`
- `LevelClassification`, `RankingTitle`, `AssessmentAttempt`, `Certificate`, `TeamUser`, `User`, `Announcement`

On `created`: Calls `FeatureGate::consume()` → checks limit, increments usage
On `deleted`: Calls `FeatureGate::release()` → decrements usage (if `decrement_on_delete=true`)

### Subscription Resource Mapping (`config/subscription-resources.php`)
Maps models to feature keys and subscriber resolvers:
- Maps `Course` → `no_of_courses` → resolve teacher subscription
- Maps `Video` → `available_storage_videos` → resolve teacher subscription (amount = MB)
- Maps `Assessment` → type-dependent mapping (competition/exam/training/self-training)
- Supports conditional feature resolution via callables

## Middleware Integration
The `feature:` middleware (`CheckFeatureLimit`) protects routes:
```php
Route::middleware(['feature:assessments_enabled,auto,strict'])->group(function () { ... });
```

## Blade Directive
`@feature('feature_key')` / `@endfeature` for conditional rendering in views.
