# CC Soccer D11 - Session Handoff

**Last Updated:** January 26, 2026 - Morning  
**Status:** ✅ Tournament invitation flow fixes complete

---

## Quick Reference

### Installation
See `INSTALLATION_GUIDE.md` for full details. Quick start:
```bash
git clone https://github.com/caleb-ccsoccer/ccsoccer-d11.git
cd ccsoccer-d11
ddev start
ddev composer require drush/drush
ddev drush site:install standard --site-name="CC Soccer D11" --account-name=admin --account-pass=admin -y
ddev drush config:set system.site uuid $(grep uuid config/sync/system.site.yml | awk '{print $2}') -y
ddev drush entity:delete shortcut_set default -y
ddev drush cim -y
ddev drush updb -y
ddev drush cr
ddev drush ccs-seed --users
ddev launch
```

### Common Commands
```bash
ddev drush cr                              # Clear cache
ddev drush updb -y                         # Run database updates
ddev drush cex -y                          # Export config
ddev drush cim -y                          # Import config
ddev drush ccs-seed --users                # Seed test data
ddev drush ccs-seed --test --force         # Registration testing data
ddev drush ccs-seed --force --populate-seasons  # Season testing data
```

### Test Accounts
| Username | Password | Role |
|----------|----------|------|
| `admin` | `admin` | Administrator |
| `player_test` | `password` | Authenticated |
| `board_test` | `password` | Board Member |
| `slofriendly_test` | `password` | Slofriendly |
| `testuser0` | `password` | Authenticated (for personalized states) |

---

## ✅ COMPLETED THIS SESSION (January 26, Morning)

### Bug Fix: Tournament Invitation Flow

**Issue:** Andrew identified multiple problems with the tournament invitation flow:
1. Click invite link → works correctly
2. My Registrations "Register to Accept" button → went to `/register` without invite token
3. `/register` page → no mention of pending invitations

**Fixes Applied:**

#### Fix 1: Template - Register to Accept button includes invite token
- **File:** `templates/ccsoccer-my-registrations.html.twig`
- Changed link from `path('ccsoccer.register')` to `path('ccsoccer.register', {invite: item.invitation.token.value})`
- Now triggers the proper invitation flow

#### Fix 2: acceptTeamInvitationDirectly() uses UUID group_id
- **File:** `src/Controller/RegistrationController.php`
- **Function:** `acceptTeamInvitationDirectly()`
- Was using: `'team_' . $team->id() . '_' . $captain_id`
- Now uses: `$team->getGroupId()` (UUID from Team entity)

#### Fix 3: Pending invitations banner on /register page
- **File:** `src/Controller/RegistrationController.php`
- **New methods:** `getPendingInvitationsForUser()`, `buildPendingInvitationsSection()`
- Yellow banner at top of `/register` page shows pending invitations
- Shows team/tournament name and who invited them
- "Register & Join" button for unregistered users (adds to cart with token)
- "Accept Invitation" button for already registered users (accepts directly)
- "Decline" button to reject invitation

**Updated Flow:**

| Scenario | What Happens |
|----------|--------------|
| Click invite link (not logged in) | → Login → Returns to `/register?invite=TOKEN` → Auto-processes |
| Click invite link (logged in, not registered) | → Adds tournament to cart → Checkout |
| Click invite link (logged in, already registered) | → Accepts directly → Redirects to team page |
| My Registrations → "Register to Accept" | → `/register?invite=TOKEN` → Same as clicking invite link |
| Go to `/register` directly | → Sees yellow banner with pending invitations → Can accept/decline |

---

### Earlier This Session: Group Management Fixes

#### Bug Fix: My Registrations Filter for Past Seasons/Tournaments
- **File:** `src/Controller/GroupController.php`
- **Function:** `myRegistrations()`
- Added date filtering to skip seasons/tournaments where `end_date < today`

