114 lines
9.2 KiB
Markdown

# Technology Stack
> This document records technology decisions, default candidates, deferred options, and trade-offs. It does not override the approved Lead Scoring Customer Pilot specification or released executable contracts.
## Project Context and Boundaries
- Purpose: Build the first Python-based Lead Scoring service in AI Platform for a controlled Customer Pilot.
- Shape: Workspace containing specifications, documentation, and the initialized baseline for the Lead Scoring service (`src/lead_scoring/`).
- Material constraints:
- DotB EMS remains the CRM source of truth.
- Omni owns EMS integration, identity resolution, conversation enrichment, Lead Scoring configuration, and HITL UI.
- Lead Scoring owns scoring logic, versioned configuration, scoring-run history, and domain events.
- AIHub owns model access, V-Key validation, quota, credit, and LLM audit.
- Global runtimes and the shared `mcpls` configuration remain outside project bootstrap scope.
## Active Decisions
### Service runtime and HTTP framework
- Status: Implemented baseline in `src/lead_scoring/`.
- Primary decision owner: Lead Scoring service.
- Technology: Python 3.13, `uv`, FastAPI, and Pydantic.
- Rationale: The service is Python-first, Pydantic provides executable validation, and FastAPI derives the API contract from the same models.
- Baseline implementation: `src/lead_scoring/` package, `GET /health` endpoint, async lifespan managing database engine and session factory.
### API contract and generated client
- Status: Implemented baseline CLI for OpenAPI generation.
- Primary decision owner: Lead Scoring API contract.
- Technology: Pydantic models as the API source of truth, FastAPI-generated OpenAPI, CLI generator with `--check` stale detection.
- Rationale: One executable backend contract avoids handwritten DTO and frontend client drift.
- Constraints: Generated artifacts (`openapi.json`) are ignored derived artifacts produced deterministically by `uv run generate-openapi` and verified for drift via `--check`. Never edit manually.
### Shared executable Contract Pack
- Status: Selected pre-release baseline for the Customer Pilot.
- Primary decision owner: AI Platform, with DotB-Omni review and consumer validation.
- Technology: Versioned committed directory at `contracts/lead-scoring-contract-pack/v1/`, generated from Pydantic models, OpenAPI and shared JSON fixtures.
- Rationale: One pinned artifact corpus lets provider and consumer repositories validate the same exact wire shapes without maintaining competing payload definitions.
- Versioning: Consumers pin `contract_pack_version` together with the AI Platform Git commit. Additive changes preserve the API major and existing required fields/enums; breaking changes publish a new major directory and retain the old pack.
- Verification: `uv run generate-contract-pack --validate-fixtures` validates positive and negative provider fixtures, while `uv run generate-contract-pack --check` detects missing, stale or unexpected artifacts.
### Persistence engine and migration tooling
- Status: Adopted and implemented baseline.
- Primary decision owner: Lead Scoring persistence and delivery boundary.
- Technology: PostgreSQL 16+, SQLAlchemy 2 async (`asyncpg`), Alembic async migration lifecycle.
- Rationale: Production requires PostgreSQL-native features (transactional outbox, jsonb, concurrency safety). SQLite fallback is strictly prohibited to prevent dialect divergence.
- Verification: Database integration tests execute real Alembic `upgrade head` and `downgrade base` lifecycle against disposable PostgreSQL 16 containers via Docker testcontainers. SQLite and ambient database fallbacks are strictly prohibited.
### Verification and repository command surface
- Status: Implemented baseline command surface.
- Primary decision owner: Root-level generation and verification workflow.
- Selected baseline: `uv` lockfile, Ruff, Pyright, `ty` for fast feedback, pytest (with `pytest-asyncio` and `testcontainers[postgres]`).
- Rationale: A small command surface serves local development, agents, hooks, and CI without adding a task orchestrator.
- Constraints: Pyright remains the authoritative type-checking reference. `ty` is non-authoritative fast feedback.
### AI integration and credential boundary
- Status: Adopted by the approved specification.
- Primary decision owner: Lead Scoring and AIHub service boundary.
- Technology: Bounded fixed-pass scoring pipelines; caller-provided `X-Tenant-VKey` held in memory by Lead Scoring and forwarded to AIHub as a Bearer token.
- Rationale: AIHub remains the single owner of model access and quota while Lead Scoring avoids persistent raw V-Key storage and an extra resolver service.
- Constraints: Raw V-Keys must not enter databases, queues, caches, logs, crash dumps, or browser code. Autonomous tools and unbounded agent loops are outside the pilot.
### Pilot durability and event delivery
- Status: Selected pattern; persistence baseline adopted with PostgreSQL.
- Primary decision owner: Lead Scoring persistence and delivery boundary.
- Technology: Durable scoring runs plus transactional outbox and registered webhook delivery on PostgreSQL; no dedicated message broker for the pilot.
- Rationale: This preserves run durability and retryable delivery without adding Kafka, RabbitMQ, or another operational subsystem before the workload requires one.
- Open work: Implement retry worker, outbox table schema, and webhook delivery on the adopted PostgreSQL persistence baseline.
### Pilot scoring execution topology
- Status: Adopted and implemented for rule-only execution.
- Primary decision owner: Lead Scoring runtime lifecycle.
- Technology: In-process `asyncio` tasks with PostgreSQL conditional claims and expiring run leases.
- Rationale: This is the smallest topology that keeps the raw tenant V-Key in the live attempt only, prevents duplicate claims, and lets database recovery terminalize orphaned work without adding a broker.
- Constraints: A process or task loss cannot resume the attempt because the V-Key is not durable. Recovery commits `worker_interrupted` with `retryable=true` and a terminal outbox event; retry is a new admission action.
### Frontend toolchain
- Status: Selected for the internal Dev Console; not implemented.
- Primary decision owner: AI Platform internal console, with Omni owning customer-facing configuration and HITL UI.
- Technology: Svelte 5, TypeScript, Bun, Vite, Vitest, `@sveltejs/vite-plugin-svelte`, `svelte-check`, `@sveltejs/mcp`, ESLint, and Prettier Svelte tooling.
- Rationale: This provides a small client for generated OpenAPI types without adding SvelteKit before routing, SSR, or deployment requires it.
- Constraints: The console must not duplicate Omni business UI. It uses a backend-only internal test V-Key separate from production Omni tenant credentials; raw V-Key never reaches browser code. Add a Svelte language server only if `mcpls` must serve `.svelte` files semantically.
### Pilot trigger boundary
- Status: Adopted by the approved specification.
- Production initiation: Manual Omni action and Captain `create_and_score_ems_lead` tool invocation.
- Internal initiation: AI Platform Dev Console using a separate backend-only test V-Key.
- Deferred: Generic automatic input-event triggers such as message-created, conversation-resolved, or EMS lifecycle events.
- Constraint: Completion events from Lead Scoring to Omni remain required and are distinct from deferred input triggers.
## Evaluated Options
- TypeScript 7 native compiler and LSP: `candidate` - Run project-locally as `tsc --lsp --stdio` or `tsgo --lsp --stdio`. Do not change global TypeScript, Node, or `mcpls` defaults before a project-local pilot.
- `typescript-language-server`: `current` - Existing `mcpls` backend for TypeScript and JavaScript. Its push-only diagnostics behavior does not satisfy the current `mcpls` pull-diagnostics path; upgrading the wrapper alone is not the fix.
- `svelte-language-server`: `deferred` - Add only if `mcpls` must provide semantic LSP support for `.svelte`.
- SvelteKit: `deferred` - Add only when production routing, SSR, or deployment requires it.
- `oasdiff`: `deferred` - Adopt as a blocking compatibility check after the first reviewed and versioned OpenAPI baseline exists.
- Schemathesis: `deferred` - Adopt when the real ASGI app, declared error responses, deterministic authentication, and external-service overrides exist.
- Dedicated broker such as Kafka or RabbitMQ: `deferred` - Transactional outbox and registered webhooks are sufficient for the Customer Pilot boundary.
- Monorepo orchestrator, second formatter or linter, generic agent framework, or custom build system: `rejected` - No current requirement justifies the maintenance and duplicate source-of-truth cost.
## Unresolved Decisions
- Production deployment and service-to-service security: Pilot caller authentication is the approved per-app opaque Bearer service-token pattern; define hosting, network exposure, per-environment secret delivery, rotation/revocation, and operational ownership before Customer Pilot deployment.
- TypeScript 7 adoption: Decide whether TS7 is the project compiler only or also the `mcpls` language-server backend after a project-local pilot verifies build, typecheck, diagnostics, and compatibility with the selected Svelte tooling.