# CC Soccer D11 - Session Handoff
**Date:** May 23, 2026
**Branch:** `main`

---

## Current State

### 🎉 SITE IS LIVE at ccsoccer.com
Soft-launch mode (IP whitelist active). Board members + beta testers testing. Andrew meeting with Caleb tomorrow (May 23) to create real 2026 season + tournament and open beta wider.

### Code — All Servers In Sync
Local, TEST, and PROD all current on `main`. No pending deploys.

---

## Session Work — May 23, 2026

### Module Updates ✅ COMPLETE
- Drupal core 11.3.9 → 11.3.10 (security update) — deployed to TEST + PROD
- Better Exposed Filters 7.1.1 → 7.1.2 (had schema updates, ran updb) — deployed to TEST + PROD
- WebAuthn 2.0.0-rc7 → 2.1.0-beta1 — **deferred to this weekend** (needs careful auth testing)
- reCAPTCHA 8.x-3.5-rc1 — skipped (RC, not ready)

### Deploy Aliases Fixed ✅
`ccsDeploy` and `ccsProdDeploy` in `~/.bashrc` on server now include `composer install` after `git pull`. Previously composer was never running on deploys, meaning module updates weren't actually applied to the servers. Fixed and confirmed working.

### Migration Welcome Email ✅ COMPLETE
Bulk welcome email system fully built and tested. Queues email to all 1,729 active users.

**To send on go-live day (on PROD):**
```bash
cd ~/public_html/ccsoccer_site
PATH=/opt/cpanel/ea-php83/root/usr/bin:$PATH /opt/cpanel/ea-php83/root/usr/bin/php vendor/drush/drush/drush.php -r web ccsoccer:migration-welcome
# Then let cron pick up the queue, or run manually:
PATH=/opt/cpanel/ea-php83/root/usr/bin:$PATH /opt/cpanel/ea-php83/root/usr/bin/php vendor/drush/drush/drush.php -r web queue:run ccsoccer_notification
```

**Fixes applied this session:**
- Hardcoded password reset URL to `https://ccsoccer.com/user/password` (was generating `http://default/` in Drush CLI context)
- Updated profile photo copy per Haley's feedback: "Please ensure you choose a pic that clearly shows you (and only you) so we know who you are."

**Logo:** Shows broken in test emails because Yahoo Mail proxy hits ccsoccer.com which is IP-whitelisted. URL is correct — will work post-launch.

**Remaining "CC Soccer":** Tournament deposit and jersey notification functions still say `CC Soccer`. Deferred.

### Pre-Launch Security Checklist ✅ COMPLETE
- ✅ `trusted_host_patterns` — set on both TEST and PROD `settings.local.php`
- ✅ `hash_salt` — set on PROD `settings.local.php`
- ✅ Devel — confirmed uninstalled on PROD; intentionally left on TEST for debugging
- ✅ HTTPS redirect + www → non-www — confirmed in `web/.htaccess` on PROD

### Cron ✅ COMPLETE
- PROD cron added to cPanel: every 15 min via `ea-php83` + drush pointing at `ccsoccer_site`
- Old D7 cron entry (`ccsoccer.com/cron.php?cron_key=...`) deleted
- TEST cron was already in place, left as-is

### Security Metrics ✅ IN PROGRESS
- Four SecurityMetrics scanner IPs whitelisted in PROD `web/.htaccess`
- Waiting on SecurityMetrics to complete scan and provide next steps

