# Marathon & Competition Business Workflows

> **Comprehensive Business Workflow Reference**
> Describes the ACTUAL implemented behavior verified from source code.
> For project owners, business analysts, QA engineers, and future developers.

---

## 1. Domain Overview

### 1.1 What is a Marathon?

A **Marathon** is a multi-competition event that groups several competitions (stored as assessments with `type = 'marathon-competition'` only) under a single timeframe. Marathons have their own dedicated model (`Marathon`), database table (`marathons`), and Filament resource (`MarathonResource`).

Marathons support full participation management including requests, approvals, seat allocation, and payments. Teachers can participate in system/program-scoped marathons, and students can enroll in teacher-scoped marathons.

**Verified by:** `app/Models/Marathon.php`

### 1.2 What is a Competition?

A **Competition** is a competitive assessment event. Competitions do NOT have their own model — they are stored in the `assessments` table with `type = 'competition'` only. They share the `Assessment` model with exams, trainings, self-trainings, and group assessments.

Competitions have two distinct types based on how they are created:
- **Standalone Competition** (`type = 'competition'`) — created independently through `CompetitionResource`. Has `marathon_id = null`.
- **Marathon Competition** (`type = 'marathon-competition'`) — created inside a Marathon through `CompetitionsRelationManager`. Has `marathon_id` pointing to the parent Marathon. Inherits participation from the parent Marathon.

**Verified by:** `app/Models/Assessment.php`, `app/Filament/Resources/CompetitionResource.php`

### 1.3 Core Terminology

| Term | Definition |
|------|------------|
| **Event** | A Marathon or Competition that users can participate in |
| **Participation** | A teacher's request to participate in an event (system/program scope) |
| **Enrollment** | A student's registration in an event |
| **Seat Allocation** | The number of student spots a teacher receives when approved |
| **Eligibility** | Configuration determining which programs can access system-scoped events |
| **Scope** | Visibility level: `system`, `program`, or `teacher` |
| **Event Type** | Discriminator string: 'marathon' or 'competition' |
| **Attempt** | A student's single try at solving a competition |
| **Payment Submission** | Proof of payment uploaded during participation request |

### 1.4 Supported Scopes

| Scope | Creator Role | Participants | Seat Allocation | Approval By |
|-------|-------------|--------------|-----------------|-------------|
| `system` | super-admin, super-manager | Teachers (any eligible program) | Yes | super-admin, super-manager |
| `program` | portal-admin, portal-manager | Teachers (same program) | Yes | portal-admin, portal-manager |
| `teacher` | portal-teacher | Students (own students) | No | portal-teacher (auto) |

**Verified by:** `app/Filament/Resources/MarathonResource.php`, `app/Filament/Resources/CompetitionResource.php`

### 1.5 User Roles

| Role | Abbreviation | Can Create Marathons? | Can Create Competitions? | Can Participate? |
|------|-------------|----------------------|------------------------|-----------------|
| Super Admin | super-admin | Yes (all scopes) | Yes (all scopes) | N/A |
| Super Manager | super-manager | Yes (all scopes) | Yes (all scopes) | N/A |
| Portal Admin | portal-admin | Yes (program, teacher) | Yes (program, teacher) | N/A |
| Portal Manager | portal-manager | Yes (program, teacher) | Yes (program, teacher) | N/A |
| Portal Teacher | portal-teacher | Yes (teacher only) | Yes (teacher only) | Yes (system/program scope) |
| Teacher Assistant | portal-teacher-assistant | No | No | No |
| Portal Student | portal-student | No | No | Via teacher enrollment |

---

## 2. Entity Relationships

### 2.1 Database Schema Overview

```
marathons (dedicated table)
  │
  ├── belongsTo: Program (program_id)
  ├── belongsTo: User [teacher] (teacher_id)
  ├── hasMany: Assessment [competitions] (marathon_id)
  ├── morphMany: EventParticipation (as 'event', event_type='marathon')
  ├── morphMany: StudentEnrollment (as 'event', event_type='marathon')
  ├── morphMany: EventEligibility (as 'event', event_type='marathon')
  └── morphMany: ParticipationAudit (as 'event', event_type='marathon')

assessments (shared table, uses both 'competition' for standalone and 'marathon-competition' for marathon events)
  │
  ├── belongsTo: Marathon (marathon_id) — nullable
  ├── belongsTo: Program (program_id)
  ├── belongsTo: User [teacher] (teacher_id)
  ├── belongsTo: LevelClassification (level_classification)
  ├── hasMany: AssessmentProblems (assessment_id)
  ├── hasMany: AssessmentAttempt (assessment_id)
  ├── hasMany: AssessmentJoinRequest (assessment_id) — legacy
  ├── morphMany: EventParticipation (as 'event', event_type='competition')
  ├── morphMany: StudentEnrollment (as 'event', event_type='competition')
  ├── morphMany: EventEligibility (as 'event', event_type='competition')
  └── morphMany: ParticipationAudit (as 'event', event_type='competition')

Shared Participation Tables (polymorphic, used by both):

event_participations          — Teacher participation requests
  ├── morphTo: event (Marathon|Assessment)
  ├── belongsTo: User [participant]
  ├── hasOne: SeatAllocation
  └── hasMany: PaymentSubmission

student_enrollments           — Student enrollment records
  ├── morphTo: event (Marathon|Assessment)
  └── belongsTo: User [student]

seat_allocations              — Teacher seat limits
  └── belongsTo: EventParticipation

payment_submissions           — Payment proof uploads
  └── belongsTo: EventParticipation

event_eligibilities           — Program eligibility for system-scoped events
  └── morphTo: event (Marathon|Assessment)

participation_audits          — Audit trail for all state changes
```

**Verified by:** `database/migrations/` listing, `app/Models/Participation/` directory

### 2.2 Polymorphic Event Architecture

Both Marathon and Competition use the same participation tables via polymorphic relationships. The `event_type` column discriminates between them:

- `event_participations.event_type` = `'marathon'` or `'competition'`
- `student_enrollments.event_type` = `'marathon'` or `'competition'`
- `event_eligibilities.event_type` = `'marathon'` or `'competition'` (morph class name)
- `participation_audits.event_type` = `'marathon'` or `'competition'`

This means all participation logic (requests, approvals, enrollments, payments, audits) is shared between Marathon and Competition through a common architecture.

---

## 3. Complete Business Workflows

### 3.1 Marathon Lifecycle

```
                         ┌─────────┐
                         │  Draft   │  ← Created by admin/teacher
                         └────┬─────┘
                              │ Open for participation
                              ▼
                         ┌─────────┐
                    ┌────│  Open    │────┐
                    │    └─────────┘    │
                    │                   │ Close participation
                    │                   ▼
                    │              ┌─────────┐
                    │              │  Closed  │
                    │              └────┬─────┘
                    │                   │ Complete marathon
                    │                   ▼
                    │              ┌─────────────┐
                    └─────────────→│  Completed   │  ← Terminal state
                                   └─────────────┘
```

