# Phase 5 Customer Discovery

## Status

Phase 5 is active under Issue #23. This checkpoint is synthetic and must not be interpreted as a production map, location, publication or customer-search deployment.

## Purpose

Phase 5 turns Phase 4 scoped claim cards into a customer-facing discovery contract without exposing original evidence, reviewer information or precise private provider locations.

The phase implements:

- customer onboarding and location-permission education;
- manual and one-time-location search models;
- policy-controlled provider/category publication;
- public-safe PostGIS search;
- list and synthetic map presentation;
- public provider/trust profiles;
- saves and share-safe metadata;
- low-bandwidth and image-free presentation;
- deterministic empty, sparse and no-location states.

## Publication model

A publication is a provider/category projection, not a provider-owned flag.

`discovery.refresh_publication()` is the only database function permitted to create or refresh a publication. A trigger rejects direct inserts, updates and deletes unless the policy function has established the transaction-local publication context.

Publication requires:

1. an active selected provider category and pinned requirement version;
2. provider state `ready_for_verification`;
3. a public-safe location record and service area;
4. a consented public premises point for fixed and hybrid providers;
5. one current active scoped claim for every mandatory requirement;
6. an explicit publication policy version.

Public search re-evaluates provider state and mandatory claim freshness on every query. A stale publication snapshot therefore cannot keep a suspended provider or expired mandatory claim visible.

Payment, profile completion, administrator row edits and client input are not publication inputs.

## Location types

`discovery.provider_locations` stores distinct fields:

- `private_base`: restricted operating-base evidence; never serialized publicly;
- `public_premises`: optional consented public point suitable for customer presentation;
- `service_area`: non-private polygon used for mobile/hybrid compatibility;
- `public_locality`: coarse human-readable public description;
- source, confidence and confirmation timestamp.

The public projection contains only the consented public premises point and public service-area geometry.

### Fixed premises

Distance may be calculated only from `public_premises`. Publication requires a consented public point.

### Mobile

Search uses `ST_Covers(service_area, origin)`. No public point or distance from the provider’s private base is returned.

### Hybrid

Search may match either the public premises distance or the public service area. The private base remains excluded.

## Customer location

Version 1 prohibits background location.

The Android model provides:

- manual area/landmark entry as the default and permanent fallback;
- a one-time current-area education path;
- no continuous tracking;
- no retained exact customer coordinate in the synthetic state;
- no ranking penalty for manual selection.

Real permission requests, geocoding and map SDK traffic remain integration gates.

## Search contract

Public endpoints:

```text
GET /api/v1/public/categories
GET /api/v1/public/providers/search
GET /api/v1/public/providers/{publicProviderId}
GET /api/v1/public/providers/{publicProviderId}/claims
GET /api/v1/public/providers/{publicProviderId}/availability
GET /api/v1/public/providers/{publicProviderId}/share
```

Search supports:

- category;
- normalized text;
- manual area;
- optional one-time latitude/longitude origin;
- public-premises radius;
- operating model;
- minimal availability state;
- scoped claim key;
- bounded limit and opaque cursor.

Ordering is deterministic:

1. service-area compatibility;
2. consented public-premises distance where applicable;
3. public display name;
4. public publication ID.

The cursor contains only a versioned offset encoded as opaque base64url. It does not contain a private provider ID, coordinate or evidence reference.

## Explainability

Allowlisted result reasons are generated by the backend from safe data:

- `Current mandatory checks`;
- `Serves your selected area`;
- `Public premises within selected distance`;
- `Currently marked available`.

Android does not infer verification or ranking reasons.

## Public DTO boundary

Public cards expose:

- public provider ID;
- category and public display name;
- operating model;
- public locality;
- consented public premises or service-area geometry;
- minimal availability;
- approved public image variants;
- current scoped claim cards and limitations;
- allowlisted reasons;
- public distance where lawful;
- share-safe path.

They do not expose:

- internal provider ID;
- private base;
- original evidence or storage key;
- document or contact identifiers;
- reviewer, assignment or decision notes;
- exact customer location;
- payment or subscription state.

## Saves and sharing

Authenticated customers may save only an eligible public publication ID. Saved-provider reads dynamically exclude hidden, suspended or stale publications.

Share metadata contains public ID, public name, category, locality and a relative public path. It contains no private location or contact handoff.

## Media and low bandwidth

Approved public media may provide separate low-bandwidth and standard URLs plus alt text. Images are optional.

Android supports:

- data-saver preference;
- standard preference with low-bandwidth fallback;
- image-free mode;
- complete text, location, claim and availability presentation without an image.

Real object storage/CDN integration remains deferred until the dedicated DIREKT infrastructure and secrets are available.

## No-results behavior

Empty search returns an empty item list and safe suggestions to:

- try a nearby area or landmark;
- remove a filter or increase public-premises distance;
- choose another active category.

The backend and Android never fabricate providers.

## Operations visibility

The operations portal shows synthetic publication eligibility:

- provider/category and operating model;
- public locality and safe location readiness;
- mandatory-claim freshness;
- publication state.

It does not display private coordinates, evidence details or a direct database publication bypass.

## Automated controls

The Phase 5 regression suite must prove:

- direct publication writes fail;
- incomplete mandatory claims cannot publish;
- private coordinates and internal IDs are absent from public responses;
- fixed, mobile and hybrid providers use the correct safe geospatial behavior;
- manual area and one-time-origin searches both work;
- multi-filter cursor pagination is deterministic;
- suspended and stale-claim providers disappear dynamically;
- claim limitations, image fallback and share metadata remain safe;
- saves use only public IDs;
- no-results recovery returns no fabricated provider.

## External integration handoff

When approved integrations become available:

- Google Maps/Places/Geocoding replace only the location adapter and Android map renderer;
- Supabase/private storage remains behind the existing storage adapter;
- Cloud Run and Vercel consume the existing API boundary;
- Firebase may distribute and observe the Android build;
- no external integration may bypass publication, claim freshness or privacy rules.