### Authorize.net Live Config ✅ RE-ENTERED
- `drush cim` had overwritten PROD payment gateway with sandbox config
- Re-entered live credentials (see Authorize.net section below)
- **Action needed:** Audit full scope of what cim overwrites on PROD (checklist item #1)

### Team Name Taxonomy Refactor ✅ COMPLETE (Phase 1)
- Replaced `field_league` and `field_tournament` on `team_names` vocabulary with `field_team_name_league` and `field_team_name_series`
- Added `TournamentSeries` entity — persistent recurring tournament concept (e.g. "SLO Friendly")
- Added `tournament_series` field to Tournament entity
- Taxonomy term form updated to show league + series fields
- `TeamManagerService` updated to query correct field names
- `ccsoccer_season_insert()` hook now fires regardless of active status; `ccsoccer_season_update()` creates teams when season flips to active
- `OrderCompleteSubscriber::createTournamentRegistration()` now creates a taxonomy term when captain registers and creates a team (term tagged to the tournament series for historical reference)
- **Key finding:** Tournament team creation uses `OrderCompleteSubscriber`, NOT `TournamentTeamManager::createTeam()` or `_ccsoccer_process_tournament_registration()` in ccsoccer.module
- **Still needed (2b/2c/2e):** See checklist item 2 sub-items

### SecurityMetrics Test Product
- Created product type "Security Metrics Test" on PROD via UI (not in config/sync) — caused `cim` failure
- Deleted product + product type via cim after removing DB records
- TODO: Recreate properly — create product type on LOCAL, cex, deploy, then create product entity on PROD

### config_ignore ✅ INSTALLED
- Payment gateway configs now ignored by `drush cim` on all environments
- Payment gateway credentials safe from accidental cim overwrites

### Authorize.net Re-entry Note
- Had to re-enter live credentials after cim overwrote them (before config_ignore was in place)
- Going forward: credentials are safe, cim won't touch payment gateways

---

## Combined Pre-Launch Checklist

### 🚨 Immediate

1. ~~**Caleb** — Audit what `drush cim` overwrites on PROD.~~ ✅ DONE — Installed config_ignore; payment gateways now ignored by cim; manual/nab dev gateways deleted; system.site stays in sync.

2. **Caleb** — Team names: currently associated to season/tournament. Refactor so team name terms are associated to a league or tournament series — when a new season/tournament is created, team names default from the parent. Phase 1 (foundational) complete — TournamentSeries entity, taxonomy fields, tournament_series field on Tournament all installed.
   - 2a. DONE -- Taxonomy term form shows league + series fields
   - 2b. `/admin/ccsoccer/team/add` still needed for admin-created tournament teams; needs UX polish to pre-filter terms by series. Discuss with Andrew.
   - 2c. DONE -- `TeamManagerService` field names updated; season teams auto-create on season insert/active flip; tournament captain registration creates taxonomy term tagged to series. KEY: tournament team creation is in `OrderCompleteSubscriber::createTournamentRegistration()`, NOT `TournamentTeamManager`.
   - 2c (cont). Phase 2: Admin UI — roster builders filter team name options by league/series. **Need to review with Andrew first** — `TeamBalancerService.suggestRosters()` requires existing Team entities (`loadTeamsForSeason()`). `TeamManagerService.createTeamsForSeason()` exists but unclear if/where it's called from UI. `getTeamNameTermsForLeague()` queries `field_league` (old field name — our new field is `field_team_name_league`). `getTeamNameTermsForTournament()` queries `field_tournament` (needs to query `field_team_name_series` via tournament’s series). Understand full flow before touching.
   - 2d. Phase 3: Roster builder verification
   - 2e. Add league/series columns and filter to team names taxonomy overview (`/admin/structure/taxonomy/manage/team_names/overview`)

---

### Before Opening Whitelist to Public

3. **Andrew** — Vanishing CAPTCHA: confirm stays visible after correct CAPTCHA + wrong password.

4. **Andrew** — Create real SLO Friendly 2026 season + tournament (doing May 23).

5. **Caleb** — Commerce checkout end-to-end with real card on PROD (season registration + jersey-only paths).

6. **Andrew** — Geo/country blocking via Cloudflare.

7. **Caleb** — Remove IP whitelist from `web/.htaccess` on go-live day (both servers, skip-worktree protected).

8. **Andrew** — Delete `ccsoccer-d11-migrated-200users.sql` from repo root if present (contains real user data).

9. ✅ DONE — Pre-launch security checklist (trusted_host_patterns, hash_salt, Devel, HTTPS redirect).

10. ~~**Caleb** — Security Metrics automated testing setup.~~ — SecurityMetrics IPs whitelisted in PROD `.htaccess`; waiting on SecurityMetrics to complete scan and provide next steps.

11. ~~**Caleb** — Configure cron on PROD via cPanel, every 15–30 min.~~ ✅ DONE — PROD cron running every 15 min; D7 cron entry deleted.

---

### Mid-term

12. `test@ccsoccer.com` mailbox decision.

13. Andrew's local environment DB update.

14. `slofriendly` config role reference cleanup (Andrew).

15. **Caleb** — WebAuthn passkey 2.0.0-rc7 → 2.1.0-beta1. **Do this weekend** — test full auth flow after.

16. Backup strategy verification.

17. CSP headers in report-only mode.

---

### Post-Launch / First 72 Hours

18. ✅ DONE — Assign `permanent_override` role (Haley, Layne, Julie, Myk, Kyle).

19. ✅ DONE — Verify credit balances against D7.

20. ✅ DONE — Check credits/registrations after April 16 dump date.

21. Remove `beta_tester` role from all users.

22. `slofriendlysoccer.com` URL forward.

23. Archive/delete D7 waivers; eventually delete `ccsoccer_site_d7_archive/`.

24. Monitor login rate, password resets, unhandled exceptions for first 72 hours.

25. Add Devel back to TEST.

---

### Development (Deferred)

26. Three-tier button methodology pass.

27. CSS consolidation — design tokens across ~33 CSS files.

28. Team handling refactor.

29. Profile picture migration — board decision pending.

30. Fix remaining `CC Soccer` → `CCSoccer` in tournament deposit + jersey notification subjects/SMS bodies.

---

## DB Quick Reference

### Production DB (live)
- DB: `n6ac4b5_d11live`
- User: `n6ac4b5_ccsoccer_user`
- Password: `vGL3KWO(K8C;`

### TEST DB
- DB: `n6ac4b5_d11test`
- User: `n6ac4b5_ccsoccer_user`
- Password: `vGL3KWO(K8C;`

### D7 archive DB
- DB: `n6ac4b5_ccsoccer`
- User: `n6ac4b5_ccsoccer_user`
- Password: `vGL3KWO(K8C;`

### Local D11 DB
- Admin: `admin` / `TJ4XxyYGCd`

---

## Server Directory Structure
```
/home/n6ac4b5/public_html/
  ccsoccer_site/            ← PRODUCTION (ccsoccer.com)
  ccsoccer_site_d7_archive/ ← D7 archive (old.ccsoccer.com, PHP 7.2)
  test_ccsoccer_site/       ← TEST (test.ccsoccer.com)
  slofriendly_redirect/     ← slofriendlysoccer.com redirect
```

---

## Email Architecture

### Pipeline
```
NotificationService / OrderCompleteSubscriber
  → Symfony Mailer pipeline
    → Inline CSS + Theme wrapper (email.html.twig)
    → URL to absolute + Wrap and convert
  → Google Workspace SMTP (TEST + prod)
  → Mailpit (local DDEV only)
```

### Key Files
- `web/modules/custom/ccsoccer/src/Service/NotificationService.php`
- `web/modules/custom/ccsoccer/src/Plugin/QueueWorker/NotificationQueueWorker.php`
- `web/modules/custom/ccsoccer/src/Commands/NotificationCommands.php`
- `web/themes/custom/ccsoccer_theme/templates/email/email.html.twig`

### Notification gating
- `site_instance = 'local'` → board members only (Mailpit catches all)
- `site_instance = 'test'` → board members + beta_testers only (real emails)
- `site_instance = 'production'` → all users

### Queue Worker — SMS suppression
When `sms_body === ''` (explicitly empty), `processItem()` calls `sendEmail()` directly, bypassing `send()` which would strip HTML for SMS. This is how migration welcome email avoids SMS.

### SMTP config (in settings.local.php, never in git)
- Host: `smtp.gmail.com`, Port: `465`, TLS: true
- User: `ccsoccer@ccsoccer.com`
- App password: `sqygkfykzwrziota`

### reCAPTCHA Keys
- Site key: `6LchguosAAAAC5kLFmKj0xCGdEWXNntLacANpVN`
- Secret key: `6LchguosAAAANBJ8ikcrZvYQMxs6-FM2YHbzPEl`

### Authorize.net Live Credentials (PROD only — never commit)
- API Login ID: `9Fus5B2a`
- Transaction Key: `7MA8r27R9KQrs3Kd`
- Public Client Key: `5ep4C2xSvyY4jpra4694guKsJyV6XGq2CB39SHRtrs59wHH47avwTfKM7R7xJ7hF`
- Mode: Live
- Plugin: Authorize.net Accept.js
- Configure at: `/admin/commerce/config/payment-gateways`

**Note:** `drush cim` will overwrite these if payment gateway config is in `config/sync`. Always re-enter after any config import on PROD.

---

## Key Facts / Gotchas

### beta_tester role — do not delete from config/sync
Always `git checkout config/sync/user.role.beta_tester.yml` after `drush cex`.

### Google SMTP App Password
`sqygkfykzwrziota` — in `settings.local.php` on TEST and prod servers only.

### Symfony Mailer — User override
Do NOT enable the "User" override — replaces HTML with plain text.

### DB import fix for InMotion
```bash
gunzip -c dump.sql.gz | sed 's/DEFINER=[^*]*\*/\*/' | gzip > dump-clean.sql.gz
```

### Two-file CSS sync
- `web/modules/custom/ccsoccer/css/ccsoccer-base.css` (admin)
- `web/themes/custom/ccsoccer_theme/css/base.css` (public)

### composer install on servers
```bash
PATH=/opt/cpanel/ea-php83/root/usr/bin:$PATH /opt/cpanel/ea-php83/root/usr/bin/php /opt/cpanel/composer/bin/composer install --ignore-platform-req=ext-intl
```

### Migration welcome email — password reset URL
Hardcoded to `https://ccsoccer.com/user/password` in `sendMigrationWelcome()`. `Url::fromRoute()` generates `http://default/` in Drush CLI context.

### CAPTCHA admin path
`/admin/config/people/captcha` — must be logged in as `admin` user. Use private window to test.

---

## Server Quick Reference
```bash
# SSH in
ssh ccsoccer

# TEST deploy (includes composer install)
ccsDeploy && ccsCr

# PROD deploy (includes composer install)
ccsProdDeploy && ccsProdCr

# Full deploy with DB updates
ccsDeploy && ccsUpdb && ccsCim && ccsCr
ccsProdDeploy && ccsProdUpdb && ccsProdCim && ccsProdCr

# Drush full path (TEST/PROD)
PATH=/opt/cpanel/ea-php83/root/usr/bin:$PATH /opt/cpanel/ea-php83/root/usr/bin/php vendor/drush/drush/drush.php -r web [command]
```

## .htaccess — both servers
Not in git — protected via `git update-index --skip-worktree web/.htaccess`

## Git Workflow
- Always `git pull` before `git push`
- `main` is the primary branch
- `settings.local.php` is NOT in git
- Always `git checkout config/sync/user.role.beta_tester.yml` after `drush cex`
