SPRINT-3 S3-7 — Browser E2E Test Plan (Production)
Date: 2026-08-28
Status: Ready for Ryan execution on production hostname after S3-5 DNS cutover.
Parent: SPRINT-3_S3-6_REPORT.md · TIER_3_REALOUTCOMES_T3-4_TEST_PLAN.md (adapted)
Scope
| In scope (S3-7) |
Out of scope |
Browser E2E on https://realoutcomes.app (and www) |
S3-8 Railway + hosted Supabase teardown |
| Auth via auth.last1.id (GoTrue retired) |
Staging hostname realoutcomes-app.last1.enterprises (optional regression only) |
| Directory, subscriptions, crawl/score UI |
Real Stripe charges / bulk SendGrid sends |
| Ryan marks PASS/FAIL in Section 10 |
Cursor does not run browser tests |
S3-6 automated PF checks already PASS. Ryan confirms behavior in a real browser session.
1. Production URL
| Item |
Value |
| App URL (primary) |
https://realoutcomes.app |
| App URL (www) |
https://www.realoutcomes.app |
| Auth issuer |
https://auth.last1.id |
| OAuth callback |
https://realoutcomes.app/auth/callback |
| Tunnel |
realoutcomes-edge (643ea255-19c7-4cef-a154-7a2fd6154275) |
| Origin |
VM 116 http://192.168.1.99:5000 |
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; total ~1,987,840 |
200 (hosted DB on Railway) |
Optional: ssh ryan@192.168.1.99 'docker logs realoutcomes-app --tail 10' while you browse — new request lines should appear.
| Item |
Guidance |
| Accounts |
ryan@last1.org, ryan@last1.enterprises, or rydaunicorn@gmail.com (Last1 ID OAuth) |
| Browser |
Chrome or Firefox; incognito profile |
| DevTools |
Network tab; filter api/ |
| Stripe |
Test card only; close checkout before confirming payment |
| SendGrid |
Verify infra only; do not trigger bulk digests |
Write policy: Prefer read-only. Mark WRITE (optional) tests as SKIP unless needed.
3. Test checklist (42 cases)
Mark each row PASS, FAIL, or SKIP in Section 10.
4.0 Pre-flight (4)
| ID |
Test |
Route / action |
Expected |
| PF-1 |
Prod apex reaches R940 |
https://realoutcomes.app/ |
SPA loads; no x-railway-edge |
| PF-2 |
Prod www reaches R940 |
https://www.realoutcomes.app/ |
Same as PF-1 |
| PF-3 |
Directory API on prod |
DevTools: GET /api/directory?limit=1 |
200; total ~1,987,840 |
| PF-4 |
Auth issuer reachable |
Browser or curl: https://auth.last1.id/.well-known/openid-configuration |
200 JSON |
4.1 Landing and navigation (6)
| 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 — Last1 ID OAuth (5)
| ID |
Test |
Route |
Expected |
| A-1 |
Login page |
/login |
Last1 ID / Google sign-in options visible |
| A-2 |
OAuth login |
Sign in with test account |
Redirect through auth.last1.id; lands in app |
| A-3 |
Auth callback |
Complete OAuth → /auth/callback |
No redirect_uri mismatch; session established |
| A-4 |
Session API |
GET /api/auth/user |
200 with user profile |
| A-5 |
Logout |
Sign out (if UI present) |
GET /api/auth/user → 401 |
4.3 Directory and org detail (5)
| 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 |
Detail tabs load |
| D-5 |
Compare |
/compare-orgs |
Compare UI loads (read-only) |
4.4 Authenticated features (5)
| ID |
Test |
Route |
Expected |
| U-1 |
Saved orgs |
/saved (logged in) |
Saved list 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 (Portfolio Intelligence populates) |
4.5 Admin (1)
| ID |
Test |
Route |
Expected |
| ADM-1 |
In-app admin routes |
/admin |
Redirects to unified admin portal |
4.6 Stripe (4)
| ID |
Test |
Route |
Expected |
| ST-1 |
Subscription page |
/settings/subscription |
Plans render |
| ST-2 |
Checkout start |
Subscribe → POST /api/stripe/checkout |
Redirect to Stripe Checkout |
| ST-3 |
Do not pay |
Close Stripe tab before confirming |
No charge |
| ST-4 |
Webhook delivery |
Stripe Dashboard → webhook we_1U9Y7m… → recent deliveries or "Send test event" |
2xx to https://realoutcomes.app/api/stripe/webhook |
4.7 SendGrid (2)
| ID |
Test |
Action |
Expected |
| SG-1 |
Alert digest infra |
ssh ryan@192.168.1.98 'journalctl -u realoutcomes-send-alert-digests.service -n 20 --no-pager' OR last timer run |
No 5xx in recent runs; do not mass-send |
| SG-2 |
UI alert prefs |
/alerts preferences (WRITE optional) |
Saves without 5xx |
4.8 Firecrawl / website analyzer (2)
| 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; not 5xx |
4.9 Edge Function timers (VM 117) (4)
| ID |
Test |
Action |
Expected |
| EF-1 |
Timers active |
ssh ryan@192.168.1.98 'systemctl list-timers realoutcomes-*' |
5 timers listed |
| EF-2 |
Status changes |
Org with recent status change in UI/alerts |
Data consistent (read-only) |
| EF-3 |
Score run queue |
Org profile score section |
Scores load or sane pending state |
| EF-4 |
Scheduled recrawl |
UI / no user-visible errors |
No errors |
4.10 Storage (3)
| ID |
Test |
Route |
Expected |
| STO-1 |
Upload infra |
Document upload UI (WRITE optional) |
Signed URL flow succeeds |
| STO-2 |
Download |
Download uploaded file |
File retrieves |
| STO-3 |
Empty baseline |
N/A |
Only test objects if STO-1 run |
Total: 42 test cases
4. Failure triage
| Symptom |
Likely cause |
Check |
| OAuth redirect error |
Callback not in app_clients on auth.last1.id |
https://realoutcomes.app/auth/callback registered |
| Still seeing Railway |
Wrong URL / DNS cache |
Hard refresh; verify PF-1 headers |
| Directory 500 |
DATABASE_URL on VM 116 |
BWS + /opt/realoutcomes/.env |
| Funder dashboard skeleton forever |
Auth/session or API error |
DevTools 401/500 on portfolio APIs |
| Stripe checkout 500 |
Missing Stripe keys |
BWS REALOUTCOMES_APP_PROD_STRIPE_* |
| Stripe webhook 4xx in dashboard |
Wrong signing secret or CF WAF |
R940 logs; BWS secret matches we_1U9Y7m… |
5. Section 10 — Ryan results worksheet
Tester: Ryan
Date: _
URL used: https://realoutcomes.app
Test account: _
Pre-flight
| ID |
Result |
Notes |
| PF-1 |
|
|
| PF-2 |
|
|
| PF-3 |
|
|
| PF-4 |
|
|
Navigation
| 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
Stripe
| ID |
Result |
Notes |
| ST-1 |
|
|
| ST-2 |
|
|
| ST-3 |
|
|
| ST-4 |
|
|
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 |
|
S3-7 gate verdict: ☐ PASS (zero FAIL on PF-1, PF-2, D-2, A-2, A-4, U-5, ST-4) · ☐ FAIL (block S3-8 until fixed)
Ryan sign-off: _ Date: _
6. After S3-7
| Phase |
Action |
| S3-7 PASS |
Ryan sign-off; Cursor writes SPRINT-3_S3-7_REPORT.md from Section 10 |
| S3-8 |
Railway + hosted Supabase teardown (only after Ryan sign-off) |
Do not proceed to S3-8 until Ryan marks S3-7 gate PASS.
END S3-7 test plan