Skip to content

Tier 3 T3-4 — Browser E2E Test Plan (RealOutcomes R940)

Date: 2026-08-28
Status: Test plan ready for Ryan review. Ryan executes browser tests; Cursor does not run browser tests.
Parent: TIER_3_REALOUTCOMES_T3-3_REPORT.md · TIER_3_REALOUTCOMES_MIGRATION_AUDIT.md (T3-0)


Scope

In scope (T3-4) Out of scope
Browser E2E on R940 stack via staging tunnel URL T3-5 DNS cutover (realoutcomes.app → R940)
Directory, auth, subscriptions, crawl/score UI paths Railway / hosted Supabase teardown
Integration smoke (Stripe checkout path, SendGrid path, storage infra) last1-admin proxy tests (Tier 6)
Ryan marks PASS/FAIL in Section 10 Real transactions / mass email sends

Production remains Railway at https://realoutcomes.app until T3-5. All T3-4 tests target the R940 parallel stack only.


1. How to reach R940 (staging tunnel)

Public realoutcomes.app still resolves to Railway (x-railway-edge response header). Use a separate staging hostname on the same Cloudflare Tunnel.

Item Value
Tunnel lastvet-r940
Tunnel UUID 4c8550f2-2156-4284-b9f7-60cdc0fdc109
App origin http://192.168.1.99:5000
Staging app URL https://realoutcomes-app.last1.enterprises
Staging Supabase URL (auth E2E) https://realoutcomes-db-r940.last1.enterprises → http://192.168.1.98:8000

One-time prep (Ryan + Cursor)

Step Owner Action
1 Ryan Cloudflare DNS CNAME: realoutcomes-app.last1.enterprises → 4c8550f2-2156-4284-b9f7-60cdc0fdc109.cfargotunnel.com (proxied)
2 Ryan Cloudflare DNS CNAME: realoutcomes-db-r940.last1.enterprises → same tunnel target (proxied) — required for browser auth
3 Cursor Dry-run tunnel ingress: DRY_RUN=1 scripts/realoutcomes/configure-tunnel-staging-app.sh on lastvet-edge
4 Cursor Dry-run Supabase tunnel: DRY_RUN=1 scripts/realoutcomes/configure-tunnel-staging-db.sh
5 Ryan + Cursor GoTrue allow-list on VM 117: https://realoutcomes-app.last1.enterprises/auth/callback — script: configure-gotrue-staging-redirects.sh
6 Cursor After Ryan confirms steps 1–2 + 5: apply both tunnel scripts (DRY_RUN=0), update app env PUBLIC_URL + VITE_SUPABASE_URL to staging HTTPS URLs, rebuild container
7 Cursor Run scripts/realoutcomes/verify-pf-headers.sh — PF-1/PF-2 must PASS before browser E2E
8 Ryan If using Google OAuth: add authorized redirect URI in GCP OAuth client for staging callback

Do not change DNS for realoutcomes.app (T3-5).

Confirm you are on R940 (not Railway)

DevTools → Network → reload /:

Signal R940 (pass) Railway (wrong stack)
Response headers No x-railway-edge Has x-railway-edge
GET /api/auth/user (logged out) 401 401 (same)
GET /api/directory?limit=1 200 with ~1.99M total 200 (hosted DB)
Optional ssh realoutcomes-app 'docker logs realoutcomes-app --tail 5' shows your requests No new lines on VM 116

2. Test account and tooling

Item Guidance
Accounts One of the 3 lifted users from Gate B: ryan@last1.org, rydaunicorn@gmail.com, ryan@last1.enterprises (password reset via R940 GoTrue if needed)
Browser Chrome or Firefox; incognito profile
DevTools Network tab; filter api/ and auth/v1/
Stripe Use test card only; close checkout before confirming payment
SendGrid Verify API path only; do not trigger bulk digests to real users

Write policy: Prefer read-only. Mark WRITE (optional) tests as SKIP unless explicitly needed.


3. Test checklist

Mark each row PASS, FAIL, or SKIP in Section 10.

4.0 Pre-flight

ID Test Route / action Expected
PF-1 Staging URL reaches R940 https://realoutcomes-app.last1.enterprises/ SPA loads; no x-railway-edge
PF-2 Prod URL still Railway https://realoutcomes.app/ Loads with x-railway-edge
PF-3 Directory API on R940 DevTools: GET /api/directory?limit=1 200; pagination total ~1,990,000
PF-4 Supabase Kong reachable (if auth tests) Browser can reach https://realoutcomes-db-r940.last1.enterprises/auth/v1/health or login attempt reaches Kong No browser network error to LAN IP

4.1 Landing and navigation

ID Test Route Expected
N-1 Home / evaluator / Page loads (evaluator or redirect when logged in)
N-2 About / landing /about Marketing landing renders
N-3 Directory nav /directory Directory UI loads
N-4 Methodology /methodology Static content loads
N-5 Framework /framework Static content loads
N-6 Header nav links Click primary nav items No 404 loop

4.2 Auth

ID Test Route Expected
A-1 Login page /login Email/password + Google options visible
A-2 Password login Sign in with test account Redirect to app; session established
A-3 Auth callback OAuth/magic link via /auth/callback Lands in app; no redirect_uri mismatch
A-4 Session API GET /api/auth/user 200 with user profile
A-5 Logout Sign out (if UI present) or clear session GET /api/auth/user → 401

SKIP A-2/A-3 if Supabase staging tunnel + GoTrue allow-list not complete.

4.3 Directory and org detail (1.99M IRS rows)