**Status meanings:**
| Status | What happens | Can submit requests? | Can edit? |
|--------|-------------|---------------------|-----------|
| `draft` | Initial state after creation | No | Yes |
| `open` | Accepting participation and enrollment | Yes | Limited |
| `closed` | No longer accepting new entries | No | Limited |
| `completed` | Marathon finished | No | No |

**Important:** Status is a free-text string field. There is NO database-level enum or state machine enforcement. The `MarathonService` provides methods (`openForParticipation()`, `closeParticipation()`, `completeMarathon()`) that enforce valid transitions at the service level, but direct database saves or updates bypass this validation.

**Verified by:** `app/Models/Marathon.php`, `app/Services/MarathonService.php`

### 3.2 Competition Lifecycle

Competitions do NOT have automated status transitions. The `status` field exists on the `assessments` table (default: `'pending'`) but is never automatically updated. Competitions rely on the `is_locked` boolean to control accessibility:

- `is_locked = true` → Competition is locked (students cannot join/start)
- `is_locked = false` → Competition is unlocked (accessible if other conditions met)

There is **no cron job** that automatically closes or completes competitions when `starts_at`/`ends_at` pass.

**Verified by:** `app/Models/Assessment.php`, `routes/console.php`

### 3.3 System Marathon Workflow

```
1. Super Admin creates Marathon
   ├── Sets scope = 'system'
   ├── Sets title, description, dates
   └── Status = 'draft' (default)

2. Super Admin opens Marathon
   ├── Changes status to 'open'
   └── Audit log: 'marathon.opened'

3. Super Admin configures eligibility
   ├── Which programs are eligible to participate
   └── Stored in event_eligibilities table

4. Teachers view Marathon in listing
   ├── Query checks: scope='system'
   ├── Query checks: teacher's program is in event_eligibilities
   └── Only eligible teachers can see it

5. Teacher submits participation request
   ├── Must have 'portal-teacher' role
   ├── Must NOT already have pending/approved request
   ├── Marathon must have status = 'open'
   ├── Must specify requested seats
   ├── If payment_required: must upload payment proof
   └── EventParticipation created with status = 'pending'

6. Super Admin reviews request
   ├── Sees request in Requests tab
   ├── Can view teacher details, requested seats, payment proof
   ├── Option A: Approve
   │   ├── EventParticipation → 'approved'
   │   ├── SeatAllocation created (total_seats = allocated)
   │   └── Notification: participation.approved
   └── Option B: Reject
       ├── EventParticipation → 'rejected'
       └── Notification: participation.rejected

7. Teacher enrolls students (after approval)
   ├── Can enroll up to allocated seat count
   ├── Manual enrollment: teacher selects student → approved immediately
   └── Request enrollment: student requests → teacher approves
```

**Verified by:** `app/Filament/Resources/MarathonResource.php`, `app/Services/Participation/Services/ParticipationService.php`

### 3.4 Program Marathon Workflow

```
1. Portal Admin creates Marathon
   ├── Sets scope = 'program'
   ├── Sets title, description, dates
   └── Status = 'draft' (default)

2. Portal Admin opens Marathon
   ├── Changes status to 'open'
   └── Audit log: 'marathon.opened' (via MarathonService::openForParticipation())

3. Portal Admin configures eligibility (optional — UI tab visible)
   ├── Portal Admin can select which teachers are eligible via the Eligibility tab
   ├── Stored in event_eligibilities table with eligible_teacher_id
   └── ⚠️ NOTE: Eligibility configuration is NOT enforced for program scope
       ├── isEligibleForProgramEvent() only checks: user.program_id === event.program_id
       ├── canView() does not check event_eligibilities for program scope
       └── All teachers in the same program can see and submit requests regardless

4. Teachers view Marathon in listing
   ├── Query checks: scope='program'
   ├── Teacher must belong to the same program (program_id match)
   └── No per-teacher eligibility check — all program teachers see it

5. Teacher submits participation request
   ├── Must have 'portal-teacher' role
   ├── Must NOT already have pending/approved request
   ├── Marathon must have status = 'open'
   ├── Must specify requested seats
   ├── If payment_required: must upload payment proof
   └── EventParticipation created with status = 'pending'

6. Portal Admin reviews request
   ├── Sees request in Requests tab
   ├── Can view teacher details, requested seats, payment proof
   ├── Option A: Approve
   │   ├── EventParticipation → 'approved'
   │   ├── SeatAllocation created (total_seats = allocated)
   │   └── Notification: participation.approved
   └── Option B: Reject
       ├── EventParticipation → 'rejected'
       └── Notification: participation.rejected

7. Teacher enrolls students (after approval)
   ├── Can enroll up to allocated seat count
   ├── Manual enrollment: teacher selects student → approved immediately
   └── Request enrollment: student requests → teacher approves
```

**Verified by:** `app/Filament/Resources/MarathonResource.php` (canView lines 638-647, submit_participation_request visibility lines 456-495), `app/Services/MarathonService.php` (openForParticipation lines 33-55), `app/Services/Participation/Services/EligibilityService.php` (isEligibleForProgramEvent lines 149-160)

### 3.5 Teacher Marathon Workflow

```
1. Teacher creates Marathon
   ├── Scope = 'teacher' (forced)
   ├── Status = 'draft' (default)
   └── Visible only to the creating teacher

2. Teacher opens Marathon → status = 'open'
   └── Audit log: 'marathon.opened' (via MarathonService::openForParticipation())

3. Teacher enrolls students
   ├── NO participation request needed (teacher scope = auto)
   ├── No seat allocation (teacher-scoped = unlimited within student count)
   │
   ├── Manual enrollment (teacher action):
   │   └── Teacher selects student → enrollment created (status: 'approved') immediately
   │       └── Notification: enrollment.approved
   │
   └── Request enrollment (student action):
       └── Student clicks "Join" → StudentEnrollment created (status: 'pending')
           ├── If payment_required: must upload payment proof
           │   └── ⚠️ NOT YET IMPLEMENTED — payment proof upload does not exist in StudentEnrollmentService
           ├── Teacher reviews pending request in Participants tab
           │   ├── Can view student details
           │   └── Can view payment proof (when implemented)
           ├── Option A: Approve
           │   ├── StudentEnrollment → 'approved'
           │   └── Notification: enrollment.approved
           └── Option B: Reject
               ├── StudentEnrollment → 'rejected'
               └── Notification: enrollment.rejected
```

**Key difference from system/program:** Teachers do NOT submit participation requests for teacher-scoped events. They automatically have participation. Seat allocation is not needed since there is no seat limit for teacher-scoped events.

**Verified by:** `app/Services/Participation/Services/StudentEnrollmentService.php` (submitEnrollmentRequest, approveEnrollment, rejectEnrollment), `app/Services/MarathonService.php` (openForParticipation)

