# Deploy Plan — July 2026 Feature Batch

Covers everything on `Sub-site-support` since `ed090ba5` (last production state),
plus the currently uncommitted transaction/feedback batch.

## What is being deployed

| Commit | Change |
|---|---|
| `56c21035` | Switchable simple text-only UI mode (cookie + per-account preference) |
| `58b40567` | Email verification enforced on authenticated routes |
| `4aa3f045` | Systemd queue workers via ansible; deploys signal `queue:restart` |
| `c12b6e09` | Bulk import overhaul (live preview, inline review, drafts option, validation) |
| `e74a6d9e` | Buy queue fixes (status checks, withdraw/remove, winner notification) |
| *(pending)* | Feedback/ratings, quantity-aware selling, transaction auto-close, queue race fix, dark mode |

### Migrations that will run (in order)

1. `2026_07_12_000001` — adds `ui_mode` to `user_preferences`
2. `2026_07_12_000002` — backfills `email_verified_at` for all existing users
   (**must ship in the same deploy as the MustVerifyEmail code — it does**;
   its `down()` is a no-op, see Rollback)
3. `2026_07_12_000003` — renumbers any duplicate buy-queue positions, then adds
   a unique index on `buy_queue(item_id, position)`

### One-time infrastructure (ansible, run from local machine)

- Queue workers: **already installed and active** (`laravel-queue-production`,
  `laravel-queue-beta`)
- Scheduler cron: **not yet installed** — required for `transactions:auto-close`

## Step 0 — Commit and push pending work

```bash
# from the repo root, on Sub-site-support
git add -A && git status   # review: should be the feedback/quantity/auto-close/race/dark-mode batch
git commit                 # (or have Claude commit as before)
git push origin Sub-site-support
```

## Step 1 — Pre-deploy safety net

```bash
# Local: full test suite green except the 3 known failures
php artisan test    # expect: 128+ passed, 3 pre-existing failures (redirect assertions on '/')

# Server: fresh production DB backup
ssh root@xeek.com "cd /var/www/html && ./backup_database.sh"
```

## Step 2 — Deploy to beta (hound.xeek.com)

```bash
./deploy-beta.sh Sub-site-support
```

This pushes the branch, then on the server: pulls, composer/npm install, builds
assets, migrates the **beta** database, rebuilds caches, `storage:link`, and
`queue:restart`.

Install the scheduler cron on beta (and production — it's harmless ahead of the
code deploy since the command ships with this batch):

```bash
cd devops
ansible-playbook playbooks/site.yml --tags scheduler
```

## Step 3 — Beta verification checklist

Auth / verification:
- [ ] Register a throwaway account (magic link lands in `storage/logs/laravel.log`
      on beta since mail is still `log`) — complete signup, confirm you land on
      the dashboard with no verification prompt
- [ ] Existing beta user can log in and reach `/messages` (backfill worked)

Simple UI:
- [ ] `https://hound.xeek.com/items?ui=simple` shows the text-only index
- [ ] Toggle survives navigation; "photo view" link switches back
- [ ] Logged-in toggle persists after logout/login (saved to preferences)

Bulk import (`/mass-listing`):
- [ ] Live preview counts items as you paste
- [ ] Review page: inline edit, apply-to-all, remove/undo
- [ ] "Save as drafts" lands on My Drafts with green banner; "Publish now" on My Listings

Buy queue (needs two test accounts):
- [ ] Commit to buy → item shows `sale_pending`; withdraw → back to `active`
- [ ] Two buyers: primary withdraws → backup promoted (check
      `storage/logs/laravel.log` for the queued mail after the worker runs)
- [ ] Seller: manage queue → Remove works; Sell To → transaction created,
      winner notified
- [ ] Multi-quantity item: sell one unit → quantity decrements, listing stays live

Transactions / feedback:
- [ ] Buyer confirms receipt → transaction completed
- [ ] Both parties can leave one rating each; seller profile shows the average
- [ ] `php artisan transactions:auto-close` runs clean on beta
      (`ssh`, `cd /var/www/hound`, expect "Auto-closed 0 transaction(s)." or similar)

Dark mode:
- [ ] Checkout, manage-queue, and transaction pages look right with the dark theme

Regression sweep:
- [ ] Marketplace index, item page, messaging, offers, admin items page all load

## Step 4 — Deploy to production

Option A (ansible, preferred — it mirrors deploy-beta and restarts workers):

```bash
cd devops
ansible-playbook playbooks/deploy-laravel.yml --limit production
```

Option B (manual, per CLAUDE.md "Updating Production"):

```bash
ssh root@xeek.com
cd /var/www/html
git pull origin Sub-site-support
php composer.phar install --no-dev --optimize-autoloader
npm install && npm run build
php artisan migrate --force
php artisan config:cache && php artisan route:cache && php artisan view:cache
php artisan queue:restart
sudo systemctl reload apache2
```

## Step 5 — Production verification (15 minutes)

```bash
# Services
ssh root@xeek.com "systemctl is-active laravel-queue-production apache2 && crontab -u www-data -l | grep schedule"

# Migrations landed
ssh root@xeek.com "cd /var/www/html && php artisan migrate:status | tail -5"

# No unverified users locked out
ssh root@xeek.com "cd /var/www/html && php artisan tinker --execute='echo App\Models\User::whereNull(\"email_verified_at\")->count();'"
# expect: 0

# Watch logs during smoke test
ssh root@xeek.com "tail -f /var/log/apache2/xeek-error.log /var/www/html/storage/logs/laravel.log"
```

Smoke test in a browser: homepage, one item page, `?ui=simple` toggle, log in,
`/messages`, `/mass-listing`.

## Rollback plan

- **Code**: `git revert` the offending commit(s) on `Sub-site-support`, push,
  re-run the deploy. (Avoid `git reset` — the server pulls.)
- **Migrations**: `php artisan migrate:rollback --step=3` undoes the ui_mode
  column and the buy_queue index. The email backfill (`000002`) is
  intentionally irreversible — but reverting the `MustVerifyEmail` commit makes
  the column values inert, so no data rollback is needed.
- **Data**: restore from the Step 1 backup with `./restore_database.sh` (last
  resort; loses activity since backup).
- **Queue workers/cron**: independent of code — leave them running; they're
  no-ops for code that doesn't queue anything.

## Known conditions (not blockers, be aware)

1. **Mail is still `MAIL_MAILER=log`** — all the new notifications (promotions,
   purchase confirmations, feedback prompts) write to `laravel.log` until a real
   mail provider is configured. When that lands later: clear stale queued jobs
   first (`php artisan queue:clear database`) to avoid flushing months of old
   notifications at users.
2. **Users created via tinker/admin** after this deploy need
   `'email_verified_at' => now()` or they'll be gated to the verify-email page.
3. **`dot_env_production` / `deploy.sh` still contain committed secrets and
   `APP_DEBUG=true`** — separate remediation, unchanged by this deploy.
4. The three failing tests (`/` redirect assertions) predate this batch.
