dotb_ai-platform/ARCHITECTURE.md
hungtran24 6577bb74be refactor: simplify scoring service, AI profile revisions and test suite
Phase 2 and 3 of the platform rework.

- Neutral request/response contract: external_id, metadata, X-AI-Key,
  run_id in the response; client-specific fields removed.
- AI profile is a revision table: saving creates an inactive revision,
  activation is separate, try-run does not store a run. One
  chat-completions gateway serves AIHub and OpenAI-compatible profiles.
- Add between and in rule operators.
- Contracts moved to contracts/lead-scoring/ with a score-response fixture.
- Admin Web updated for revisions, runs and the neutral fixture.
- Consolidate tests; remove rewrite_architect.md and the stale handoff doc;
  rewrite spec, CONTEXT and ARCHITECTURE for the current design.

Not verified: live AIHub/OpenAI behavior, Omni/EMS integration.
2026-10-09 08:23:21 +07:00

4.9 KiB

Architecture

Status and scope

This document records module boundaries for the AI Platform Lead Scoring service. Behavior is in docs/specs/ai-platform-lead-scoring.md; wire shapes are in contracts/lead-scoring/. The current backend and Admin Web live under src/ai_platform/ and apps/web/. Local checks do not establish client integration, live AI behavior or production readiness.

AI Platform is a shared scoring service. A client sends a snapshot with rules and weights to one synchronous endpoint and receives the score, breakdown, summary, signals and suggested action. The client owns thresholds, human review, user authorization and CRM writeback. There is no customer-facing UI in this service.

Backend boundaries

One runtime, one deployable backend, under src/ai_platform/.

  • Bootstrap: loads validated settings and composes framework, database, one shared HTTP client and use cases. Resource lifetime is established here.
  • Platform: app-key verification, admin auth and sessions, shared persistence and settings.
  • Lead Scoring domain: pure rule execution and metrics, canonical fingerprinting, safe_http_url. No framework, network, environment or clock access.
  • Lead Scoring application: the score use case (idempotent lookup, AI evaluation under a deadline, persistence), prompt building, the AI profile admin use cases and the ports they need. Use cases own commit and rollback.
  • Infrastructure: SQLAlchemy repositories and one chat-completions HTTP gateway used for both AIHub and OpenAI-compatible profiles. Provider details stop here.
  • Presentation: HTTP schemas, mapping, auth dependencies and error mapping. Transport schemas do not become domain objects.

Dependency direction is inward and enforced by Import Linter: domain depends on nothing; application must not import infrastructure, presentation or bootstrap; presentation must not import infrastructure or SQLAlchemy. Avoid generic base services, empty ports, service locators and extra processes unless evidence requires them.

Lifecycle and data invariants

  1. Authenticate the app by its key; the app ID comes from the key, never the body.
  2. Validate bounded input and fingerprint the canonical body.
  3. Look up (app_id, idempotency_key) before any AI call. Same fingerprint replays the stored result; a different one is rejected. A concurrent insert race re-reads the winner.
  4. Commit the read transaction before the AI call. The AI call has a deadline from the active profile; failure or timeout degrades to the rule score with an error code.
  5. The AI key lives in memory for the call only and is never persisted, logged or returned.
  6. Persist the run with the profile revision used, then return the result. Replay returns the stored result.
  7. AI profile saves create inactive revisions; activation is separate and revisions are never edited.

Transaction and effect boundaries

  • Use cases define atomic boundaries; persistence adapters implement them.
  • The AI call is a network effect with an explicit timeout and no automatic retry.
  • Clock, provider factory and persistence are explicit inputs at the application boundary.
  • Domain functions are deterministic and I/O-free.

Admin Web design system

Admin Web dùng SvelteKit 5, Tailwind CSS v4 semantic tokens, shadcn-svelte component source cho button/input/card/badge/table khi UI cần, Bits UI cho dialog/dropdown/popover hoặc tương tác phức tạp, và một icon family Lucide nếu cần icon. Chỉ thêm component đang dùng, không scaffold cả catalog. src/lib/components/ui/ chỉ chứa primitives không biết domain; route giữ thành phần chỉ dùng tại route. HTML native là lựa chọn đúng cho form, label và bảng đơn giản khi không cần behavior phức tạp. Style tokens có một nguồn trong apps/web/src/app.css; UI phải kiểm tra focus, keyboard, validation, responsive và contrast. Browser chỉ gọi SvelteKit; backend auth/credentials và BACKEND_INTERNAL_URL thuộc $lib/server/. Không tạo frontend Clean Architecture giả lập.

Verification structure

  • Domain: rule operators, metrics and score formulas without network or database.
  • Endpoint: the score route through application and persistence on PostgreSQL (ai_platform_test) with a mock AI transport, covering result modes, replay, concurrency, auth and error shapes.
  • Adapter: request shape and error mapping of the chat-completions gateway.
  • Contract: committed OpenAPI and fixtures match the generator; the initial migration matches the models.
  • Architecture: Import Linter contracts.
  • Web: server-only logic with Vitest; svelte-check against types generated from OpenAPI.

Deferred decisions

Production hosting, TLS topology, secret management, database backup and retention, alerting, load targets and the real AIHub protocol and model behavior remain open. Resolve them with accountable owners before deployment. No production-readiness claim is warranted while these remain open.