### 3.6 Standalone System Competition Workflow

```
1. Super Admin creates Competition
   ├── Via ListCompetitions create action or AssessmentResource
   ├── Sets type = 'competition', scope = 'system'
   ├── Sets title, description (translatable)
   ├── Sets is_locked = true (default — prevents student access until unlocked)
   ├── Sets enrollment_mode = 'both', 'manual', or 'request'
   ├── Sets level classification
   ├── Sets timing mode and duration
   ├── Sets starts_at / ends_at
   ├── Adds problems (at least one required)
   ├── Optionally sets payment_required for teacher participation
   └── Status = 'pending' (never automatically transitions)

2. Super Admin configures eligibility
   ├── Which programs can teachers participate from
   └── Stored in event_eligibilities table (event_type = 'competition')

3. Super Admin creates or views Competition
   ├── Query checks: type = 'competition', marathon_id = null (standalone only)
   └── Competition visible in CompetitionResource listing

4. Teachers view Competition in listing
   ├── Query checks: scope = 'system'
   ├── Query checks: teacher's program is in event_eligibilities
   └── Only eligible teachers can see it (via CompetitionResource::canView())

5. Teacher submits participation request
   ├── Must have 'portal-teacher' role
   ├── Must NOT already have pending/approved request
   ├── Competition must NOT be marathon-bound (marathon_id = null)
   ├── Must specify requested seats
   ├── If payment_required: must upload payment proof
   └── EventParticipation created with status = 'pending' (event_type = 'competition')

6. Super Admin reviews request
   ├── Sees request in participation management UI
   ├── Can view teacher details, requested seats, payment proof
   ├── Option A: Approve
   │   ├── EventParticipation → 'approved'
   │   ├── SeatAllocation created (total_seats = allocated)
   │   └── Notification: participation.approved
   └── Option B: Reject
       ├── EventParticipation → 'rejected'
       └── Notification: participation.rejected

7. Teacher enrolls students (after approval)
   ├── Can enroll up to allocated seat count
   ├── Manual enrollment: teacher selects student → approved immediately
   │   └── Notification: enrollment.approved
   └── Request enrollment: student clicks "Join" → pending → teacher approves
       ├── Notification: enrollment.submitted (to teacher)
       ├── Approve → enrollment.approved (to student)
       └── Reject → enrollment.rejected (to student)

8. Super Admin unlocks Competition
   ├── Sets is_locked = false
   └── Students can now start solving (if within starts_at/ends_at range)

9. Student solves Competition
   ├── One attempt per student
   ├── Problems solved within time limit
   ├── Submission or timeout
   └── Results shown if show_result is enabled
```

**Key difference from Marathon:** Competitions use `is_locked` boolean instead of Marathon's `status` enum. There is no auto-close when ends_at passes.

**Verified by:** `app/Filament/Resources/CompetitionResource.php` (getEloquentQuery lines 200-215, canView lines 235-330), `app/Services/Participation/Services/CompetitionParticipationService.php` (isMarathonBound, submitTeacherParticipation), `app/Services/Participation/Services/StudentEnrollmentService.php`

### 3.7 Standalone Program Competition Workflow

```
1. Portal Admin creates Competition
   ├── Via ListCompetitions create action or AssessmentResource
   ├── Sets type = 'competition', scope = 'program'
   ├── Sets title, description (translatable)
   ├── Sets is_locked = true (default — prevents student access until unlocked)
   ├── Sets enrollment_mode = 'both', 'manual', or 'request'
   ├── Sets level classification
   ├── Sets timing mode and duration
   ├── Sets starts_at / ends_at
   ├── Adds problems (at least one required)
   ├── Optionally sets payment_required for teacher participation
   └── Status = 'pending' (never automatically transitions)

2. Portal Admin configures eligibility (optional — UI tab visible)
   ├── Portal Admin can select which teachers are eligible
   ├── Stored in event_eligibilities table
   └── ⚠️ NOTE: Eligibility configuration is NOT enforced for program scope
       ├── EligibilityService::isEligibleForProgramEvent() only checks:
       │   user.program_id === event.program_id
       └── All teachers in the same program can see and submit requests regardless

3. Teachers view Competition in listing
   ├── Query checks: scope = 'program'
   ├── Teacher must belong to the same program (program_id match)
   └── No per-teacher eligibility check — all program teachers see it

4. Teacher submits participation request
   ├── Must have 'portal-teacher' role
   ├── Must NOT already have pending/approved request
   ├── Competition must NOT be marathon-bound (marathon_id = null)
   ├── Must specify requested seats
   ├── If payment_required: must upload payment proof
   └── EventParticipation created with status = 'pending' (event_type = 'competition')

5. Portal Admin reviews request
   ├── Sees request in Requests tab
   ├── Can view teacher details, requested seats, payment proof
   ├── Option A: Approve
   │   ├── EventParticipation → 'approved'
   │   ├── SeatAllocation created (total_seats = allocated)
   │   └── Notification: participation.approved
   └── Option B: Reject
       ├── EventParticipation → 'rejected'
       └── Notification: participation.rejected

6. Teacher enrolls students (after approval)
   ├── Can enroll up to allocated seat count
   ├── Manual enrollment: teacher selects student → approved immediately
   │   └── Notification: enrollment.approved
   └── Request enrollment: student clicks "Join" → pending → teacher approves
       ├── Notification: enrollment.submitted (to teacher)
       ├── Approve → enrollment.approved (to student)
       └── Reject → enrollment.rejected (to student)

7. Portal Admin unlocks Competition
   ├── Sets is_locked = false
   └── Students can now start solving (if within starts_at/ends_at range)

8. Student solves Competition
   ├── One attempt per student
   ├── Problems solved within time limit
   ├── Submission or timeout
   └── Results shown if show_result is enabled
```

**Same patterns as Program Marathon:** Same eligibility gap (UI tab visible but NOT enforced), same approval hierarchy, same enrollment flows.

### 3.8 Standalone Teacher Competition Workflow

