# CC Soccer D11 - Session Handoff
**Date:** March 21, 2026
**Session:** Migration prep — field cleanup, migrate command updates
**Branch:** `main`

## Last Updated
2026-03-21 — Migration prep session

---

## What Happened This Session

### Update hook 9061 — removed unused user fields
Four fields removed from the User entity (already deployed locally via `ddev drush updb`):
- `field_has_jersey` — superseded by registration history query (count regs > 0)
- `field_jersey_size` — jersey size is order data, not user data
- `field_credits_balance` — `CreditManagerService::getUserBalanceCents()` queries Credits entities directly, never read this field
- `field_notification_prefs` (plural, multi-value) — dead field; `field_notification_preference` (singular) is what `NotificationService` actually reads

**Andrew:** Run `ddev drush updb -y` then `ddev drush cr` after pulling.

### MigrateCommands.php — three additions
File: `web/modules/custom/ccsoccer/src/Drush/Commands/MigrateCommands.php`

1. **`field_phone` now populated** — added `LEFT JOIN {sms_user} su ON u.uid = su.uid` to the user query; `su.number` maps to `field_phone`. Phone numbers live in D7's `sms_user` table, not a field table.

2. **`field_notification_preference` now populated** — D7's `field_message_preference` value maps directly except `sms` → `text` (D11 uses `text` instead of `sms`).

3. **`--dev` flag added** — controls password behavior:
   - `--dev` → all users get `CCSoccer2026!` (for local masquerading)
   - No flag (default) → each user gets `bin2hex(random_bytes(16))` (production-safe random password)
   - Users reset their password on first login via the launch email

4. **`updateCreditBalances()` removed** — was setting `field_credits_balance` on users post-migration, but that field is now gone. Credits are always queried live from the Credits entity.

### Team handling — deferred refactor (discuss with Andrew first)
Decided the current eager team creation (all term Teams created on season save) should be changed to lazy creation (Teams only created when Roster Builder opens, empty ones deleted on save). This matches D7 behavior — team names are just taxonomy terms, Team entities only exist when players are assigned.

**Do not implement until:** migration is complete, Andrew's passkey work is merged, and Andrew has been consulted (he built the roster builder).

**The three changes when ready:**
1. `ccsoccer.module` `ccsoccer_season_insert` — remove `createTeamsForSeason()` call
2. `TeamBalancerService::getRosterState()` — add lazy creation if no teams exist yet for season
3. `RosterBuilderController::save()` — delete Team entities with zero players after save

---

### Migration strategy decisions made
- **Option B confirmed:** Run migration locally in DDEV, export DB, upload to server. Never run migration command on shared hosting (timeout/memory risk).
- **Third DB on server** will be `n6ac4b5_d11prod` — created in cPanel when ready, separate from the existing test DB.
- **D7 dump:** Need a fresh pull from production (spring registrations + any credits since last pull). Caleb handles via SSH — see next steps.
- **Pull timestamp:** When D7 dump is taken, record the datetime. Post-launch checklist: verify any credits issued after that datetime, any new users, any waitlist changes.

### Migration command usage
```bash
# Local dev (masquerade-friendly passwords):
ddev drush ccsoccer:migrate-d7 --dev

# Full local dev run with limit:
ddev drush ccsoccer:migrate-d7 --dev --limit=200

# Dry run to verify counts:
ddev drush ccsoccer:migrate-d7 --dry-run

# Production migration (random passwords — NO --dev flag):
ddev drush ccsoccer:migrate-d7
```

---

## Current State of Local Environment

- **Update 9061 run:** ✅ Four user fields removed from local DB
- **MigrateCommands.php:** ✅ Updated with phone, notification pref, --dev flag
- **D7 source dump:** ❌ Not yet on disk locally — needs fresh pull from production
- **D11 local DB:** Has existing seeded/test data from prior dev sessions — needs reset before production migration run
- **CSS aggregation:** Still off on TEST (intentional during dev)

---

## Next Steps (In Order)

### 1. SSH into InMotion (Caleb only — in progress this session)
Set up SSH access to the production server. Required for pulling D7 dump and eventually creating the third DB. Per-machine setup — Caleb is the gatekeeper, Andrew does not need server access.

See `DEPLOYMENT_GUIDE.md` Section 2 for full steps. Short version:
1. cPanel → Security → SSH Access → Manage SSH Keys → Generate New Key
2. Authorize the key, download private key to `~/.ssh/inmotion_key`
3. `chmod 400 ~/.ssh/inmotion_key`
4. `ssh -p 2222 -i ~/.ssh/inmotion_key n6ac4b5@ccsoccer.com`
5. Add SSH config shortcut (optional — see DEPLOYMENT_GUIDE.md Section 2.4)

