# CC Soccer D11 - Session Handoff
**Date:** January 13, 2026  
**Last Updated:** Session End (Team Status, Co-Captain, Captain Management)

---

## COMPLETED THIS SESSION

### Team Status & Weight Fields ✅

**Overview:** Added team status management (active/withdrawn/disqualified) and weight-based ordering for tournament teams.

#### Team Entity Updates (`Team.php`)
- Added `status` field (list_string: active/withdrawn/disqualified, defaults to active)
- Added `weight` field (integer for drag-and-drop ordering, defaults to 0)
- Added `co_captain` field (entity reference to user)
- Added helper methods:
  - `getStatus()`, `isActive()`, `isWithdrawn()`, `isDisqualified()`
  - `getWeight()`
  - `hasCoCaptain()`, `getCoCaptainId()`, `isTeamLeader()`

#### Install Updates (`ccsoccer.install`)
- `ccsoccer_update_9039()` - Team status and weight fields
- `_ccsoccer_ensure_team_status_weight_fields()` - Idempotent helper
- Sets existing teams to `status = 'active'`
- Sets weight values based on alphabetical order for existing teams
- Added PHASE 22 to `hook_install()`

#### Tournament Teams Page
- Status dropdown column (already existed, CSS styling added)
- `tournament-teams.css` - Status dropdown styling (`.team-status-cell`, `.team-status-select`, `.status-save-indicator`)

#### Tournament Roster Builder Updates
- Sort teams by `weight` field (not alphabetical)
- Status-based CSS classes (`team-withdrawn`, `team-disqualified`)
- Status badges (W/DQ) in team headers for non-active teams
- Active team count displayed in header stats ("Teams: 13" and "Active Teams: 9")
- Visual styling: Withdrawn = gray header (65% opacity), Disqualified = red header (65% opacity)

### Schedule Builder - Active Teams Filter ✅

**File:** `TournamentScheduleGeneratorService.php`
- `getTeamsWithSkillLevels()` now filters by `status = 'active'` (excludes withdrawn/disqualified teams)
- Player counts now come from `ccsoccer_registration` entities instead of Team's `players` field (fixes stale counts)

### Captain & Co-Captain Management ✅

**File:** `GroupInvitationsForm.php`

**Captain Management:**
- Captain row now has dropdown: "Captain" or "⚠️ Release as Captain"
- `releaseCaptain()` - Revised to keep players on team, just removes captain status
- Captain becomes regular team member (team stays active, not withdrawn)

**Co-Captain Support:**
- Co-Captain row (if exists) has dropdown: "Co-Captain" or "⚠️ Release as Co-Captain"
- Accepted players can be promoted: "⭐ Promote to Captain" or "⭐ Promote to Co-Captain"
- New methods: `promoteToCoCaptain()`, `releaseCoCaptain()`
- Both captain and co-captain have `is_captain = TRUE` for invite permissions

**Styling:** `group-invitations-admin.css`
- Captain dropdown styling (green theme)
- Co-Captain dropdown styling (blue theme)

### Seed Command Update ✅

**File:** `CcsoccerCommands.php`
- `populateTournamentsWithTeams()` now populates all 3 tournaments (2024, 2025, 2026)
- Each tournament gets: 13 teams with 10 players each, 10 unassigned players, 10 CCSoccer Pool players

### Previously Completed (Confirmed) ✅

**These TODO items from the previous session were already implemented:**
1. ✅ **Player notification when removed from team** - Already implemented in `GroupController::removeMember()` which calls `$this->notificationService->sendPlayerRemoved()`
2. ✅ **Admin dashboard for unassigned players** - Not needed as separate page; Tournament Roster Builder Workbench already shows unassigned players and CCSoccer Pool players with drag-drop assignment

---

## KEY FILES MODIFIED THIS SESSION