```
1. Teacher creates Competition
   ├── Via ListCompetitions create action
   ├── Scope = 'teacher' (forced for portal-teacher role)
   ├── Sets type = 'competition'
   ├── Sets title, description (translatable)
   ├── Sets is_locked = true (default — prevents student access until unlocked)
   ├── Sets enrollment_mode = 'both', 'manual', or 'request'
   ├── Sets level classification
   ├── Sets timing mode and duration
   ├── Sets starts_at / ends_at
   ├── Adds problems (at least one required)
   └── Status = 'pending' (never automatically transitions)

2. Teacher views Competition
   ├── No participation request needed (teacher scope = auto)
   ├── No seat allocation (teacher scope = unlimited within own students)
   └── Competition visible to teacher's own students only

3. Teacher unlocks Competition
   ├── Sets is_locked = false
   └── Students can now join and start solving

4. Student enrollment
   ├── Teacher-scoped: only teacher's own students can see/join
   ├── Duplicate check: no existing pending/approved enrollment
   ├── Scope-based eligibility via ParticipationPolicy.canStudentJoin()
   ├── No seat allocation (teacher scope = unlimited)
   │
   ├── Manual enrollment (teacher action):
   │   └── Teacher selects student → enrollment created (status: 'approved') immediately
   │       └── Notification: enrollment.approved
   │
   └── Request enrollment (student action):
       └── Student clicks "Join" → StudentEnrollment created (status: 'pending')
           ├── If payment_required: must upload payment proof
           │   └── ⚠️ NOT YET IMPLEMENTED — payment proof upload does not exist in StudentEnrollmentService
           ├── Teacher reviews pending request
           │   ├── Can view student details
           │   └── Can view payment proof (when implemented)
           ├── Option A: Approve
           │   ├── StudentEnrollment → 'approved'
           │   └── Notification: enrollment.approved
           └── Option B: Reject
               ├── StudentEnrollment → 'rejected'
               └── Notification: enrollment.rejected

5. Student solves Competition
   ├── One attempt per student
   ├── Problems solved within time limit
   ├── Submission or timeout
   └── Results shown if show_result is enabled
```

**Same patterns as Teacher Marathon:** No participation request needed, no seat allocation, teacher owns the event and enrolls own students directly.

**Verified by:** `app/Filament/Resources/CompetitionResource.php` (canView lines 235-330, canJoin logic), `app/Filament/Resources/AssessmentResource.php` (shared form/table components), `app/Services/Participation/Services/StudentEnrollmentService.php`

### 3.9 Competition inside Marathon

```
1. Marathon is created (any scope)

2. Teacher adds Competitions via CompetitionsRelationManager
   ├── Creates assessment with type = 'marathon-competition'
   ├── marathon_id = parent Marathon's ID
   ├── Inherits Marathon's scope automatically
   └── Scope can be synced via syncScopeToCompetitions()

3. Teacher participation is BYPASSED for marathon competitions (`type = 'marathon-competition'`)
   ├── Teachers participate via the parent Marathon instead
   ├── `isMarathonBound()` returns true
   └── `submitTeacherParticipation()` throws RuntimeException

4. Student enrollment
   ├── Currently delegates to competition's own ParticipationService
   └── Marathon's enrollment is NOT automatically checked

5. Students see marathon competition
   ├── Visible in CompetitionResource only if `marathon_id = null` (standalone only)
   └── Visible inside Marathon's Competitions tab
```

**Verified by:** `app/Filament/Resources/MarathonResource/RelationManagers/CompetitionsRelationManager.php`, `app/Services/Participation/Services/CompetitionParticipationService.php`

---

## 4. Event Creation

### 4.1 Who Creates Events

| Event Type | Creator Roles | Location |
|-----------|--------------|----------|
| Marathon (system) | super-admin, super-manager | MarathonResource → Create |
| Marathon (program) | portal-admin, portal-manager | MarathonResource → Create |
| Marathon (teacher) | portal-teacher | MarathonResource → Create |
| Competition (system) | super-admin, super-manager | CompetitionResource → ListCompetitions → Create |
| Competition (program) | portal-admin, portal-manager | CompetitionResource → ListCompetitions → Create |
| Competition (teacher) | portal-teacher | CompetitionResource → ListCompetitions → Create |
| Marathon Competition | Any who can edit Marathon | CompetitionsRelationManager (inside Marathon) |

### 4.2 Required Fields

**Marathon:**
| Field | Type | Required | Notes |
|-------|------|----------|-------|
| Title (en) | string | Yes | Translatable |
| Title (ar) | string | Yes | Translatable |
| Scope | enum | Yes | system/program/teacher |
| Starts at | datetime | Yes | |
| Ends at | datetime | Yes | Must be after starts_at |
| Picture | image | No | Upload to `marathons/` directory |

**Competition:**
| Field | Type | Required | Notes |
|-------|------|----------|-------|
| Title (en) | string | Yes | Translatable |
| Title (ar) | string | Yes | Translatable |
| Scope | enum | Yes | system/program/teacher/user/team |
| Level Classification | int (FK) | Yes | Links to `level_classifications` |
| Timing | enum | Yes | 'problems' or 'assessment' |
| Duration | int | Yes | Minutes |
| Starts at | datetime | Yes (competition/exam) | Hidden for training types |
| Ends at | datetime | Yes (competition/exam) | Hidden for training types |
| Problems | array | Yes | At least one problem required |
| Is Locked | boolean | Yes (default true) | Controls student access |
| Show Result | boolean | Yes (default true) | Disabled for competitions |
| Payment Required | boolean | No | System/program scope only |
| Enrollment Mode | enum | No | both/manual/request |

### 4.3 Publishing and Visibility

**Marathon:**
- Created as `draft` — invisible to participants
- Must be manually opened (`status = 'open'`) to accept participation
- Visibility is scope-based:
  - `system`: visible to eligible programs
  - `program`: visible to all teachers in the program
  - `teacher`: visible only to the creating teacher

**Competition:**
- Created with `is_locked = true` by default
- Must be manually unlocked to allow student access
- Visibility follows scope rules
- `system` scope competitions: students can see if eligible OR if they have enrollment
- `teacher` scope competitions: visible to the teacher's own students

---

## 5. Participation Workflow

### 5.1 Who Can See Events

**Marathon Visibility:**
| Role | System Scope | Program Scope | Teacher Scope |
|------|-------------|---------------|---------------|
| Super Admin | ✅ All | ✅ All | ✅ All |
| Portal Admin | ✅ All | ✅ Own program | ✅ Own program |
| Portal Manager | ✅ All | ✅ Own program | ✅ Own program |
| Teacher | ✅ If program eligible | ✅ Own program | ✅ Own |
| Teacher Assistant | ✅ If program eligible | ✅ Own program | ✅ Assigned teacher |
| Student | ✅ If enrolled OR eligible | N/A | ✅ Own teacher |

**Competition Visibility:**
Same as Marathon, plus students can see competitions where they have an approved enrollment.

**Verified by:** `app/Filament/Resources/MarathonResource.php` canView(), `app/Filament/Resources/CompetitionResource.php` canView()

### 5.2 Who Can Submit Requests

- **Teachers** can submit participation requests for system/program-scoped events
- Teachers must have `portal-teacher` role
- Teachers cannot submit for events where they already have a pending/approved request
- Teachers cannot submit for marathon competitions (`type = 'marathon-competition'`)
- System-scoped events require the teacher's program to be in the eligibility list

### 5.3 Payment Workflow