### 2. Pull fresh D7 dump from production
```bash
ssh inmotion
mysqldump -u DB_USER -p n6ac4b5_ccsoccer | gzip > ~/d7-production-$(date +%Y%m%d).sql.gz
# Note the datetime of this dump — post-launch checklist item
```
Then SCP to local:
```bash
scp -P 2222 -i ~/.ssh/inmotion_key n6ac4b5@ccsoccer.com:~/d7-production-*.sql.gz ~/Sites/ccsoccer-d11/
```

### 3. Import D7 dump into DDEV as second DB
```bash
ddev mysql -uroot -e "CREATE DATABASE IF NOT EXISTS n6ac4b5_ccsoccer;"
ddev mysql -uroot -e "GRANT ALL ON n6ac4b5_ccsoccer.* TO 'db'@'%';"
gunzip -c d7-production-YYYYMMDD.sql.gz | ddev mysql -uroot n6ac4b5_ccsoccer
```
Add to `web/sites/default/settings.local.php`:
```php
$databases['d7']['default'] = [
  'database' => 'n6ac4b5_ccsoccer',
  'username' => 'db',
  'password' => 'db',
  'host' => 'db',
  'driver' => 'mysql',
];
```

### 4. Reset local D11 DB to clean baseline
Wipe seeded/test data for a clean migration run. Options:
- `ddev drush si` (full fresh install — cleanest)
- Or selectively purge test users/data

### 5. Run migration locally
```bash
ddev drush ccsoccer:migrate-d7 --dev          # for ongoing local dev work
ddev drush ccsoccer:migrate-d7                # for production export (no --dev)
```
Verify: user counts, spot-check a few users, check credits, check registrations.

### 6. Export and upload to server
```bash
ddev export-db --gzip --file=d11-production-ready.sql.gz
scp -P 2222 -i ~/.ssh/inmotion_key d11-production-ready.sql.gz n6ac4b5@ccsoccer.com:~/
```

### 7. Create third DB on server and import
In cPanel: create `n6ac4b5_d11prod`, create/assign a DB user.
```bash
ssh inmotion
gunzip d11-production-ready.sql.gz
mysql -u n6ac4b5_d11user -p n6ac4b5_d11prod < d11-production-ready.sql
```
Update `settings.local.php` on server to point at new DB.

### 8. Post-migration checklist (do at launch)
- [ ] Record D7 dump datetime — check for credits/registrations issued after that date
- [ ] Manually assign roles: Haley, Layne, Julie, Myk, Kyle → board member + permanent_override
- [ ] Verify credit balances for a handful of known users against D7
- [ ] Test password reset flow (migrated users have random passwords, need reset)
- [ ] All security hardening items from SESSION_HANDOFF archive (see prior handoff)

---

## Andrew: What You Need to Do

1. `git pull`
2. `ddev drush updb -y` — runs update 9061, removes four unused user fields
3. `ddev drush cr`

No composer changes, no config import needed. Just updb + cr.

When a fresh D7 dump is ready and a clean migration run has been done, Caleb will provide an updated DB export for you to import. You'll get the signal when that's ready — don't import anything until then.

---

## Files Changed This Session
- `web/modules/custom/ccsoccer/src/Drush/Commands/MigrateCommands.php`
  - Added `sms_user` JOIN + `field_phone` mapping
  - Added `field_notification_preference` mapping (`sms` → `text`)
  - Added `--dev` flag for password control
  - Removed `updateCreditBalances()` method
- `web/modules/custom/ccsoccer/ccsoccer.install`
  - Removed four field creation blocks from `_ccsoccer_add_user_fields()`
  - Added `ccsoccer_update_9061()` to drop fields from existing installs

---

## Server Quick Reference
```bash
# SSH in
ssh -p 2222 -i ~/.ssh/inmotion_key n6ac4b5@ccsoccer.com

# Deploy to test
cd ~/public_html/test_ccsoccer_site
git pull
PATH=/opt/cpanel/ea-php83/root/usr/bin:$PATH /opt/cpanel/ea-php83/root/usr/bin/php vendor/drush/drush/drush.php -r web updb -y
PATH=/opt/cpanel/ea-php83/root/usr/bin:$PATH /opt/cpanel/ea-php83/root/usr/bin/php vendor/drush/drush/drush.php -r web cr

# If new PHP classes added:
PATH=/opt/cpanel/ea-php83/root/usr/bin:$PATH /opt/cpanel/ea-php83/root/usr/bin/php /opt/cpanel/composer/bin/composer dump-autoload --ignore-platform-req=ext-intl

# If composer.lock changed:
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
```

## Test Server .htaccess (IP Whitelist)
Not in git — protected via `skip-worktree`. If ever lost:
```apache
Require ip 68.249.41.9 35.151.50.130 99.8.107.54 97.84.70.141
<IfModule mod_headers.c>
  Header set X-Robots-Tag "noindex, nofollow, noarchive"
</IfModule>
```
```bash
git update-index --skip-worktree web/.htaccess
```

## Git Workflow
- Always `git pull` before `git push` — Andrew may have pushed changes
- `main` is the primary branch
- `settings.local.php` is NOT in git — never commit it
