# Grabb & Durando — Calendar App (data.grabbanddurando.com) Login Fix + Migration Audit

## User
- **User:** Mike Swanson (mike)
- **Machine:** GURU-5070
- **Role:** admin

## Session Summary

Investigated a report that "Jeff's login isn't working" on the firm's calendar/case-management web app while other users were fine. Mike clarified it was NOT a Leap/M365 issue but the custom PHP app at data.grabbanddurando.com. Resolved DNS to 72.194.62.5 = ACG's IX server (internal 172.16.3.10), found the app under cPanel account `grabblaw` at `/home/grabblaw/public_html/data_grabbanddurando`, with live DB `grabblaw_gdapp_data`.

Read the auth code: login (index.php) authenticates against table `vt_users` by username + md5(password) with is_enabled=1. The live `vt_users` had only 5 rows; "Jeff" was identified as jwilliams (Jeff Williams). His account was absent. Cross-checked an older DB copy `grabblaw_gdapp` (48 users) which contained jwilliams (id 46, Super Admin, enabled, password intact). Restored just his row into the live DB via INSERT ... SELECT (schemas identical, id 46 free, orphan ACL role row already present). Verified login conditions met.

Spot-checked all shared tables old vs live: every DATA table in the live DB is equal to or larger than the old copy (live is authoritative and actively used) — only `vt_users` (6/48) and `acl_junction_user_role` (77/82) were under-populated. So this was never a "restore the database" problem, just a dropped user table; a full restore would have lost newer live data.

Mike hypothesized the firm's web people tried to move the site and broke it. Forensics confirmed the shape: an on-server `backups_mariadb_fix/MIGRATION_REPORT.md` (dated 2025-12-15, "Prepared by: IT Support") documents a GoDaddy/legacy -> IX cPanel migration with a PHP 7.4->8.1 + MariaDB 10.11 strict-mode rebuild (61 files modified). The live DB dir was built 2025-12-16, alongside 5 clone/scratch DBs created 2025-12-11; connection.php repointed 2025-12-15; app error_log shows DB-connect failures in Jan 2026 (rocky aftermath). Binary logging is OFF, so there is no statement-level proof of deliberate prune vs failed import — but the circumstantial timeline is solid.

Per Mike's direction, the other ~20 inactive accounts were left for Jeff to decide later (no bulk backfill). Created Syncro ticket #32405 and billed 1.0 hr remote, which applied to the firm's prepaid block (invoice $0.00; 21.25 prepay hrs remaining). Updated the wiki extensively.

## Key Decisions

- Restored ONLY jwilliams (preserving his original md5 password + id 46 + Super Admin role) rather than a full DB restore — the live DB is current and authoritative; a wholesale restore would lose post-migration data.
- Kept Jeff's existing pre-migration password (least surprise; forgot-password flow available) rather than setting a temp.
- Left the remaining 41 missing accounts un-restored at Mike's direction (only a handful of active users; Jeff to decide).
- Recorded the migration root cause from the on-server MIGRATION_REPORT.md + filesystem/DB timestamps rather than guessing; explicitly noted the no-binlog limitation.

## Problems Encountered

- **Public SSH to IX timed out** (port 22 on 72.194.62.5 firewalled). Connected via internal IP `172.16.3.10` instead (this machine reaches the 172.16.3.0/24 net).
- **App DB user is scoped to its own DB:** `grabblaw_gddata` could not read the old `grabblaw_gdapp` (access denied). Used root MySQL (socket auth) for cross-DB inspection and the restore.
- **Prepay misread:** the Syncro customer-LIST endpoint returned `prepay_hours: None`, so the billing initially looked like it should be $150; the invoice came back $0.00 with "- Applied 1.0 Prepay Hours". The per-customer DETAIL endpoint confirmed Grabb & Durando is prepaid (21.25 hrs remaining). $0.00 invoice is correct.
- **Diagnosis correction:** initial framing blamed a recent GoDaddy->IX migration; Mike corrected that the app has been on IX a year+ (path GoDaddy->WebSvr->IX over ~2 yrs). Forensics then pinned the user-table loss to the Dec 2025 IX/MariaDB rebuild specifically. Wiki + ticket wording revised accordingly.

## Configuration Changes