```
Teacher sees event requires payment
    │
    ▼
Teacher uploads payment proof during request submission
    │
    ▼
EventParticipation created (status: 'pending')
PaymentSubmission created (status: 'pending')
    │
    ▼
Authority reviews payment proof
    │
    ├── VERIFY →
    │   PaymentSubmission → 'verified'
    │   EventParticipation → 'approved' (if not already)
    │
    └── REJECT →
        PaymentSubmission → 'rejected'
        (Teacher can re-upload)
```

**Verified by:** `app/Models/Participation/PaymentSubmission.php`, `app/Services/Participation/Services/PaymentService.php`

### 5.4 Approval Workflow

| Event Scope | Approver | Based On |
|-------------|----------|----------|
| System Marathon | Super Admin / Super Manager | `config/participation.php` approval authority config |
| System Competition | Super Admin / Super Manager | Same config |
| Program Marathon | Portal Admin / Portal Manager | Same config (program scope) — eligibility tab visible but NOT enforced for teachers |
| Program Competition | Portal Admin / Portal Manager | Same config |
| Teacher Marathon | Auto (teacher owns it) | Scope = 'teacher' |
| Teacher Competition | Auto (teacher owns it) | Scope = 'teacher' |

**Verified by:** `config/participation.php`, `app/Policies/ParticipationPolicy.php`

### 5.5 Seat Request and Allocation

```
Teacher requests X seats during participation request
    │
    ▼
Authority approves and allocates Y seats (Y ≤ X usually)
    │
    ▼
SeatAllocation created:
  total_seats = Y
  used_seats = 0
  is_locked = false
    │
    ▼
Teacher enrolls students (consumes seats)
  used_seats increments with each enrollment
    │
    ▼
When used_seats = total_seats → is_locked = true (auto)
OR authority can manually lock
```

**Verified by:** `app/Models/Participation/SeatAllocation.php`, `app/Services/Participation/Services/SeatAllocationService.php`

---

## 6. Student Enrollment

### 6.1 Enrollment Methods

**Method 1: Manual Enrollment (Teacher Action)**
```
Teacher opens event → selects student → enrollment created (status: 'approved')
```
- No approval needed
- Consumes a seat (if applicable)
- Used when `enrollment_mode` includes 'manual'

**Method 2: Student Request Enrollment**
```
Student clicks "Join" → StudentEnrollment created (status: 'pending')
    │
    ▼
Teacher reviews pending requests
    │
    ├── Approve → status: 'approved' (seat consumed)
    └── Reject → status: 'rejected' (no seat consumed)
```
- Teacher must approve/reject
- Student cannot submit duplicate requests
- Used when `enrollment_mode` includes 'request'

**Method 3: Both**
Both manual and request enrollment are available simultaneously.

### 6.2 Enrollment Rules

| Rule | Implementation |
|------|---------------|
| No duplicate enrollment | Check: no existing record with status 'pending' or 'approved' for same (event, student) |
| Seat availability | SeatAllocation.used_seats < SeatAllocation.total_seats |
| Student role only | User must have 'portal-student' role |
| Event must be unlocked | `is_locked` must be false |
| Scope eligibility | Gate: `participation.student-can-join` |
| Marathon must be open | `status` must be 'open' (Marathons only) |

**Verified by:** `app/Filament/Resources/MarathonResource.php` canJoin(), `app/Filament/Resources/AssessmentResource.php` canJoin()

---

## 7. Competition Assignment

### 7.1 How Students Access Competitions

1. Student enrolls in event (Marathon or standalone Competition)
2. Enrollment is approved
3. Student navigates to event → sees the competition
4. If competition is unlocked (`is_locked = false`) and within time range:
   - Student can click "Start Competition"
   - System creates an AssessmentAttempt
   - Student solves problems within time limit

### 7.2 Level Classification

Competitions are assigned a `level_classification` at creation time. This links to a `LevelClassification` record which defines:
- Scope (system/program/teacher)
- Name (translatable)
- Associated program (for program scope)
- Associated teacher (for teacher scope)

Level classification determines which students can see/access the competition. Students are typically grouped by level classification.

### 7.3 Marathon-Bound Competition Assignment

When a competition is inside a Marathon:
- The competition inherits the Marathon's scope
- `syncScopeToCompetitions()` can propagate scope changes
- Teacher participation is inherited from the Marathon
- Student enrollment checks are independent (there is no automatic check against Marathon enrollment)

**Verified by:** `app/Services/MarathonService.php` syncScopeToCompetitions()

---

## 8. Solving Workflow

### 8.1 How Students Start

```
Student clicks "Start Solving" (from competition view)
    │
    ▼
Check: Competition has problems (must have at least 1)
Check: No existing attempt for this student+competition
Check: Competition is unlocked
Check: Within time range (starts_at ≤ now ≤ ends_at)
    │
    ▼
Create AssessmentAttempt (status: not submitted)
Create AssessmentAttemptAnswer for each problem (status: 'pending')
    │
    ▼
Load MentalMathTimer page with all problems
```

**Verified by:** `app/Filament/Pages/MentalMathTimer.php` mount()

### 8.2 Attempt Lifecycle

```
1. Student starts attempt
   ├── Attempt created with started_at = now
   └── All answers initialized as 'pending'

2. Student solves each problem
   ├── Problems shown one-by-one (or full problem if show_once)
   ├── Each problem has a time limit (interval per number)
   ├── Student types answer for each
   └── Progress saved via saveProblem() API

3. Student submits attempt
   ├── finished_at = now
   ├── is_submitted = true
   └── Notification: assessment.attempt.submitted

4. OR Timeout
   ├── All pending answers → 'timed_out'
   ├── correct = false for timed out answers
   ├── is_submitted = true
   └── Notification: assessment.attempt.timed_out
```

**Verified by:** `app/Filament/Pages/MentalMathTimer.php`

### 8.3 Time Limits

- **Per-problem timing:** Each problem has an `interval` (seconds per number). Total time = sum of all intervals.
- **Per-assessment timing:** A fixed `duration_minutes` for the entire assessment.
- Default mode: `'problems'` (per-problem timing).

### 8.4 Submission and Completion

Once submitted:
- Student cannot restart (one attempt only for competitions)
- Results shown based on `show_result` setting
- Each answer graded: correct/incorrect/timed_out
- Score points awarded per correct answer

---

## 9. Results, Rankings & Certificates

### 9.1 Current State

- Results are shown per-attempt (correct/incorrect per problem)
- There is **NO built-in leaderboard or ranking system** for competitions
- There is **NO built-in ranking system for marathons**
- Certificates are managed through a separate Certificate module (not integrated with Marathon/Competition)
- The `show_result` toggle controls whether results are visible to students
- Results can be viewed through the Assessment Classification page (accessible from the competition view)

### 9.2 Classification Page

The Assessment Classification page (`AssessmentClassification.php`) displays:
- Per-student results
- Per-problem results
- Filterable by level classification
- Available from competition view when attempts exist

**Verified by:** `app/Filament/Pages/AssessmentClassification.php`