#### Bug Fix: Co-Captain Invitation Permissions
- **File:** `src/Controller/GroupController.php`
- **Function:** `manage()`
- Changed to use `$team->isTeamLeader($this->currentUser->id())` for tournaments
- Both captain and co-captain can now manage team and send invitations

#### Bug Fix: Duplicate Invitation Prevention
- **File:** `src/Controller/GroupController.php`
- **Function:** `invite()`
- Three checks: (1) Already on THIS team, (2) Already on ANOTHER team in tournament, (3) Duplicate from SAME team
- Players CAN receive multiple pending invitations from DIFFERENT teams

#### Bug Fix: Tournament Team group_id Using UUID
- **File:** `src/Controller/GroupController.php`
- **Functions:** `invite()`, `acceptTeamInvitation()`
- Now uses Team entity's UUID `group_id` instead of captain-based format

---

## Files Modified This Session

| File | Function | Change |
|------|----------|--------|
| `src/Controller/GroupController.php` | `myRegistrations()` | Filter out past seasons/tournaments |
| `src/Controller/GroupController.php` | `manage()` | Use `Team::isTeamLeader()` for permissions |
| `src/Controller/GroupController.php` | `invite()` | 3-tier duplicate check, UUID group_id |
| `src/Controller/GroupController.php` | `acceptTeamInvitation()` | UUID group_id |
| `src/Controller/RegistrationController.php` | `acceptTeamInvitationDirectly()` | UUID group_id |
| `src/Controller/RegistrationController.php` | `available()` | Added pending invitations section |
| `src/Controller/RegistrationController.php` | NEW: `getPendingInvitationsForUser()` | Helper method |
| `src/Controller/RegistrationController.php` | NEW: `buildPendingInvitationsSection()` | Helper method |
| `templates/ccsoccer-my-registrations.html.twig` | Register to Accept button | Include invite token |

---

## Testing Checklist - This Session's Fixes

### Tournament Invitation Flow
1. [ ] Click invite link (not logged in) → prompts login → processes invite
2. [ ] Click invite link (logged in, not registered) → adds to cart → checkout
3. [ ] Click invite link (logged in, already registered) → accepts directly
4. [ ] My Registrations "Register to Accept" → goes to `/register?invite=TOKEN`
5. [ ] `/register` page shows yellow banner with pending invitations
6. [ ] "Register & Join" button adds to cart with invite context
7. [ ] "Accept Invitation" button accepts directly (if already registered)
8. [ ] "Decline" button declines invitation

### Earlier Fixes
1. [x] Past seasons/tournaments filtered from My Registrations
2. [x] Co-captain can send invitations
3. [x] Duplicate invitations blocked from same team
4. [x] Multiple teams can invite same player
5. [x] Tournament group_id uses UUID

---

## ✅ COMPLETED PREVIOUS SESSION (January 25, Late Evening)

### Bug Fix: Cart Duplicate Prevention
- Added cart item check before adding season/tournament
- Shows warning and redirects to checkout if item already in cart

### Bug Fix: Re-registration After Cancellation
- Changed duplicate check to exclude cancelled registrations
- Users can now re-register after admin cancels their registration

---

## Project Status (~90% Complete)

### ✅ Complete
- All 10 custom entities + SeasonCreditEvent entity
- Registration flow (season + tournament)
- Group management system (with co-captain support) ✅
- Roster builder with drag-drop and balancing
- Schedule builder with round-robin generation
- Notification service (email/SMS)
- Game status with auto-reset and credits
- Credits system (Phases 1-5, A, B, C complete)
- Season publishing with visibility flags
- Override system with admin UI
- Content pages
- Masquerade for testing
- Cart duplicate prevention
- Team roster access control
- Registration page cache invalidation
- Duplicate registration prevention
- Override status mismatch fix
- Capacity validation defense in depth
- Season-specific notification links
- Dashboard waitlist/reserved columns
- Phase A: Season Credits Summary Page
- Schedule cancellation overlay (Andrew)
- All Players admin page with search/pagination
- Inline skill level editing on player pages
- My Registrations filter for past seasons ✅
- Co-captain invitation permissions ✅
- Tournament team UUID group_id ✅
- Tournament invitation flow improvements ✅