```
Entity:
web/modules/custom/ccsoccer/src/Entity/
└── Team.php
    └── Added status field (active/withdrawn/disqualified)
    └── Added weight field (integer for ordering)
    └── Added co_captain field (entity reference)
    └── Added helper methods: getStatus(), isActive(), isWithdrawn(), isDisqualified()
    └── Added helper methods: getWeight(), hasCoCaptain(), getCoCaptainId(), isTeamLeader()

Services:
web/modules/custom/ccsoccer/src/Service/
└── TournamentScheduleGeneratorService.php
    └── getTeamsWithSkillLevels() - Filter by status=active, fix player counts

Forms:
web/modules/custom/ccsoccer/src/Form/
├── TournamentRosterBuilderForm.php
│   └── getTournamentRosterState() - Added status and weight to team data
│   └── buildForm() - Sort teams by weight
│   └── buildTeamColumn() - Status classes, badges, data attributes
│   └── Header stats - Added active_team_count
└── GroupInvitationsForm.php
    └── Captain dropdown with Release option
    └── Co-Captain dropdown with Release option
    └── Accepted players Promote to Captain/Co-Captain options
    └── releaseCaptain() - Revised to keep players on team
    └── promoteToCoCaptain(), releaseCoCaptain() - New methods

Drush Commands:
web/modules/custom/ccsoccer/src/Drush/Commands/
└── CcsoccerCommands.php
    └── populateTournamentsWithTeams() - Now populates all 3 tournaments

Module Files:
web/modules/custom/ccsoccer/
└── ccsoccer.install
    └── ccsoccer_update_9039() - Team status and weight fields
    └── _ccsoccer_ensure_team_status_weight_fields() - Idempotent helper
    └── PHASE 22 added to hook_install()

CSS:
web/modules/custom/ccsoccer/css/
├── tournament-teams.css
│   └── Status dropdown styling (.team-status-cell, .team-status-select)
├── tournament-roster-builder.css
│   └── .team-column.team-withdrawn (gray header, 65% opacity)
│   └── .team-column.team-disqualified (red header, 65% opacity)
│   └── .team-status-badge styling
└── group-invitations-admin.css
    └── Captain dropdown styling (green)
    └── Co-Captain dropdown styling (blue)
```

---

## PROJECT STATUS

**Overall Completion:** ~98%

### COMPLETE Features (100%)

| Feature | Status | Notes |
|---------|--------|-------|
| Core Entities | Complete | All 10 entities working |
| Registration Flow | Complete | Season + tournament checkout |
| Group Management | Complete | Unified interface for seasons AND tournaments |
| Roster Builder | Complete | Drag-drop + algorithm (seasons) |
| Tournament Roster Builder | Complete | Drag-drop admin interface for tournament teams |
| Tournament Overview Page | Complete | Mirrors Season pattern with stats and flags |
| Schedule Builder (Season) | Complete | Drag-drop + generator + snapshots |
| Tournament Schedule Builder | Complete | Round-robin matchups, rest optimization, true grid drag-drop, snapshots |
| Schedule Snapshots | Complete | Save/list/rename/delete/restore all working |
| Tournament Teams Admin | Complete | Teams list with skill levels + Create Team UI + Status dropdown |
| Group ID UUID System | Complete | Consistent UUIDs for both season and tournament groups |
| Notifications | Complete | Email/SMS with test mode + privileged verify + multi-season |
| Captain Notifications | Complete | Player joined, declined, removed notifications |
| Game Status | Complete | Banner + admin form + auto-reset + credits |
| Credits System | Complete | Entity + service methods |
| Season Publishing | Complete | Visibility flags + league inheritance |
| Override System | Complete | Logic + admin UI complete |
| Content Pages | Complete | Home, teams, schedule, my-schedule, my-teams |
| Tournament Public Pages | Complete | /tournament-schedule, /tournament-teams, my-* variants |
| Jersey Purchase | Complete | Cart display fixed, waiver skip for jersey-only |
| Masquerade | Complete | Footer block with dashboard links |
| Mobile Menu | Complete | Dropdowns work on iOS |
| Floating Schedule Nav | Complete | Arrows accessible when scrolled |
| Cancelled Game Display | Complete | Visual overlay on all schedule views |
| Board/Director Dashboards | Complete | Role-based access with appropriate footer links |
| Tournament Entity | Complete | Full entity with scheduling fields |
| Tournament Team Pane | Complete | Checkout pane with team selection/creation |
| Tournament Payment Processing | Complete | Team creation, roster joining, token flow |
| Tournament Capacity System | Complete | Roster limits enforced throughout |
| TournamentTeamManager | Complete | Complete service for team/player management |
| Tournament Invite Flow | Complete | Email invite auto-accepts for registered users |
| Tournament My Registrations UX | Complete | Status display for all player states |
| Tournament Admin Menu | Complete | Dynamic dropdown with Edit/Roster Builder/Schedule Builder links |
| Tournament Seed Data | Complete | --populate-tournaments creates 3 tournaments with teams |
| **Team Status Management** | **Complete** | **Active/Withdrawn/Disqualified status with visual indicators** |
| **Co-Captain Support** | **Complete** | **Co-captain field, promote/release functionality** |
| **Captain Management** | **Complete** | **Release captain, promote player, via Group Invitations** |
| **Player Removed Notification** | **Complete** | **Already in GroupController::removeMember()** |