---

## 10. Notifications

### 10.1 Marathon Notifications

| Trigger | Event Name | Recipients | Cron Job? |
|---------|-----------|------------|-----------|
| Marathon created | `marathon.created` | Scope-based authorities | No (model event) |
| Marathon starts within 24h | `marathon.starts.soon` | Participants | Yes (daily 8AM) |
| Marathon ends within 24h | `marathon.ends.soon` | Participants | Yes (daily 8AM) |
| Marathon completed | `marathon.completed` | Participants | Yes (daily 8AM) |
| Participation submitted | `participation.submitted` | Authorities | No (service event) |
| Participation approved | `participation.approved` | Participant | No (service event) |
| Participation rejected | `participation.rejected` | Participant | No (service event) |
| Seats allocated | `seat.allocated` | Participant | No (service event) |
| Seats full | `seat.full` | Participant, Authority | No (service event) |
| Enrollment submitted | `enrollment.submitted` | Teacher | No (service event) |
| Enrollment approved | `enrollment.approved` | Student | No (service event) |
| Enrollment rejected | `enrollment.rejected` | Student | No (service event) |
| Enrollment removed | `enrollment.removed` | Student | No (service event) |
| Payment submitted | `payment.submitted` | Authorities | No (service event) |
| Payment verified | `payment.verified` | Participant | No (service event) |
| Payment rejected | `payment.rejected` | Participant | No (service event) |

**Verified by:** `app/Models/Marathon.php` booted(), `app/Console/Commands/SendMarathonUpcomingNotifications.php`, `app/Services/Participation/Services/`

### 10.2 Competition Notifications

| Trigger | Event Name | Recipients | Cron Job? |
|---------|-----------|------------|-----------|
| Assessment created | `assessment.created` | Scope-based | No (model event) |
| Assessment updated | `assessment.updated` | Scope-based | No (model event) |
| Attempt submitted | `assessment.attempt.submitted` | Student | No (model event) |
| Attempt timed out | `assessment.attempt.timed_out` | Student | No (model event) |

**Note:** Competition uses the generic `assessment.*` events. There are NO dedicated competition-specific notifications (e.g., `competition.participation.submitted`). All participation-related notifications are handled through the shared Participation Architecture.

**Verified by:** `app/Models/Assessment.php` booted(), `app/Notifications/AssessmentAttempt/`

### 10.3 Scheduled Commands

| Command | Schedule | Purpose |
|---------|----------|---------|
| `notifications:marathon-upcoming` | Daily at 08:00 | Marathon start/end reminders |
| `notifications:assessment-upcoming` | Hourly | Assessment (competition/exam) start/end reminders |

**Verified by:** `routes/console.php`

---

## 11. Role-Based User Journeys

### 11.1 Super Admin Journey

```
LOGIN → Navigate to Marathons or Competitions
    │
    ├── MARATHONS TAB
    │   ├── See all marathons (all scopes)
    │   ├── Create system marathon
    │   ├── Open/close/complete marathons
    │   ├── Configure eligibility (system scope)
    │   ├── Review participation requests
    │   ├── Approve/reject with seat allocation
    │   ├── View participants
    │   ├── Add competitions inside marathon
    │   └── Verify payments
    │
    └── COMPETITIONS TAB
        ├── See all standalone competitions (all scopes)
        ├── Create system competition
        ├── Lock/unlock competitions
        ├── Configure eligibility
        ├── Review participation requests
        ├── Approve/reject
        └── View participants
```

### 11.2 Portal Admin Journey

```
LOGIN → Navigate to Marathons or Competitions
    │
    ├── Can see system events (all)
    ├── Can create program & teacher events
    ├── Can manage events in own program
    ├── Can approve/reject requests for own program
    └── Cannot create system-scoped events
```

### 11.3 Teacher Journey

```
LOGIN → See Marathons/Competitions
    │
    ├── SYSTEM SCOPE EVENTS
    │   ├── See only if program is eligible
    │   ├── Submit participation request (with seat count)
    │   ├── Upload payment proof if required
    │   └── After approval: enroll students
    │
    ├── PROGRAM SCOPE EVENTS
    │   ├── See all in own program
    │   ├── Submit participation request
    │   └── After approval: enroll students
    │
    ├── TEACHER SCOPE EVENTS (own)
    │   ├── Create marathons
    │   ├── Create competitions
    │   ├── Auto-participation (no request needed)
    │   └── Enroll own students directly
    │
    └── STUDENT ENROLLMENTS
        ├── See pending requests
        ├── Approve/reject enrollments
        └── Remove students
```

### 11.4 Student Journey

```
LOGIN → Navigate to Marathons/Competitions
    │
    ├── See eligible events (scope-based)
    │   ├── Teacher scope: own teacher's events
    │   ├── Program scope: program events (if teacher is approved participant)
    │   └── System scope: if program eligible + teacher approved
    │
    ├── Click "Join" on an event
    │   ├── Creates pending enrollment
    │   └── Wait for teacher approval
    │
    ├── After approval: see event details
    │
    └── For competitions:
        ├── Click "Start Competition"
        ├── Solve problems within time limit
        ├── Submit attempt
        └── View results (if show_result enabled)
```

---

## 12. End-to-End Scenarios

### 12.1 Scenario A: System Marathon with Competitions

```
1. Super Admin creates Marathon
   Title: "Summer Challenge 2026"
   Scope: System
   Status: Draft

2. Super Admin adds 3 competitions inside Marathon
   ├── Competition 1: "Speed Round" (marathon-competition type)
   ├── Competition 2: "Accuracy Round" (marathon-competition type)
   └── Competition 3: "Final Challenge" (marathon-competition type)

3. Super Admin configures eligibility
   ├── Program A is eligible
   └── Program B is eligible

4. Super Admin opens Marathon
   Status → Open

5. Teacher from Program A sees Marathon
   (System notification: marathon.starts.soon at 8AM on start day)

6. Teacher submits participation request
   ├── Requests 30 seats
   ├── No payment required
   └── Status: pending

7. Super Admin approves
   ├── SeatAllocation: total_seats=30, used_seats=0
   └── Teacher notified: participation.approved

8. Teacher enrolls 20 students manually
   ├── 20 StudentEnrollment records (status: approved)
   └── SeatAllocation.used_seats = 20

9. 10 additional students request enrollment
   ├── StudentEnrollment (status: pending)
   └── Teacher approves → used_seats = 30

10. SeatAllocation reached → is_locked = true
    (No more students can enroll)

11. Marathon starts
    Competitions become visible to enrolled students

12. Students solve competitions
    ├── Each competition attempted once
    └── Results recorded per attempt

13. Marathon ends
    ├── Super Admin closes Marathon (status: closed)
    └── Later completes it (status: completed)

14. Results reviewed
    └── Super Admin views classification page
```

### 12.2 Scenario B: Teacher Marathon

