# AI Platform New AI Platform repository scaffold. The backend and SvelteKit implementation are being developed concurrently; this document records the intended local workflow, not a claim that every command already works. ## Runtime layout - Python 3.13 backend package: `src/ai_platform`, served as `ai_platform.main:app`. - PostgreSQL 16 with a new, project-specific Compose volume named `ai_platform_pgdata`. - Alembic schema changes are applied as a one-shot Compose service before the backend starts. - SvelteKit is a separate web image under `apps/web`. - `old_repo/` is archived source only and is excluded from Docker build contexts and local checks. The local Compose stack runs one backend process. It is for development only; default credentials and loopback port mappings are not deployment settings. Keep production secrets outside `.env` and inject them through the deployment environment or a secrets manager. ## Local setup Copy the backend/Compose template and the separate SvelteKit server-only template. Both `.env` files are ignored by Git; the previous root `.env` is preserved under `old_repo/.env` as historical local data, not loaded by the rebuilt service. ```sh cp .env.example .env cp apps/web/.env.example apps/web/.env make install ``` Start the database and run the backend and web servers in separate terminals: ```sh make db-up make migrate make backend-dev make web-dev ``` The local web server should call the backend through server-only configuration. Do not expose `BACKEND_INTERNAL_URL`, database credentials, or provider keys as browser-visible `PUBLIC_*` variables. Compose can instead build and start all services, including the one-shot migration step: ```sh docker compose up --build ``` The database is reachable from the host at `127.0.0.1:55432`, backend at `127.0.0.1:8000`, and web at `127.0.0.1:3000` by default. To discard only this new database and its data, run `docker compose down -v`; this does not target archived or unrelated volumes. The local database starts with only the development database. To run tests safely, create a separate database in that same new PostgreSQL instance, then pass its URL explicitly: ```sh docker compose exec postgres createdb -U ai_platform ai_platform_test AI_PLATFORM_DATABASE_URL=postgresql+asyncpg://ai_platform:local-change-this-password@127.0.0.1:55432/ai_platform_test make test ``` `make test` rejects a database URL that does not contain `ai_platform_test`. CI provisions its own isolated PostgreSQL 16 test database. ## Chấm điểm AI qua CLIProxy khi phát triển local Không cần chạy AIHub để thử adapter OpenAI-compatible. Cấu hình URL trên backend (trong môi trường hoặc `.env` local đã có): ```sh AI_PLATFORM_ENVIRONMENT=development AI_PLATFORM_OPENAI_BASE_URL=http://127.0.0.1:8317 # AI_PLATFORM_OPENAI_API_KEY=... # chỉ cần nếu CLIProxy yêu cầu xác thực ``` Chạy `make backend-dev` trên máy host: `127.0.0.1:8317` bên trong Docker không trỏ tới CLIProxy trên host. Trong Admin Web, tạo và kích hoạt **một phiên bản Cấu hình AI mới**, chọn `OpenAI-compatible`, nhập URL `http://127.0.0.1:8317`, model `gemini-3.5-flash-lite`, prompt và timeout. `AI_PLATFORM_OPENAI_BASE_URL` là URL mặc định cho profile cũ và là địa chỉ duy nhất nhận `AI_PLATFORM_OPENAI_API_KEY`; URL khác nhập trong Web không được gửi key đó. Profile cũ mặc định AIHub; URL AIHub vẫn cấu hình bằng `AI_PLATFORM_AIHUB_BASE_URL`. Lựa chọn này áp dụng cho các run mới của Lead Scoring, không đổi các run đã nhận trước đó. Gửi `POST /v1/lead-scoring/runs` với `ai_profile=medium`, `ai_weight>0` và tenant key; OpenAI-compatible không dùng `X-Tenant-VKey`. Nút “Chạy mẫu” trên Web hiện chỉ gửi mẫu quy tắc (`ai_weight=0`), nên hãy dùng API để thử AI. Với endpoint OpenAI-compatible chạy ở production, URL phải dùng HTTPS. Key được cấu hình trên server chỉ gửi tới URL được gắn với key đó; thay URL trên Web không tự chuyển key. Không đặt key vào Web hoặc file versioned. CLIProxy local chỉ xác minh được đường gọi thử; chưa chứng minh các điều kiện phát hành production. ## Terminal webhook và retention Khi cấu hình đồng thời `AI_PLATFORM_WEBHOOK_URL` và `AI_PLATFORM_WEBHOOK_SIGNING_SECRET` (ít nhất 32 ký tự), backend gửi thông báo kết thúc run tới một URL Omni cố định. URL HTTP chỉ hợp lệ trên loopback khi phát triển. Body chỉ có `event_id`, `run_id`, `tenant_id`, `status`, `occurred_at`; header `X-Webhook-Timestamp` và `X-Webhook-Signature` chứa chữ ký HMAC-SHA256 trên `timestamp + "." + raw body`. Phản hồi 2xx xác nhận giao; lỗi được thử lại tối đa 5 lần rồi giữ bản ghi đánh dấu `dead`. Chỉ bật gửi thực tế sau khi Omni xác nhận fixture chữ ký, chống replay và GET/writeback. Backend dọn run quá 90 ngày (gồm snapshot, fingerprint và thông báo liên quan) khi khởi động và mỗi ngày. Không áp dụng chính sách này cho backup; cần chốt vòng đời backup và tenant offboarding trước production. ## Quality checks The opt-in pre-commit runner is installed by `make install` as a project-local development dependency. Run: ```sh make check-fast make check ``` `make check-fast` runs the pinned Ruff and pre-commit-hooks rules. `make check` additionally runs Python type/import checks and tests; tests must use a separate test database, never a developer or production database. CI uses the same fast hooks and the Makefile test/check commands with an isolated PostgreSQL 16 service. ## Operations notes - Apply migrations as a release step; application startup must not migrate the database. - `/health/live` is liveness; `/health/ready` checks readiness and PostgreSQL. The Compose backend health check waits for readiness. - Avoid logging credentials, request payloads containing personal data, or provider responses with sensitive content. - The Compose PostgreSQL volume is disposable development data. Backup, restore, retention, secrets, TLS, and alerting must be defined for the eventual deployment target. The web container currently assumes `package.json`, `bun.lock`, a production SvelteKit build at `build/index.js`, and Bun compatibility with the selected SvelteKit adapter. Confirm those assumptions with the web implementation before treating the image as verified.