Commit graph

5 commits

Author SHA1 Message Date
DJP
b553bef43a deploy: pipe DEV_AUTH_BYPASS into the Vite build
Vite inlines import.meta.env.VITE_DEV_AUTH_BYPASS at build time. The
build container wasn't getting it, so even with DEV_AUTH_BYPASS=true on
the backend the SPA still rendered the MSAL login gate.

Resolve VITE_DEV_AUTH_BYPASS, falling back to DEV_AUTH_BYPASS if it's
not explicitly set, and pass it through `docker run -e` to the build.
A single DEV_AUTH_BYPASS=true in .env now controls both halves.
2026-04-27 17:12:46 -04:00
DJP
ed0746267b deploy: auto-pick free ports + render Apache conf from template
The script bailed when 8003 was taken on the dev server. Per spec, it
should never block on a port clash — find a free port and run with it.

How it picks ports:
- Reads OSOP_DB_PORT / OSOP_REDIS_PORT / OSOP_BACKEND_PORT from .env,
  falling back to defaults 5435 / 6380 / 8003.
- For each, if the preferred port is taken on the host, scans upward in
  a sane range (5435-5499 / 6380-6399 / 8003-8099) for the next free one.
- Persists chosen ports back to .env via an idempotent KEY=VALUE upsert,
  so subsequent deploys keep using the same allocation.
- If our compose project is already running, skips the scan and reuses
  the current ports (re-deploy in place).

Compose port mappings now reference those env vars with defaults:
  127.0.0.1:${OSOP_DB_PORT:-5435}:5432, etc.

Apache config templating:
- deploy/apache-osop.conf.tmpl has __BACKEND_PORT__ placeholder.
- The script renders it to deploy/apache-osop.conf each run with the
  chosen backend port substituted in. The rendered file is gitignored
  (the template is the source of truth in git).
- If the backend port changed (or the Apache vhost doesn't yet Include
  our conf), the script tells the user to reload Apache.

This means a fresh server hits the conflict on 8003 (something else is
listening), the script picks 8004 silently, writes it to .env, renders
apache-osop.conf with 8004, brings the stack up, and tells you to
reload Apache. Re-running the script on the same server keeps 8004.
2026-04-27 16:34:05 -04:00
DJP
0734afedac deploy: fix silent exit when ports are free (lsof + pipefail)
The port-conflict check called lsof inside a pipeline. When no process
is listening (the success path on a fresh server) lsof returns 1, and
under `set -euo pipefail` that killed the script silently right after
the "Checking host ports" line.

Wrap the lsof/ss invocations in `{ … || true; }` and the call site
with `|| true`. Switched the function to `printf` so we don't get a
stray newline when the port is free.
2026-04-27 16:29:10 -04:00
DJP
0eedd412e6 Match /gsb/-style deploy: built SPA on disk + Apache Alias
The dev server runs everything else (/gsb/, /olivas/, /cc-dashboard/,
etc.) the same way: backend in Docker on a 127.0.0.1 port, frontend
built once and served by Apache as a static SPA via Alias. This commit
restructures V2 to match.

Apache (deploy/apache-osop.conf):
- Drops the ProxyPass-everything model; uses Alias + Directory + SPA
  RewriteRule, identical to the /gsb/ block.
- Stays as an Include — drop a single line into the merged vhost:
    Include /opt/oliver-sales-ops-platform/deploy/apache-osop.conf

Compose (docker-compose.yml):
- Frontend service moved behind a "dev" profile so it doesn't start in
  production. Locally:  COMPOSE_PROFILES=dev docker compose up
- Backend / db / redis are unprofiled and always come up.

Deploy script (deploy/deploy.sh):
- Sanity, port-conflict (5435/6380/8003 only — frontend port no longer
  needed in prod), git pull, docker compose build + up.
