11 KiB
ProspectOS web — Phase 9 boundary
Self-contained static frontend for the Prospect Platform API. There is no bundler or runtime dependency: serve this directory with any static HTTP server. The UI supports a manual, tenant-scoped review workflow, Phase 4 MVP job monitor, and Phase 8 scan-result/history presentation when supplied by the API. The browser does not fetch targets, submit forms, execute scan JavaScript, or send outreach; SSRF controls and budgets are server-side.
Configure and run
The API base is configurable before app.js runs:
<script>window.API_BASE = 'http://127.0.0.1:8000';</script>
<script src="app.js"></script>
If not set, the UI uses localStorage.prospect_api_base when present; otherwise it targets the same origin. The dashboard requires an authenticated API session and shows the login screen until /api/v1/auth/me succeeds.
Phase 3 UI contract
- The explorer requests tenant-scoped business pages from
GET /api/v1/businessesand sends bounded pagination plus supported search/score/status filters to the API. Filtering is not a substitute for server-side authorization. - Selecting a row loads the tenant-scoped detail view, including child intelligence/evidence records, provenance/source labels, confidence/freshness, current pipeline state, notes, and relevant audit/activity context when available.
- Add prospect, add intelligence, change pipeline state, and add note are explicit manual actions. The API records the acting user and applies permission, tenant, validation, deduplication, and suppression rules server-side.
- Evidence labels describe stored observations and their provenance. The UI must not present them as the result of automated discovery, DNS lookup, website crawling, or verification unless a future approved integration explicitly supplies that evidence.
- Review and suppressed states remain safety states. The UI shows outreach as unavailable; there is no send button, message composer, sender, or outreach endpoint.
- The CSV control is preview-only and local to the browser. Selecting a file does not persist rows or send them to the API.
The API remains the source of truth for tenant isolation, pagination bounds, filters, pipeline transitions, notes, audit records, and suppression. See apps/api/README.md for the route contract.
Phase 6 normalization and deduplication UI contract
The UI may display the API's normalized SA phone and location values alongside the original observation, normalization version, and any ambiguity warning. It must not silently replace the source value or imply that a canonical form verifies identity. Duplicate candidates must show deterministic score, threshold band (strong >=0.90, review 0.75–0.8999, or none <0.75), and explainable matching reasons.
Suggestions are review aids only. A merge flow must identify the surviving record, list all parents/children/evidence/notes/source records that will be preserved, show conflicts, and require an explicit human confirmation before calling an authorized API mutation. The UI must offer rejection and, where implemented, reversal using the merge snapshot; it must never auto-merge based on a score. Candidate, merge, snapshot, and audit data are tenant-scoped by the API, not by hidden UI state.
The current static MVP requests /matches, renders a Human review required list with confidence/reasons, asks for Confirm merge, and displays merge history with Reverse merge when the API marks it reversible. The API remains authoritative; these controls are not a substitute for server-side authorization. Existing normalization and match display remain suggestion-only; no merge happens without explicit operator confirmation.
Phase 8 website-scanning UI contract
The UI may request a tenant-scoped scan through an authenticated API route when enabled and render the returned classification, status, redirect chain, observed time, scanner/policy version, cache freshness, applied budgets, and uncertainty/error reasons. The server permits only http and https targets. It must label cached data as cached/stale rather than “live,” keep unknown, blocked, partial, timeout, and error distinct from positive observations, and never turn a conservative classification into identity, ownership, consent, deliverability, or outreach permission.
The browser must not directly fetch arbitrary target URLs, follow redirects for scanning, submit forms, send cookies/credentials, execute target JavaScript, or expose response bodies unnecessarily. Scan history and cache controls are tenant-scoped API capabilities, not hidden client state. A result that is budget-limited or incomplete must remain visibly incomplete; no UI timer may imply that a scan completed.
Phase 5 source UI contract
The web client may display registered source metadata, query mode, approval/terms state, rate-limit status, retention class, health, and circuit state returned by the API. It must label dry_run as a plan/validation result and distinguish operator-supplied CSV/manual references from independently verified evidence. It must not offer a live-source control unless the API reports explicit approval and operational enablement; client visibility is never an authorization control.
CSV and manual reference workflows must show source attribution, adapter/version, observed time, and any retention/redaction status. Raw source payloads should be hidden or minimized in the UI and remain tenant-scoped. A circuit-open or rate-limited source must be presented as unavailable/deferred, not as an empty discovery result. The current static client has no network discovery implementation; these are display and contract requirements for a future approved integration.
Phase 4 job/live-log UI contract
A future job view should show queued, running, succeeded, failed, or cancelled, the current attempt, timestamps, safe error text, and a clear terminal state. It should display persisted events in sequence order, resume from the last cursor after refresh/reconnect, and tolerate duplicate events. Create/retry requests should send an idempotency key and show the returned job identity rather than starting duplicate work.
The preferred live path is SSE backed by the persisted event cursor; polling with bounded backoff is the required fallback and should be used for browsers/proxies that do not support SSE. Cancel is a cooperative action with an explicit pending/terminal result; retry is available only when the API authorizes it and must be presented as a new attempt/lineage. The UI must never infer progress from timers or claim work completed because a request was accepted.
The current client renders job status/counts, detail, structured errors, progress, and event timelines, and polls the jobs collection while queued/running work exists. It exposes authorized cancel/retry affordances based on the API response. There is no SSE client yet; polling is the current fallback and should remain available after SSE is introduced. The backend's SQLite/in-process worker is MVP-only. Do not add a Redis/Celery dependency by implication or label that worker production-ready.
Browser verification
- Start the API from
apps/apiwithpython3 app/main.py. - Serve this directory:
python3 -m http.server 8080 --directory apps/web. - Open
http://127.0.0.1:8080, withwindow.API_BASEset tohttp://127.0.0.1:8000using a tiny pre-load edit or browser devtools. - Sign in and confirm the header changes to API connected, tenant metrics populate, and the explorer renders a bounded page with search, score, status, and pagination controls.
- Select a row and confirm the detail view keeps the business, child intelligence, evidence provenance, confidence/freshness, pipeline, notes, and audit context associated with that tenant.
- Add or update only through the explicit manual controls. Confirm the refreshed detail/list state reflects the API response and that a viewer cannot mutate records.
- Confirm review and suppressed rows show Outreach unavailable with the appropriate reason. Confirm there is no outreach/send endpoint or button.
- Select a CSV and confirm a local, preview-only table appears without a network request or persistence.
- Resize below 700px to verify the collapsible nav, stacked panels, and horizontally scrollable explorer/detail content.
A zero-dependency static smoke page (smoke-test.html) checks the key DOM contract in an iframe and reports pass/fail. Browser smoke coverage should treat pagination, detail child records, provenance rendering, pipeline/notes actions, and the disabled outreach state as separate checks.
Phase 9 contact-observation UI contract
When the API supplies Phase 9 results, the UI may render contacts extracted from the approved/public official site and same-site contact/about pages. Display source URL/page context, extraction method, observed time, extractor/policy version, confidence and reasons, syntax status, role classification, free-mail classification, and independent MX/DNS status/freshness. Use explicit labels such as Observation, Human review required, and Unknown; never label a candidate verified, deliverable, owned, consented, or ready for outreach. The UI must show suppressed contacts as Do not contact, preserve the suppression reason, and never hide or override suppression through filters, refreshes, exports, or cached results.
Extraction is not a browser crawler. The browser must not fetch target pages directly, submit contact forms, execute target JavaScript, send credentials/cookies, probe SMTP, send validation messages, or expose an outreach/send control. Render bounded/partial/blocked/timeout/error results distinctly from an empty successful result, including candidate/page/byte/time limit reasons. Do not display false-positive candidates from assets, scripts/styles, example/test/placeholder values, tracking addresses, malformed schemes, or unrelated third-party pages.
The API remains authoritative for official-site scope, tenant isolation, suppression enforcement, limits, retention, provenance, and permissions. A cached extraction must show its observed time and freshness, never “live.” Candidate confidence, role/free-mail labels, syntax, and MX/DNS uncertainty are review metadata only and cannot enable a contact action.
Remaining limitations
The static client has no client-side crawler, scanner, contact extractor, enrichment scheduler, outreach integration, availability provider, or SSE delivery. It can display server-provided Phase 9 observations, but production still requires server-side official-site scoping, SSRF/DNS-rebinding/redirect controls, hard extraction/page/byte/time/candidate budgets, durable history/cache isolation and retention/deletion, abuse/rate controls, suppression regression tests, and authenticated provenance/audit coverage. For domain intelligence, display registrable-domain/PSL version and unresolved reasons, DNS status and freshness/TTL (not “available”), independent MX/NS/TXT uncertainty, and association confidence with explainable evidence. Never auto-attach candidate domains or treat nxdomain/no_data as availability. CSV preview is capped for display and is not an import workflow.