### 📋 Backlog
- Reports (City Payment, Insurance, Tournament Team, Jersey)
- Migration scripts from D7
- Mobile testing
- End-to-end testing

---

## Credits System Overview (All Phases Complete)

| Phase | Description | Status |
|-------|-------------|--------|
| Phase 1 | Credits entity with cents-based storage | ✅ |
| Phase 2 | CreditManagerService with FIFO usage | ✅ |
| Phase 3 | Checkout integration with credits pane | ✅ |
| Phase 4 | Credit sources (rainout, cancellation, admin) | ✅ |
| Phase 5 | GameStatusForm with credit preview | ✅ |
| Phase A | Season Credits Summary Page | ✅ |
| Phase B | Admin User Credits Management | ✅ |
| Phase C | Player Credits Page (/my-credits) | ✅ |

---

## Key Entity Relationships (Tournament Teams)

```
Tournament
  └── Team (has group_id UUID, captain, co_captain, players[])
        └── Registration (links player to team, stores group_id)
        └── Invitation (links to team by team_id, not group_id)
```

**Important:** For tournaments, the Team entity is the source of truth for:
- `players` field - who is on the team
- `captain` field - the team captain (user reference)
- `co_captain` field - the co-captain (user reference)
- `group_id` field - UUID for admin URLs (NOT captain-based)

The `Team::isTeamLeader($user_id)` method returns TRUE if user is captain OR co-captain.

---

## 📋 Deferred TODOs

### 1. Enhance Cancellation Notification
- Add credit/refund details to `sendRegistrationCancelled()` notification
- Currently just says "has been cancelled" without financial details

---

## Collaboration Notes

**Working with Andrew:**
- Always `git pull` before `git push`
- Use SESSION_HANDOFF.md for detailed context
- Andrew completed: Schedule cancellation overlay ✅

**Code Style:**
- Complete functions (not partial updates)
- Detailed logging for debugging
- Clear comments explaining business logic

---

## Recent Changes Log

**January 26, 2026 (Morning):**
- Fixed tournament invitation flow for seamless user experience
- Template: Register to Accept button now includes invite token
- RegistrationController: acceptTeamInvitationDirectly uses UUID group_id
- Register page: Added pending invitations banner for logged-in users

**January 26, 2026 (Early Morning):**
- Fixed My Registrations to filter out past seasons/tournaments
- Fixed co-captain invitation permissions using Team::isTeamLeader()
- Added 3-tier duplicate invitation prevention for tournaments
- Fixed tournament group_id to use UUID stored on Team entity (not captain-based)

**January 25, 2026 (Late Evening):**
- Fixed cart duplicate prevention - checks cart before adding season/tournament
- Fixed re-registration after cancellation - excludes cancelled registrations from duplicate check

**January 25, 2026 (Evening):**
- Added inline skill level editing to Season Players and All Players pages
- Created PlayerSkillController with AJAX endpoint
- Added player-skill.js for auto-save with visual feedback
- Updated sort order on Season Players (empty skill first, then by name)
- Added sticky table headers accounting for Drupal admin toolbar

**January 25, 2026 (Afternoon):**
- Marked Schedule cancellation overlay as complete (Andrew)

**January 25, 2026 (Morning):**
- Completed Phase A: Season Credits Summary Page
- Created SeasonCreditEvent entity
- Added two-step Add Season Credit form

---

## Documentation Index

| Document | Purpose |
|----------|---------|
| `INSTALLATION_GUIDE.md` | Full setup instructions, troubleshooting |
| `SESSION_HANDOFF.md` | This file - current state and handoff notes |
| `PROJECT_STATUS.md` | Detailed project status |
| `ARCHITECTURE_DECISIONS.md` | Key architecture decisions |
| `REQUIREMENTS_TO_ARCHITECTURE.md` | Original requirements mapping |

---

**End of Session Handoff**
