File-by-file implementation plan
This is the handoff for the coding agent. It is based on the current repository layout observed inapps/api, apps/web, and libs/db. It is
intentionally narrow: no new package, no new transport, no broad refactor.
Slice A — Provenance and rights
Modify
libs/db/src/entities/record.entity.ts- Keep dynamic customer fields in
fields. - Extend
field_metaor add a dedicated relation for contact endpoint rights; do not hide compliance state in an untyped string.
- Keep dynamic customer fields in
apps/api/src/radar/contact-path.ts- Add the logical provenance/rights shape to
ContactEndpoint. - Preserve the distinction between personal, role, and general endpoints.
- Keep
assertNoGeneralAsPersonalas a domain invariant.
- Add the logical provenance/rights shape to
apps/api/src/radar/ports/endpoint-verifier.port.ts- Extend
ResolvedEndpointonly with metadata the adapter can substantiate. - Never synthesize license approval from provider identity.
- Extend
apps/api/src/radar/radar-enrichment.service.ts- Persist
sources, provider, observed time, verification, attribution, and policy decision. - Preserve fallback provider/source instead of writing null by default.
- Reject or quarantine unknown rights according to policy.
- Persist
apps/api/src/radar/radar.module.ts- Wire the policy/provenance service through existing module boundaries.
Add
libs/db/src/entities/contact-endpoint-provenance.entity.tsif a normalized table is selected.libs/db/src/entities/provider-policy.entity.ts.libs/db/src/migrations/<timestamp>-contact-governance.ts.apps/api/src/radar/contact-governance.service.ts.apps/api/src/radar/contact-governance.service.spec.ts.
Slice B — Authorization ledger
Reuse and modify
libs/db/src/entities/audit-log.entity.ts- Continue using it for immutable action evidence, but do not put raw emails,
message bodies, OAuth data, or full audience payloads in
detail.
- Continue using it for immutable action evidence, but do not put raw emails,
message bodies, OAuth data, or full audience payloads in
apps/api/src/audit/audit.service.ts- Keep ordinary audit best-effort behavior for non-blocking telemetry.
- Authorization creation must use a transactional, fail-closed persistence path; an audit write failure cannot silently authorize a sensitive action.
apps/api/src/radar/radar.controller.ts- Expand the enrichment DTO with a bounded purpose/policy acknowledgement or resolve an authorization before calling the service.
apps/api/src/radar/dto/radar.dto.ts- Add enum validation; do not accept arbitrary legal claims from clients.
apps/api/src/radar/radar-enrichment.service.ts- Require a valid enrichment authorization before provider calls.
Add
libs/db/src/entities/data-authorization.entity.ts.apps/api/src/authorization/authorization.service.ts.apps/api/src/authorization/authorization.module.ts.apps/api/src/authorization/dto/create-authorization.dto.ts.- Tests for replay, expiry, revocation, workspace isolation, and action separation.
Slice C — Suppression
Add
libs/db/src/entities/suppression-entry.entity.ts.apps/api/src/suppression/suppression.service.ts.apps/api/src/suppression/suppression.module.ts.apps/api/src/suppression/suppression.controller.tsfor authorized human management only.apps/api/src/suppression/suppression-policy.spec.ts.
Integrate
radar-enrichment.service.ts: check before provider calls.- export service/controller: check before materializing output.
- future campaign/send service: check at final execution time.
apps/api/src/email/unsubscribe.controller.ts: map unsubscribe events to a suppression entry where the event is attributable to a workspace.
Slice D — Retention and deletion
Modify
apps/api/src/retention/retention.job.ts- Add contact expiry and provider-deletion work only after the data model and provider contracts exist.
- Make runs idempotent and report unresolved provider deletions.
apps/api/src/collections/records.service.ts- Route contact deletion/expiry through one policy-aware operation.
apps/api/src/export/export.service.ts- Keep exports scoped and add governed contact fields only when permitted.
apps/api/src/export/export.controller.ts- Require/export an explicit export authorization for sensitive contact data; preserve current owner/admin and human-session checks.
Add
apps/api/src/retention/contact-retention.service.ts.apps/api/src/retention/contact-deletion.service.ts.- Tests covering record fields, serialized paths, indexes, exports, drafts, campaign references, and provider failures.
Slice E — Google data
Inspect and modify
apps/api/src/integrations/integrations.service.ts.apps/api/src/integrations/nango.service.ts.libs/db/src/entities/oauth-token.entity.ts.- existing connection/revocation controllers and retention paths.
- scope catalog per feature;
- incremental consent;
- token revocation and deletion;
- no copy from private Google data into shared commercial records;
- audit of connection, use, and disconnect without logging contents.
Slice F — Frontend
The coding agent should first locate the current Radar collection UI before editing. The required surfaces are:- enrichment confirmation;
- export confirmation or blocked-field explanation;
- send confirmation when a send surface exists;
- provider/Google connection disclosure;
- provenance detail view;
- suppression/opt-out state.
Explicitly out of scope for the first implementation
- automatic legal-basis selection per contact;
- a generic policy engine for every product feature;
- a new queue/transport/cache;
- activation of Smartlead, Hunter, or Tomba without provider evidence. Smartlead is legacy-only; the active beta sender is Nylas and remains send-only.
- generalized CRM campaign automation;
- claims of regulatory certification.
Coding-agent handoff checklist
Before opening a PR, the coding agent must provide:- migration list and rollback notes;
- changed files mapped to slices above;
- tests for every acceptance-test row;
- proof that raw contact data is absent from audit details/logs;
- provider-policy fixtures for approved, restricted, unknown, and blocked;
- deletion and suppression integration evidence;
- full harness result, including unrelated baseline failures separately.