### TODO (Remaining Items)

**UI/UX Enhancements:**
1. **Roster Builder team drag-and-drop reordering** - Allow dragging team columns to reorder (uses weight field)
2. **Tournament pill boxes** - Update Tournament Public and private views to use pill boxes for tournament name
3. **Player credits UI** - Is there a UI to credit individual players?
4. **Season/Tournament player filter** - Sub menu under individual seasons and tournaments to only display players with that season or tournament

**Phase 4: Tournament Public Display (Partially Complete)**
- ✅ `/tournament-schedule` - Tournament schedule grid
- ✅ `/tournament-teams` - List of tournament team rosters
- ✅ `/my-tournament-schedule` - User's tournament games
- ✅ `/my-tournament-teams` - User's tournament team
- ⏳ `/tournament/{id}` - Public tournament info page (standalone)

**Reports (deferred):**
- City Payment Report (revenue share with rainout exclusion)
- Insurance Report (player roster)
- Tournament Team Report (deposits and formation)
- Jersey Report (sizes/distribution)

**Migration (January-February):**
- Board decision on user pruning cutoff (2yr vs 3yr vs 5yr)
- Write migration scripts (users, credits, payment methods)
- Test migration with D7 data subset

---

## ARCHITECTURE HIGHLIGHTS

### Team Status System