```
1. Teacher creates Marathon
   Title: "Weekly Practice"
   Scope: Teacher
   Status: Draft

2. Teacher adds 1 competition inside Marathon

3. Teacher opens Marathon (status: open)

4. Teacher enrolls students directly
   ├── Own students only
   └── No seat limit (teacher scope)

5. Students solve competition
   ├── Each student attempts once
   └── Results recorded

6. Teacher closes marathon
   └── Status: closed
```

### 12.3 Scenario C: Standalone System Competition (Paid)

```
1. Super Admin creates Competition
   Title: "National Finals"
   Scope: System
   Payment Required: Yes
   Enrollment Mode: Both
   Is Locked: Yes (initially)

2. Super Admin configures eligibility
   └── Only Program A eligible

3. Teacher from Program A submits participation
   ├── Requests 10 seats
   ├── Uploads payment proof
   └── Status: pending

4. Super Admin verifies payment
   └── PaymentSubmission: verified

5. Super Admin approves participation
   ├── SeatAllocation: total_seats=10
   └── Teacher can now enroll students

6. Super Admin unlocks competition
   └── is_locked: false

7. Teacher enrolls 10 students manually
   └── All approved immediately

8. Competition starts
   Students can start solving

9. Students solve competition
   └── One attempt each

10. Competition ends
    (No auto-close — admin must lock or rely on dates)
```

### 12.4 Scenario D: Edge Cases

**Rejected Participation:**
```
Teacher submits request → Admin rejects
├── EventParticipation status: rejected
├── Teacher can resubmit (no pending/approved request blocking)
└── No seat allocation created
```

**Duplicate Enrollment Prevention:**
```
Student tries to join event twice
├── First click → enrollment created (pending)
├── Second click → DuplicateEnrollmentException
└── Message: "You already have a pending or approved request"
```

**Marathon without Competitions:**
```
Marathon created and opened
├── No competitions added
├── Students enroll
├── No competitions to solve
└── Marathon completes with no results
```

**Competition without Marathon:**
```
Standalone competition created
├── marathon_id = null
├── Managed via CompetitionResource
├── Participation and enrollment work independently
└── No Marathon context
```

---

## 13. Business Rules

### 13.1 Visibility Rules

| Event | Scope | Visible To |
|-------|-------|-----------|
| Marathon | system | Super admins + eligible programs' teachers + students (if enrolled or eligible) |
| Marathon | program | Super admins + same program users |
| Marathon | teacher | Creator teacher + creator's students + super admins |
| Competition | system | Super admins + eligible programs' teachers + students (if enrolled or eligible) |
| Competition | program | Super admins + same program users |
| Competition | teacher | Creator teacher + creator's students + super admins |

### 13.2 Scope Rules

- A Marathon's scope determines its competitions' scope (via `syncScopeToCompetitions()`)
- Competition scope is NOT automatically synced — must be called explicitly
- Scope controls who can see, participate, and approve

### 13.3 Eligibility Rules

- System-scoped events: eligibility IS enforced — only eligible programs' teachers can view/submit
- Program-scoped events: eligibility UI tab IS visible but **NOT enforced** — all teachers in the same program can view and submit participation requests regardless of event_eligibilities configuration
- Eligibility is stored in `event_eligibilities` table
- Links teachers or programs to events (which can access which events)
- Managed by super-admins/super-managers for system scope
- Managed by portal-admins/portal-managers for program scope
- **Implementation gap**: `EligibilityService::isEligibleForProgramEvent()` only checks `$user->program_id === $event->program_id`, ignoring event_eligibilities

### 13.4 Seat Allocation Rules

- Only applies to system and program scopes
- Teacher-scoped events have NO seat limits
- Seats are allocated when participation is approved
- `is_locked` prevents enrollment when all seats are used
- Seat allocation is NOT configurable per event — all approved teachers get seats

### 13.5 Approval Hierarchy

| Event Scope | Submission Target | Approval Authority |
|-------------|------------------|-------------------|
| System | Super Admin | Super Admin / Super Manager |
| Program | Portal Admin | Portal Admin / Portal Manager |
| Teacher | N/A (auto) | N/A |

### 13.6 Enrollment Rules

- One enrollment per student per event (pending or approved status blocks duplicates)
- Students cannot enroll if `is_locked` is true
- Students cannot enroll if Marathon status is not `'open'`
- Removed students can re-enroll
- Enrollment mode (`both` / `manual` / `request`) controls available methods

### 13.7 Competition Assignment Rules

- Marathon-bound competitions share the Marathon's scope
- Teacher participation is inherited from Marathon (not independently managed)
- Students solve competitions independently (one attempt per competition)
- Level classification filters which competitions students see

### 13.8 Notification Rules

- Notifications are dispatched through NotificationEngine
- Recipients are resolved dynamically based on scope
- System-scope: super-admins + managers
- Program-scope: program admins + managers
- Teacher-scope: the teacher
- Cron-based notifications run on schedule (daily at 08:00 for marathons, hourly for assessments)

### 13.9 Ranking Rules

- No built-in ranking system exists
- Results are per-student per-attempt
- Classification page shows per-problem results
- No aggregate rankings, leaderboards, or certificates are generated automatically

---

## 14. Edge Cases

| Edge Case | How the System Handles It | Status |
|-----------|--------------------------|--------|
| Rejected participation | Teacher can resubmit (no blocking record) | ✅ Implemented |
| Full seat allocation | `is_locked` prevents further enrollment | ✅ Implemented |
| Competition without Marathon | Standalone — works independently | ✅ Implemented |
| Marathon without Competitions | No competitions to solve — completes empty | ⚠️ No guard |
| Student already enrolled | DuplicateEnrollmentException with clear message | ✅ Implemented |
| Duplicate requests | Check prevents pending/approved duplicates | ✅ Implemented |
| Closed marathon | `canJoin` checks `status !== 'open'` and denies | ✅ Implemented |
| Expired marathon | No auto-close — relies on manual action | ❌ Missing |
| Expired competition | No auto-close — relies on `is_locked` or manual | ❌ Missing |
| Teacher views locked event | Can view but cannot interact | ✅ Implemented |
| Student views locked event | Cannot see (filtered in canView) | ✅ Implemented |
| Marathon-bound competition participation | Exception thrown with clear message | ✅ Implemented |
| Payment rejection with existing participation | Participation stays pending — can resubmit payment | ✅ Implemented |
| Removal of enrolled student | Releases seat, allows re-enrollment | ✅ Implemented |
| Concurrent attempt creation | One attempt per student per competition enforced | ✅ Implemented |
| Competition with no problems | "Start Solving" button hidden | ✅ Implemented |
| Student not in any program | Cannot see system events (program_id check) | ✅ Implemented |

---

## 15. Open Questions & Observations

### 15.1 Marathon-Bound Competition Enrollment Ambiguity

