Files
AOS/aos-verify12.sh
T
Z User e45b68bb8b feat: IMAP mail sync with thread-to-contact matching (PRD §6.1)
Real IMAP connection via imapflow library:
- Connects to IMAP server (IMAPFlow, TLS on port 993)
- Fetches recent messages (configurable limit, default 20)
- Extracts: from, fromEmail, subject, date, snippet (200 chars)
- Thread-to-contact matching (PRD §6.1):
  1. Match sender email against persons table
  2. If no person match, extract domain and match against company.website
  3. Returns matchedCompany + matchedPerson for each email
- Audit-logged (action: crm.mailsync:imap)
- Zod validated (host, port, user, password, folder, limit)
- 502 on IMAP connection failure with detail
- 400 on validation failure

Tested: invalid creds → 502 'IMAP connection failed', missing host → 400
2026-10-27 22:50:50 +00:00

123 lines
5.1 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 ==="