#!/usr/bin/env bash # Verify Client Portal (real project-scoped data + real IP evidence) set -u cd /home/z/my-project BASE=http://127.0.0.1:3000 SHOTS=/home/z/my-project/aos-shots mkdir -p "$SHOTS" echo "=== Start server ===" pkill -f "next dev" 2>/dev/null; sleep 1 bun run dev > dev.log 2>&1 & SRV=$! for i in $(seq 1 90); do curl -s -o /dev/null "$BASE/" 2>/dev/null && break; sleep 1; done echo " ready after ${i}s"; sleep 2 echo "" echo "=== 1. Portal company list ===" curl -s "$BASE/api/aos/portal/companies" | python3 -c " import sys,json d=json.load(sys.stdin) print(f' companies: {len(d[\"companies\"])}') for c in d['companies'][:3]: print(f' {c[\"name\"]}: {c[\"projectCount\"]} projects, {c[\"invoiceCount\"]} invoices') " 2>/dev/null echo "" echo "=== 2. Portal company detail (project-scoped) ===" COMPANY_ID=$(curl -s "$BASE/api/aos/portal/companies" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['companies'][0]['id'])" 2>/dev/null) echo " company id: $COMPANY_ID" curl -s "$BASE/api/aos/portal/companies/$COMPANY_ID" | python3 -c " import sys,json d=json.load(sys.stdin) print(f' company: {d[\"company\"][\"name\"]}') print(f' kpis: {d[\"kpis\"]}') print(f' projects: {len(d[\"projects\"])}') print(f' invoices: {len(d[\"invoices\"])}') print(f' tickets: {len(d[\"tickets\"])}') print(f' approvals: {len(d[\"approvals\"])} ({sum(1 for a in d[\"approvals\"] if a[\"status\"]==\"pending\")} pending)') print(f' licenses: {len(d[\"licenses\"])}') " 2>/dev/null echo "" echo "=== 3. Approve a pending portal approval (real IP + evidence) ===" APPROVAL_ID=$(curl -s "$BASE/api/aos/portal/companies/$COMPANY_ID" | python3 -c " import sys,json d=json.load(sys.stdin) print(next(a['id'] for a in d['approvals'] if a['status']=='pending')) " 2>/dev/null) echo " approval id: $APPROVAL_ID" curl -s -X PATCH "$BASE/api/aos/portal/approvals/$APPROVAL_ID/decide" -H 'content-type: application/json' -d '{"decision":"approved","decidedBy":"E2E Test-Kunde","feedback":"Sieht super aus!"}' | python3 -c " import sys,json d=json.load(sys.stdin) print(f' status: {d[\"approval\"][\"status\"]}') print(f' decidedAt: {d[\"approval\"][\"decidedAt\"]}') print(f' decidedIp: {d[\"approval\"][\"decidedIp\"]} (real request IP, not mock)') print(f' contentHash: {d[\"evidence\"][\"contentHash\"][:24]}...') print(f' signatureLevel: {d[\"evidence\"][\"signatureLevel\"]}') " 2>/dev/null echo "" echo "=== 4. Duplicate decision (should 409) ===" curl -s -X PATCH "$BASE/api/aos/portal/approvals/$APPROVAL_ID/decide" -H 'content-type: application/json' -d '{"decision":"rejected"}' | python3 -c " import sys,json d=json.load(sys.stdin) print(f' result: {d.get(\"error\",\"ok\")}') " 2>/dev/null echo "" echo "=== Browser: Portal flow ===" agent-browser open "$BASE/" >/dev/null 2>&1 agent-browser wait --load networkidle >/dev/null 2>&1 || true agent-browser wait 3000 >/dev/null 2>&1 agent-browser set viewport 1440 900 >/dev/null 2>&1 echo " === Click 'Client-Portal öffnen' ===" agent-browser find text "Client-Portal öffnen" click >/dev/null 2>&1 agent-browser wait 3000 >/dev/null 2>&1 H1=$(agent-browser get text h1 2>/dev/null | head -1) echo " portal login H1: $H1" agent-browser screenshot --full "$SHOTS/v16-portal-login.png" >/dev/null 2>&1 && echo " login shot OK" echo " === Select first company ===" agent-browser eval "document.querySelector('button[class*=border]')?.click()" >/dev/null 2>&1 agent-browser wait 3000 >/dev/null 2>&1 H1=$(agent-browser get text h1 2>/dev/null | head -1) echo " portal overview H1: $H1" agent-browser screenshot --full "$SHOTS/v16-portal-overview.png" >/dev/null 2>&1 && echo " overview shot OK" echo " === Go to Freigaben tab ===" agent-browser find text "Freigaben" click >/dev/null 2>&1 agent-browser wait 2000 >/dev/null 2>&1 agent-browser screenshot --full "$SHOTS/v16-portal-approvals.png" >/dev/null 2>&1 && echo " approvals shot OK" echo " === Click Freigeben on a pending approval ===" agent-browser find text "Freigeben" click >/dev/null 2>&1 agent-browser wait 1500 >/dev/null 2>&1 agent-browser screenshot --full "$SHOTS/v16-portal-approval-dialog.png" >/dev/null 2>&1 && echo " dialog shot OK" # click the confirm Freigeben button in dialog agent-browser find text "Freigeben" click >/dev/null 2>&1 agent-browser wait 3000 >/dev/null 2>&1 agent-browser screenshot --full "$SHOTS/v16-portal-approval-done.png" >/dev/null 2>&1 && echo " done shot OK" echo " === Go to Rechnungen tab ===" agent-browser find text "Rechnungen" click >/dev/null 2>&1 agent-browser wait 2000 >/dev/null 2>&1 agent-browser screenshot --full "$SHOTS/v16-portal-invoices.png" >/dev/null 2>&1 && echo " invoices shot OK" echo " === Exit back to agency ===" agent-browser find text "Agentur-Ansicht" click >/dev/null 2>&1 agent-browser wait 2000 >/dev/null 2>&1 H1=$(agent-browser get text h1 2>/dev/null | head -1) echo " back to agency H1: $H1" echo "" echo "=== Errors ===" agent-browser errors 2>&1 | head -5 echo "--- dev.log errors ---" grep -iE "error|⨯|500" dev.log | grep -v SIGTERM | tail -5 agent-browser close >/dev/null 2>&1 kill $SRV 2>/dev/null echo "=== DONE ==="