When a competition is marathon-bound, `CompetitionParticipationService::submitStudentEnrollment()` does NOT check whether the student is enrolled in the parent Marathon. The comment says it should, but the implementation delegates to `ParticipationService` without any marathon-specific validation. The only gate is `ParticipationPolicy::canStudentJoin()`.

**Question:** Should marathon-bound competitions validate that the student is enrolled in the parent Marathon before allowing enrollment?

### 15.2 Feature Consumption in Model Boot Event

Feature consumption for `no_of_competition_per_marathon` happens directly in Assessment's `created` boot event. This has no rollback mechanism and relies on `auth()->user()` which can be null in queue/CLI contexts.

**Observation:** This should be moved to the SubscriptionUsageObserver or a service layer for testability and reliability.

### 15.3 No Automated Status Transitions

Neither Marathon nor Competition has a scheduled job that automatically transitions status based on `starts_at` / `ends_at`. Marathons and competitions remain in their current status indefinitely.

**Question:** Is this intentional? Or should a daily cron job close/completed events whose `ends_at` has passed?

### 15.4 Teacher View of Other Teachers' Teacher-Scoped Events

For teacher-scoped competitions, there is no explicit check preventing Teacher A from accessing Teacher B's teacher-scoped competition when manually navigating to the URL.

**Observation:** The `canView()` method relies on `scope === 'teacher' && teacher_id === user->id`, so this is protected at the resource level. But no database-level guard exists.

### 15.5 Competition Create Pages Not Registered

`CreateCompetition.php` and `EditCompetition.php` exist on disk but are NOT registered in `CompetitionResource::getPages()`. Competition creation happens through `ListCompetitions` inline create action.

**Question:** Is this intentional, or should these pages be registered for better UX?

### 15.6 No Competition Leaderboard

There is no leaderboard or ranking system for competitions. While the Assessment Classification page shows per-student results, there is no aggregate ranking or certificate generation.

**Question:** Is this feature planned but not yet implemented?

### 15.7 Competition-Scoped Marathon-Bound Competitions View

Marathon-bound competitions are filtered OUT of `CompetitionResource::getEloquentQuery()` (`->where('marathon_id', null)`). This means teachers cannot see their marathon-bound competitions in the standalone competition listing.

**Observation:** Teachers may create competitions inside a Marathon and then wonder why they can't see them in the Competitions list.

---

## Appendix: Referenced Source Files

### Models
- `app/Models/Marathon.php` — Marathon model
- `app/Models/Assessment.php` — Competition (type discriminator)
- `app/Models/AssessmentProblems.php` — Competition problems
- `app/Models/AssessmentAttempt.php` — Student attempt
- `app/Models/AssessmentAttemptAnswer.php` — Per-problem answer
- `app/Models/AssessmentJoinRequest.php` — Legacy join request
- `app/Models/Participation/EventParticipation.php` — Teacher participation
- `app/Models/Participation/StudentEnrollment.php` — Student enrollment
- `app/Models/Participation/SeatAllocation.php` — Seat allocation
- `app/Models/Participation/PaymentSubmission.php` — Payment proof
- `app/Models/Participation/EventEligibility.php` — Eligibility config
- `app/Models/Participation/ParticipationAudit.php` — Audit trail
- `app/Models/LevelClassification.php` — Level classification

### Services
- `app/Services/MarathonService.php` — Marathon lifecycle
- `app/Services/Participation/Services/ParticipationService.php` — Central facade
- `app/Services/Participation/Services/MarathonParticipationService.php` — Marathon entry point
- `app/Services/Participation/Services/CompetitionParticipationService.php` — Competition entry point
- `app/Services/Participation/Services/EligibilityService.php` — Eligibility checks
- `app/Services/Participation/Services/ParticipationRequestService.php` — Request management
- `app/Services/Participation/Services/SeatAllocationService.php` — Seat management
- `app/Services/Participation/Services/StudentEnrollmentService.php` — Student enrollment
- `app/Services/Participation/Services/PaymentService.php` — Payment management
- `app/Services/Participation/Services/ParticipationAuditService.php` — Audit logging
- `app/Services/Participation/Contracts/*` — Service interfaces

### Filament Resources
- `app/Filament/Resources/MarathonResource.php` — Marathon CRUD
- `app/Filament/Resources/MarathonResource/Pages/ListMarathons.php` — Marathon list
- `app/Filament/Resources/MarathonResource/Pages/ViewMarathon.php` — Marathon view
- `app/Filament/Resources/MarathonResource/RelationManagers/CompetitionsRelationManager.php` — Competitions tab
- `app/Filament/Resources/CompetitionResource.php` — Competition CRUD
- `app/Filament/Resources/CompetitionResource/Pages/ListCompetitions.php` — Competition list
- `app/Filament/Resources/CompetitionResource/Pages/ViewCompetition.php` — Competition view
- `app/Filament/Resources/AssessmentResource.php` — Shared assessment forms/columns

### Policies
- `app/Policies/ParticipationPolicy.php` — Authorization for participation

### Pages
- `app/Filament/Pages/MentalMathTimer.php` — Competition solving page
- `app/Filament/Pages/AssessmentClassification.php` — Results classification
- `app/Filament/Pages/StudentEnrollmentPage.php` — Student's enrollment overview

### Configuration
- `config/participation.php` — Approval authorities, event types
- `config/features.php` — Feature definitions
- `config/subscription-resources.php` — Usage tracking mapping

### Database
- `database/migrations/2026_05_04_223500_create_assessments_table.php`
- `database/migrations/2026_06_13_103524_create_marathons_table.php`
- `database/migrations/2026_06_13_104054_add_marathon_id_to_assessments_table.php`
- `database/migrations/2026_07_15_000001_add_participation_columns_to_marathons.php`
- `database/migrations/2026_07_15_000002_add_participation_columns_to_assessments.php`
- `database/migrations/2026_07_15_000001_create_event_eligibilities_table.php`
- `database/migrations/2026_07_15_000002_create_event_participations_table.php`
- `database/migrations/2026_07_15_000003_create_seat_allocations_table.php`
- `database/migrations/2026_07_15_000004_create_student_enrollments_table.php`
- `database/migrations/2026_07_15_000005_create_payment_submissions_table.php`
- `database/migrations/2026_07_15_000006_create_participation_audits_table.php`
- `database/migrations/2026_07_17_000001_add_marathon_competition_to_assessment_type_enum.php`

### Tests
- `tests/Feature/Participation/MarathonWorkflowTest.php`
- `tests/Feature/Participation/CompetitionWorkflowTest.php`
- `tests/Unit/Services/Participation/MarathonParticipationServiceTest.php`
- `tests/Unit/Services/Participation/CompetitionParticipationServiceTest.php`
- `tests/Unit/Services/Participation/ParticipationServiceTest.php`
- `tests/Unit/Services/Participation/EligibilityServiceTest.php`