- **Live DB write:** `INSERT INTO grabblaw_gdapp_data.vt_users SELECT * FROM grabblaw_gdapp.vt_users WHERE id=46;` (restored jwilliams). No ACL change needed — orphan row (46, role 1 Super Admin) already present in live.
- `wiki/clients/grabb-durando.md` — updated Servers table (GoDaddy=retired, IX=live host w/ details), Web Applications (full data-app entry + auth model + weak-auth warning), Patterns (Dec-2025 origin + do-not-full-restore rule + per-user login diagnostic), Active Work (migration complete; backfill DEFERRED to client), History (2025-12-15/16 confirmed migration row; 2026-06-10 fix row), Profile (prepaid 21.25 hrs, Syncro id 14232794).

## Credentials & Secrets

- **App DB (live):** host localhost, user `grabblaw_gddata`, password `GrabbData2025`, database `grabblaw_gdapp_data`. Hardcoded in `/home/grabblaw/public_html/data_grabbanddurando/connection.php`. [WARNING] not vaulted — TODO: migrate to SOPS vault under clients/grabb-durando/.
- **SSH:** `root@172.16.3.10` (IX internal; key-based, system OpenSSH). Public 72.194.62.5:22 firewalled.
- App auth model (for future reference): `vt_users` login by username + unsalted MD5(password) + is_enabled=1; roles in acl_user_role (1 Super Admin, 3 Assistant, 4 Lawyer, 5 Call Center) via acl_junction_user_role. [WARNING] weak auth (unsalted MD5 + plaintext password cookie).

## Infrastructure & Servers

- IX: `ix.azcomputerguru.com` = 72.194.62.5 (public, :22 firewalled) / 172.16.3.10 (internal). CloudLinux 9.7, cPanel, MariaDB 10.11, PHP 8.1.
- App: cPanel acct `grabblaw`, docroot `/home/grabblaw/public_html/data_grabbanddurando`, DNS `data.grabbanddurando.com -> 72.194.62.5` (zone on ACG WebSvr 162.248.93.81).
- DB copies on IX: `grabblaw_gdapp_data` (LIVE, 6 users now), `grabblaw_gdapp` (48 users, pre-migration), plus `gdapp2`, `_clone`, `_new`, `sandbox` (clones from 2025-12-11).
- Migration doc: `/home/grabblaw/public_html/data_grabbanddurando/backups_mariadb_fix/MIGRATION_REPORT.md` (2025-12-15).
- Retired: GoDaddy VPS 208.109.235.224 (nothing points here; verify cancelled).

## Commands & Outputs

```bash
# locate app + auth
ssh root@172.16.3.10 'grep -i data.grabbanddurando /etc/userdatadomains'
#  -> grabblaw==...==/home/grabblaw/public_html/data_grabbanddurando
# login query (index.php): select * from vt_users where username='<login>' and password='<md5>' and is_enabled=1
# restore Jeff
mysql -e "INSERT INTO grabblaw_gdapp_data.vt_users SELECT * FROM grabblaw_gdapp.vt_users WHERE id=46;"
# table count comparison: vt_users OLD 48 / LIVE 6 ; all data tables LIVE >= OLD
# forensics: live DB dir 2025-12-16; clone DBs 2025-12-11; connection.php edited 2025-12-15; binlog OFF
```

## Pending / Incomplete Tasks

- **Backfill remaining users — DEFERRED to client.** 41 accounts still missing from live `vt_users` (20 enabled real users + disabled/test). Restore individually on request via targeted INSERT...SELECT from grabblaw_gdapp; skip test/junk (testsuntec, ContactOne).
- **Vault the app DB creds** (connection.php plaintext) under clients/grabb-durando/.
- **Confirm the old GoDaddy VPS (208.109.235.224) is cancelled** — nothing points to it but it may still bill.
- Tell Jeff: log in at https://data.grabbanddurando.com with username `jwilliams` + his pre-migration password (forgot-password link emails jwilliams@grabblaw.com).

## Reference Information

- Syncro: customer `14232794` (Grabb & Durando Law Office; contact jwilliams@grabblaw.com). Ticket **#32405** (id 112505040), Initial Issue comment id 418428207 (internal/no email), line item id 42811333, invoice **#67812** (id 1650639454, $0.00 prepaid), prepay 21.25 hrs remaining. Bot alert message_id 1514392451853455490.
- Restored user: jwilliams (Jeff Williams), vt_users id 46, role Super Admin.
- Wiki: `wiki/clients/grabb-durando.md`.
- Tenant (M365, unrelated to this fix): grabblaw.com `032b383e-96e4-491b-880d-3fd3295672c3`.