**Status Values:**
| Status | Header Color | Opacity | Badge | Included in Schedule |
|--------|-------------|---------|-------|---------------------|
| Active | Green (#2c5f2d) | 100% | None | Yes |
| Withdrawn | Gray (#6c757d) | 65% | "W" | No |
| Disqualified | Red (#dc3545) | 65% | "DQ" | No |

**Schedule Builder Filter:**
```php
// In TournamentScheduleGeneratorService::getTeamsWithSkillLevels()
->condition('status', 'active')
```

### Captain/Co-Captain System

**Permissions:**
- Both captain and co-captain have `is_captain = TRUE` on their registration
- Both can invite players to the team
- Team entity has separate `captain` and `co_captain` fields

**Management Workflows:**

*Merge Two Small Teams:*
1. Go to Group Invitations for the team to disband
2. Change captain's dropdown → "⚠️ Release as Captain"
3. Save - Captain becomes regular player, team has no captain
4. Drag players to surviving team in Roster Builder

*Change Captain (Injured Captain):*
1. Go to Group Invitations for that team
2. Find new captain, change dropdown → "⭐ Promote to Captain"
3. Save - New captain takes over, old captain becomes regular team member

### Tournament Public Pages Architecture

**Menu Visibility Logic:**
```php
// In hook_menu_links_discovered_alter()
// Query active tournaments for visibility flags
$roster_visible_count = $tournament_storage->getQuery()
  ->condition('active', TRUE)
  ->condition('roster_visible', TRUE)
  ->count()->execute();

$schedule_visible_count = $tournament_storage->getQuery()
  ->condition('active', TRUE)
  ->condition('schedule_visible', TRUE)
  ->count()->execute();

// Hide links if no tournaments have the flag set
if ($roster_visible_count == 0) {
  $links['ccsoccer.tournament_teams.menu']['class'] = 'hidden';
  $links['ccsoccer.my_tournament_team.menu']['class'] = 'hidden';
}
```

**Route Access Control:**
| URL | Access | Visibility Depends On |
|-----|--------|----------------------|
| `/tournament-schedule` | Public | `schedule_visible = TRUE` |
| `/my-tournament-schedule` | Login Required | `schedule_visible = TRUE` |
| `/tournament-teams` | Login Required | `roster_visible = TRUE` |
| `/my-tournament-teams` | Login Required | `roster_visible = TRUE` |

### Snapshot System Architecture

```
User clicks "Save Snapshot"
    ↓
JavaScript sends POST to /snapshot/save
    ↓
Controller calls service->saveSnapshot()
    ↓
Service queries all games for entity
    ↓
Serializes game data (home_team, away_team, time_slot, field, etc.)
    ↓
Inserts into tournament_schedule_snapshot or season_schedule_snapshot table
    ↓
Returns success + updated snapshot list
    ↓
JavaScript refreshes snapshot table via refreshSnapshotList()
```

**Snapshot Restore Logic (Position-Based):**
```
User clicks "Restore"
    ↓
Load snapshot data from database
    ↓
Build lookup by POSITION (not game_id):
  - Tournament: time_slot + field → "3_Field 2"
  - Season: week_number + time_slot + field → "5_2_Field 1"
    ↓
Load current games for entity
    ↓
For each current game:
  - Build position key from game's time_slot/field
  - Look up snapshot data by position
  - Update game if data differs
    ↓
Return count of games updated
```

### Tournament Schedule Algorithm

**Matchup Generation - Round-Robin Based:**
```
1. Generate round-robin rounds using circle method
   - Fix position 0, rotate all others
   - Creates n-1 rounds for n teams (even)
   - Each round has n/2 games, each team plays once

2. Score and sort rounds by total skill gap
   - Lower total gap = more skill-balanced round
   - Select best rounds first

3. Select rounds until each team has games_per_team games
   - Guarantees exact game count (hard constraint)
   - No possibility of dead ends

4. Fallback for odd teams (byes)
   - fillRemainingMatchups() uses constraint-aware greedy
   - Most-constrained-first prevents stuck states
```

---

## DEVELOPER SETUP

### After Pulling Latest Code:
```bash
git pull origin main
ddev drush updb -y
ddev drush cr
```

### Seed Commands:
```bash
# Create test users with roles
ddev drush ccs-seed --users

# Create comprehensive test data
ddev drush ccs-seed --test --force

# Create seasons with registrations
ddev drush ccs-seed --populate-seasons

# Create tournaments with teams (all 3 tournaments: 2024, 2025, 2026)
ddev drush ccs-seed --populate-tournaments

# Full reset and reseed tournaments
ddev drush ccs-seed --force --populate-tournaments
```

### Current Update Hooks:
- 9027: Tournament and Team max_roster_size fields
- 9029: Tournament registration_visible field
- 9030: Registration ccsoccer_pool field
- 9031: Tournament active field for admin menu visibility
- 9032: Rename Tournament schedule_generated to schedule_visible
- 9033: Tournament scheduling fields (num_fields, game_duration, etc.)
- 9034: Team skill level fields (calculated_skill_level, admin_skill_level)
- 9035: Team admin_skill_level decimal conversion
- 9036: Team group_id UUID field + migration
- 9037: Schedule snapshot tables creation
- 9038: Tournament roster_visible field
- **9039: Team status and weight fields** (NEW)

---

## TESTING NOTES

### Testing Team Status Management:
1. Run `ddev drush updb` to apply update hook 9039
2. Run `ddev drush cr` to clear caches
3. Navigate to Tournament Teams page (`/admin/ccsoccer/tournament/{id}/teams`)
4. **Verify Status dropdown appears** for each team
5. Change a team's status to "Withdrawn"
6. Navigate to Roster Builder - **Verify:**
   - Team column has gray header with "W" badge
   - Team appears at 65% opacity
   - Header shows separate "Teams" and "Active Teams" counts
7. Generate schedule - **Verify:**
   - Withdrawn/Disqualified teams are NOT included in schedule

### Testing Captain/Co-Captain Management:
1. Navigate to Group Invitations for a tournament team
2. **Test Release Captain:**
   - Captain row should show dropdown with "⚠️ Release as Captain"
   - Select and Save
   - **Verify:** Captain becomes regular player, team has no captain, players stay on team
3. **Test Promote to Captain:**
   - Find an accepted player
   - Change dropdown to "⭐ Promote to Captain"
   - Save
   - **Verify:** Player becomes captain, old captain (if any) becomes regular member
4. **Test Co-Captain:**
   - Promote a different player to Co-Captain
   - **Verify:** Co-Captain row appears with blue styling
   - Release Co-Captain and verify they become regular member

### Testing Tournament Public Pages:
1. Set `roster_visible = TRUE` and/or `schedule_visible = TRUE` on a tournament
2. **Verify menu links appear:**
   - "Tournament Teams" and "Tournament Schedule" in main Links section
   - "My Tournament Team" and "My Tournament Schedule" in Player Links section
3. Visit `/tournament-schedule`:
   - Should show tournament tabs if multiple tournaments visible
   - Should show grid with time slots as rows, fields as columns
4. Visit `/tournament-teams`:
   - Should require login (redirect anonymous users)
   - Should show all teams with captain and player roster

### Testing Snapshot Feature:
1. Navigate to `/admin/ccsoccer/tournament/{tournament}/schedule`
2. Generate a schedule
3. Click "💾 Save Snapshot" - verify toast appears and snapshot added to list
4. Make changes to the schedule (drag teams around)
5. Click "Restore" on the snapshot
6. **Verify:** Schedule reverts to saved state, toast shows correct game count

---

## NEXT STEPS (Priority Order)

### UI/UX Enhancements:
1. **Roster Builder team drag-and-drop reordering**
   - Make team columns draggable (separate from player drag)
   - AJAX endpoint to save new order (update weight field)
   - Visual drop indicators between columns

2. **Tournament pill boxes**
   - Update Tournament Public and private views
   - Use pill box styling for tournament name selection

3. **Player credits UI investigation**
   - Determine if UI exists for crediting individual players
   - If not, design and implement

4. **Season/Tournament player filter**
   - Add sub-menu to filter players by specific season or tournament

### Later (Phase 4):
5. Tournament public info page (`/tournament/{id}`)

---

## HISTORICAL SESSION SUMMARIES

### Session: Team Status, Co-Captain, Captain Management (January 13, 2026 - This Session)
```
feat(tournament): Add team status and weight fields for management
feat(tournament): Add co-captain support and captain management

Team Status Management:
- Add status field (active/withdrawn/disqualified) to Team entity
- Add weight field for drag-and-drop ordering
- Roster Builder sorts by weight, shows status badges (W/DQ)
- Schedule Builder filters to only active teams
- Visual styling: withdrawn=gray, disqualified=red

Co-Captain Support:
- Add co_captain field to Team entity
- Add helper methods hasCoCaptain getCoCaptainId isTeamLeader
- Both captain and co-captain have is_captain=TRUE for invite permissions

Captain Management via Group Invitations:
- Captain can be released (stays on team as regular player)
- Accepted players can be promoted to Captain or Co-Captain
- Co-Captain can be released back to regular player

Seed Command:
- populateTournamentsWithTeams() now populates all 3 tournaments
```

### Session: Tournament Public Pages (January 11, 2026)
```
feat(tournament): add tournament public pages with schedule and teams views

Phase 1: Tournament roster_visible field
- Add roster_visible boolean field to Tournament entity
- Create idempotent update hook 9038 with helper function

Phase 2: Dynamic menu links
- Add 4 tournament menu links with conditional visibility
- Links show only when roster_visible or schedule_visible is TRUE

Phase 3: TournamentScheduleGridBuilder service
- Create new service for rendering tournament schedule grids
- Support MODE_PUBLIC and MODE_MY_SCHEDULE display modes

Phase 4: Controller methods and routes
- Add 4 new routes and controller methods
- Tournament tabs with smart default selection
- Captain display on tournament team cards

Phase 5: CSS library
- Create tournament-schedule-grid.css with full styling
- Responsive breakpoints for tablet and mobile
```

### Session: Snapshot Restore Fix (January 11, 2026)
```
fix(snapshots): restore functionality and UI spacing

- Fix restoreSnapshot() to use position-based matching instead of game_id
  - Tournament: matches by time_slot + field
  - Season: matches by week_number + time_slot + field

- Fix CSS spacing for Saved Snapshots section arrow
```

### Session: Schedule Snapshot Feature (January 11, 2026)
```
feat(snapshots): add schedule snapshot save/restore system for tournaments and seasons

- Create tournament_schedule_snapshot and season_schedule_snapshot tables
- Add saveSnapshot, listSnapshots, restoreSnapshot, renameSnapshot, deleteSnapshot
- Add snapshot AJAX endpoints and JavaScript handlers
```

### Session: Tournament Schedule Bug Fixes (January 11, 2026)
```
fix(tournament): fix schedule generation and enable true grid drag-drop

- Replace greedy matchup algorithm with round-robin based selection
- Fix type casting in createEmptyGameShells for consistent key matching
```

### Session: Strategy Documentation + True Grid Drag-Drop (January 11, 2026)
```
Tournament Schedule Builder enhancements:
- Add Scheduling Strategy documentation section
- Implement true grid drag-drop with empty game shells
- Add rest issue warnings for back-to-back games
```

### Session: Admin Team Creation UI + Group ID UUID Migration (January 11, 2026)
```
Add admin team creation UI and update tournament seed data

- Add Create Team button and inline form to Tournament Teams page
- Add group_id field to Team entity with UUID storage
- Update tournament seed data with 2025 SLO Friendly team names
```

### Session: Tournament Schedule Builder Phases 1-4 (January 11, 2026)
```
Add Tournament Schedule Builder with drag-drop editing

- Add scheduling fields to Tournament entity
- Add skill level fields to Team entity
- Create TournamentScheduleGeneratorService with skill-based matchups
- Create TournamentScheduleBuilderForm with grid display
```

### Earlier Sessions (Reference):
- Tournament Overview Page + Admin UX
- Tournament Roster Builder + Seed Data
- Tournament Invite Flow Fix
- Tournament Registration System Phases 1-2
- Multi-season notification system
- Game status banner with auto-reset and credits
- Mobile menu iOS fixes
- Cancelled game display overlays
- Board/Director dashboard role-based access
- Jersey purchase waiver skip logic
- Season publishing visibility flags

---

## GIT COMMIT MESSAGES (This Session)

```
feat(tournament): Add team status and weight fields for management

- Add status field (active/withdrawn/disqualified) to Team entity
- Add weight field for drag-and-drop ordering
- Add Status dropdown column to Tournament Teams page
- Add AJAX handler for status updates
- Add CSS for status dropdown and indicators
- Existing teams default to active status
- Weight initialized based on alphabetical order
```

```
feat(tournament): Add co-captain support and fix schedule builder team filtering

Schedule Builder fixes:
- Filter teams by status=active (exclude withdrawn/disqualified)
- Get player counts from registrations instead of stale team data
- Roster Builder header now shows Active Teams count separately

Captain management via Group Invitations:
- Captain can be released (stays on team as regular player)
- Accepted players can be promoted to Captain or Co-Captain
- Co-Captain can be released back to regular player

Co-Captain support:
- Add co_captain field to Team entity
- Add helper methods hasCoCaptain getCoCaptainId isTeamLeader
- Both captain and co-captain have is_captain=TRUE for invite permissions
- Style co-captain dropdown with blue theme in Group Invitations
```

---

**End of Session Handoff**