- New step 5: builds the Vite SPA in a one-shot node:20 container and
  rsyncs (or cp -a) the dist/ output to /var/www/html/oliver-sales-ops-platform/.
  Uses sudo if the dest isn't writable as the deploy user.
- Reports the Apache include line + reload command.
- New flag: --no-frontend (skip the build-and-sync step).
- Unsets COMPOSE_PROFILES so the dev profile never activates on prod.

Frontend type fixes (caught by `tsc && vite build`, hidden by dev mode):
- types/index.ts gains ClientAsset / Match / MatchConfidenceKey /
  RatecardLine / RatecardSummary, and StageArtifact gains its three
  cost columns. These were referenced from api/assets.ts and several
  Stage panels but were missing on the export side.
- New src/vite-env.d.ts declares ImportMetaEnv (VITE_DEV_AUTH_BYPASS).
- Drops one unused import (Stage4QAPack: downloadQAPack) and one
  unused variable (Stage16Delivery: currentBadge).
- Production build now passes: tsc clean, vite build clean, dist/
  index.html correctly references /oliver-sales-ops-platform/assets/...

Server layout (deploy server):
  /opt/oliver-sales-ops-platform/                — repo + compose
  /var/www/html/oliver-sales-ops-platform/       — built SPA
  Apache vhost includes deploy/apache-osop.conf
  Backend at 127.0.0.1:8003, db 5435, redis 6380 — none clash with the
  /gsb/ stack (5432/8002/3010) or any other listed in the merged vhost.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 16:16:08 -04:00
DJP
b8dadb4f99 Deploy infra + admin user seed + URL path migration
Three things needed for the optical-dev rollout.

1) Path migration /osop/ → /oliver-sales-ops-platform/
   The public URL is https://optical-dev.oliver.solutions/oliver-sales-ops-platform/
   Updated the basename across:
   - Vite base + proxy match
   - React Router basename
   - axios baseURL
   - MSAL redirectUri (preserves SSO when wired)
   - downloadQAPack URL
   - Backend app_path_prefix default
   - docker-compose APP_PATH_PREFIX default
   - Apache Location blocks

2) DEV_AUTH admin user
   Auth middleware now reads DEV_AUTH_EMAIL / DEV_AUTH_NAME / DEV_AUTH_ROLE
   when DEV_AUTH_BYPASS=true (defaults preserve the old dev@localhost /
   editor behaviour). The dev_bypass identity also promotes existing
   AppUser rows to admin if the env says so — so no manual SQL on the
   server when we want a different account exposed.
   New backend/scripts/seed_admin.py is idempotent and runs from
   start.sh after Alembic migrations. It upserts the configured
   DEV_AUTH_EMAIL with role=admin (or whatever DEV_AUTH_ROLE says).
   Smoke-tested locally: /api/users/me now returns
   admin@oliver.agency / role=admin.

3) Deploy assets under deploy/
   - apache-osop.conf — drop-in vhost block (Location /…/api/ → 8003,
     Location /…/ → 3011, ProxyTimeout 300, redirect bare prefix to /).
     Sits alongside the existing /gsb/ V1 block on the same vhost.
   - deploy.sh — idempotent script:
     * sanity (.env present, docker on PATH)
     * port-conflict check (5435 db, 6380 redis, 8003 backend, 3011
       frontend) — if our compose project is already running, skips
       the lsof check because the ports are ours; otherwise warns and
       exits if anything else is listening
     * git pull --ff-only (skip with --no-pull)
     * docker compose build && up -d (skip with --no-build)
     * health-poll backend /api/health for up to 60s
     * frontend probe at the new path
     * prints local + public URLs and the admin email on success

V1 host ports (5432/8002/3010) and V2 host ports (5435/6380/8003/3011)
are non-overlapping by design, so both stacks coexist on the same dev
server. CLAUDE.md naming policy is satisfied — docker-compose.yml has
name: oliver-sales-ops-platform pinned.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 16:08:50 -04:00