Files
MarketingTool/apps/web

ProspectOS web — Phase 6 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 and a Phase 4 MVP job monitor. Phase 5 source concepts and Phase 6 normalization/deduplication concepts are display/contract boundaries only; the UI does not perform network discovery, scan DNS/websites, or send outreach.

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/businesses and 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.750.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 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

  1. Start the API from apps/api with python3 app/main.py.
  2. Serve this directory: python3 -m http.server 8080 --directory apps/web.
  3. Open http://127.0.0.1:8080, with window.API_BASE set to http://127.0.0.1:8000 using a tiny pre-load edit or browser devtools.
  4. 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.
  5. 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.
  6. 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.
  7. Confirm review and suppressed rows show Outreach unavailable with the appropriate reason. Confirm there is no outreach/send endpoint or button.
  8. Select a CSV and confirm a local, preview-only table appears without a network request or persistence.
  9. 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.

Remaining limitations

The static client has no background discovery, DNS/website scanner, enrichment scheduler, outreach integration, or SSE delivery. It cannot make missing provenance authoritative and should display API-provided limitations rather than infer them. CSV preview is capped for display and is not an import workflow. Production deployment still requires durable job execution, tenant-scoped controls, idempotency verification, SSE/polling verification, and the security and operations gates in docs/SECURITY.md and docs/OPERATIONS.md.