Files

6.6 KiB

sales_service Risk Points

Step 4 Event Outbox Status

Current state after Step 4:

  • sales_service publishes domain events to the shared event_outbox.
  • Publisher: services/sales_service/event_publisher.py (SalesEventPublisher).
  • Registry: services/sales_service/sales_events.py.
  • Events are appended before session.commit(), in the same transaction as the business change.
  • tenant_id is included in event envelope payload for every sales event.

Published MVP events:

  • lead.entered_crm
  • lead.enrichment_completed
  • deal.stage_changed
  • deal.scenario_selected
  • deal.next_action_scheduled
  • deal.closed
  • deal.lost
  • deal.won
  • communication.started
  • communication.summary_created
  • message.received
  • message.sent
  • call.received
  • call.completed
  • offer.created
  • offer.sent
  • offer.accepted
  • offer.rejected
  • deal.conditions_confirmed
  • counterparty.completed
  • document.created
  • document.sent
  • document.confirmed
  • document.signed
  • invoice.created
  • invoice.sent
  • invoice.overdue
  • payment.received
  • invoice.paid

Remaining risks:

  • No sales-specific consumers/handlers yet; outbox rows are ready for the shared dispatcher, but sales automation/analytics/post-sale reactions are future steps.
  • The shared event_outbox schema has no dedicated tenant_id, actor_type, actor_id, or causation_id columns. These values are stored inside payload_json.payload.
  • Event payload schemas are registry constants plus tests, not yet formal JSON Schema files.

DEFAULT_TENANT_ID

Current state after Step 2:

  • Production sales API flow no longer uses DEFAULT_TENANT_ID.
  • _tenant_id(actor) requires tenant context from JWT/legacy dev header.
  • Webhooks resolve tenant from auth/header or tenant_integrations provider mapping.
  • Sales reads/writes are tenant-scoped.

Remaining risk:

  • Tenant entity/settings are MVP-level, not full subscription/billing model.
  • Webhook provider signature verification is still separate from tenant resolution.

stage_id Changes

Current state after Step 3:

  • sales_pipelines and sales_pipeline_stages exist.
  • Deal.pipeline_id stores real pip_* public id.
  • Deal.stage_id stores real pst_* public id.
  • STAGE_LABELS is no longer the source of truth.
  • _apply_stage(...) resolves stable stage code to tenant/pipeline stage id and writes SalesStageHistoryRow.
  • Step 4 also publishes deal.stage_changed to event_outbox.

Initial stage writes:

  • _create_lead_and_deal_for_contact resolves default stage code new_qualified_lead to real pst_* id and records history.
  • _resolve_deal_for_inbound creates inbound lead/deal, resolves real stage id and records history.
  • create_lead creates a lead and auto-deal, then records history with reason lead.entered_crm.
  • create_deal resolves stage code/id input to real pst_* id and records history with reason deal.created.

Endpoint-driven stage changes:

  • POST /api/v1/leads/{lead_id}/enrich
  • POST /api/v1/deals/{deal_id}/change-stage
  • POST /api/v1/deals/{deal_id}/schedule-next-action
  • POST /api/v1/deals/{deal_id}/close
  • POST /api/v1/deals/{deal_id}/escalate
  • POST /api/v1/deals/{deal_id}/communications/text
  • POST /api/v1/deals/{deal_id}/communications/voice
  • POST /api/v1/communications/{communication_id}/switch-channel
  • POST /api/v1/communications/{communication_id}/bind-external
  • Offer actions: create/send/accept/reject.
  • Conditions upsert.
  • Counterparty create/patch.
  • Document create/send/confirm.
  • Invoice create/send/mark-overdue.
  • Payment webhook success/partial.

Risk:

  • No transition validation/state machine yet.
  • Stage customization is API/MVP-level; no UI/admin migration workflow for moving active deals between stages.

AutomationTask Creation

Central helper:

  • _schedule_task(session, deal, task_type, run_at, payload) creates SalesAutomationTaskRow.

Creation points:

Code area task_type
_start_communication payload.next_action_type
POST /api/v1/deals/{deal_id}/schedule-next-action payload.next_action_type
POST /api/v1/communications/{communication_id}/summary payload.next_action_type
POST /api/v1/communications/{communication_id}/switch-channel switch_to_{to_channel}
POST /api/v1/invoices/{invoice_id}/send invoice_follow_up

Task fields:

  • status defaults to pending.
  • retry_count defaults to 0.
  • last_error exists.
  • Index exists on (run_at, status).

Risk:

  • No worker/dispatcher found for pending tasks.
  • No API found to list/update/execute/cancel/retry automation tasks.
  • No overdue task handling found.
  • Status values allow running, completed, failed, canceled, but code only creates pending.

Payment Webhook

Endpoint:

  • POST /api/v1/payments/webhook

Input:

  • Required deal_id.
  • Optional invoice_id.
  • Optional external_payment_id.
  • payment_provider, amount, currency, status, paid_at, payment_method, failure_reason, metadata.

Current flow:

  1. Load deal by payload.deal_id.
  2. If invoice_id is present, load invoice by id.
  3. Create or update SalesPaymentRow idempotently by (tenant_id, payment_provider, external_payment_id) when external id is provided.
  4. If invoice exists and status is success:
    • invoice -> paid
    • invoice.paid_at set
    • deal.status -> won
    • deal.closed_at set
    • deal.final_amount set to payment amount
    • stage -> won
    • ensure CRM customer
  5. If invoice exists and status is partial:
    • invoice -> partially_paid
    • stage -> partially_paid
  6. If invoice exists and status is failed:
    • only invoice.updated_at changes.

Risk:

  • No provider signature verification.
  • Payment idempotency depends on provider sending external_payment_id.
  • Payment totals are not reconciled against invoice amount before marking paid.
  • Endpoint still lacks provider-specific webhook signature authentication.

Notes

Current state:

  • SalesNoteRow and sales_notes exist.
  • No SalesNoteIn/Out schemas found.
  • No notes API routes found.
  • SalesWorkspaceOut does not include notes.

Risk:

  • Notes are table-only, not product-ready.
  • System/user notes cannot be created or retrieved through current sales API.

Escalation

Current state:

  • POST /api/v1/deals/{deal_id}/escalate creates SalesEscalationRow.
  • It sets deal.assigned_human_user_id.
  • It sets deal.scenario_type = "custom_human_escalation".
  • It moves stage to transferred_to_support.

Risk:

  • No resolve/reassign API found.
  • No integration with queue/routing SLA in sales-service.
  • No status transition beyond initial open.