ID Test Route Expected
D-1 Directory list /directory Paginated org list loads
D-2 Search Search known org name or EIN Results return from R940 Postgres
D-3 Filters State / classification filters Filtered results update
D-4 Org profile /org/:ein (pick org from directory) Detail tabs load (scores, flags, connections as applicable)
D-5 Compare /compare-orgs Compare UI loads (read-only)

4.4 Authenticated features

ID Test Route Expected
U-1 Saved orgs /saved (logged in) Saved list loads or empty state
U-2 Watchlists /watchlists Watchlist UI loads
U-3 Alerts /alerts Alerts page loads
U-4 Portfolio /portfolio Portfolio view loads
U-5 Funder dashboard /funder-dashboard Dashboard loads (if entitled)

4.5 Admin-facing (RealOutcomes app)

ID Test Route Expected
ADM-1 In-app admin routes /admin Redirects to unified admin portal (not in-app admin UI) — mark PASS if redirect works

RealOutcomes product admin is via last1-admin proxy (Tier 6). No in-app admin E2E in T3-4.

4.6 Stripe checkout (verify path only)

ID Test Route Expected
ST-1 Subscription page /settings/subscription Plans render with Stripe price IDs
ST-2 Checkout start Click subscribe → POST /api/stripe/checkout Redirect to Stripe Checkout session URL
ST-3 Do not pay Close Stripe tab before confirming No charge; return to app safely

4.7 SendGrid (verify path only)

ID Test Action Expected
SG-1 Alert digest infra ssh realoutcomes-db 'curl -sS -X POST http://127.0.0.1:8000/functions/v1/send-alert-digests ...' OR inspect last timer log Function returns 200; do not send to production mailing list
SG-2 UI alert prefs /alerts preferences (if exposed) Saves without 5xx (WRITE optional, use test account only)

4.8 Firecrawl / website analyzer

ID Test Route Expected
FC-1 Website analyzer page /website-analyzer Form loads
FC-2 Analyze public site Submit well-known nonprofit URL Analysis completes or graceful error (Firecrawl quota); POST /api/... not 5xx

Uses server-side Firecrawl key from BWS; does not require Edge Function from browser.

4.9 Edge Function–backed data (timers on VM 117)

Background timers (systemd on VM 117): process-status-changes, run-validations, process-score-runs, send-alert-digests, scheduled-recrawl.

ID Test Action Expected
EF-1 Timers active ssh realoutcomes-db 'systemctl list-timers realoutcomes-*' 5 timers listed
EF-2 Status changes reflected Org with recent status change shows in UI/alerts Data consistent with R940 DB (read-only)
EF-3 Score run queue Org profile score section Scores load or "pending" state sane
EF-4 Scheduled recrawl Check crawl queue table via UI if exposed No user-visible errors

4.10 Storage upload/download

ID Test Route Expected
STO-1 Upload infra Portfolio or document upload UI (WRITE optional) Signed URL flow succeeds; object in R940 storage bucket
STO-2 Download Download uploaded file File retrieves correctly
STO-3 Empty bucket baseline N/A Hosted had 0 objects; R940 may have test object only after STO-1

5. Failure triage

Symptom Likely cause Check
OAuth redirect error Staging URL not in GoTrue ADDITIONAL_REDIRECT_URLS VM 117 .env + configure-gotrue-staging-redirects.sh
Auth calls fail in browser VITE_SUPABASE_URL still LAN IP Rebuild with https://realoutcomes-db-r940.last1.enterprises
Directory 500 Bad DATABASE_URL (Supavisor format) postgres.{tenant}@192.168.1.98:5432
Still seeing Railway Wrong URL Use staging hostname; verify PF-1
Stripe checkout 500 Missing/invalid Stripe keys BWS REALOUTCOMES_APP_PROD_STRIPE_*

6. T3-5 placeholder cleanup reminder

Before T3-5 cutover (not a T3-4 blocker):

  • Replace VM 117 .env.example placeholders (your-tenant-id, default postgres password)
  • Rotate D-live vendor secrets (Stripe webhook, SendGrid, Firecrawl)
  • Regenerate JWT/anon/service keys for production cutover

7. Section 10 — Ryan results worksheet

Tester: Ryan
Date: _
Staging URL used: https://realoutcomes-app.last1.enterprises
Test account:
_

Pre-flight

ID Result Notes
PF-1
PF-2
PF-3
PF-4
ID Result Notes
N-1
N-2
N-3
N-4
N-5
N-6

Auth

ID Result Notes
A-1
A-2
A-3
A-4
A-5

Directory

ID Result Notes
D-1
D-2
D-3
D-4
D-5

Authenticated

ID Result Notes
U-1
U-2
U-3
U-4
U-5

Admin

ID Result Notes
ADM-1

Stripe

ID Result Notes
ST-1
ST-2
ST-3

SendGrid

ID Result Notes
SG-1
SG-2

Firecrawl

ID Result Notes
FC-1
FC-2

Edge Functions

ID Result Notes
EF-1
EF-2
EF-3
EF-4

Storage

ID Result Notes
STO-1
STO-2
STO-3

Summary

Metric Count
PASS
FAIL
SKIP

T3-4 gate verdict: ☐ PASS (zero FAIL on PF-1, PF-2, D-2, A-2, ST-2) · ☐ FAIL (block T3-5 until fixed)

Ryan sign-off: _ Date: _


8. After T3-4

Phase Action
T3-4 complete Ryan fills Section 10; Cursor writes TIER_3_REALOUTCOMES_T3-4_REPORT.md from results
T3-5 DNS cutover realoutcomes.app → tunnel (Ryan approval)
T3-7 Railway + hosted Supabase teardown

Do not proceed to T3-5 until Ryan marks T3-4 gate PASS.