6.7 KiB
Contract API
FastAPI service for V2 contract workflows.
Storage
Contract list, detail, workspace tasks and approval timeline data use the SQLAlchemy repository. Local development defaults to SQLite so the V2 main flow can run without extra services:
CONTRACT_API_DATABASE_URL=sqlite+pysqlite:///.runtime/contract-api.sqlite3
Production can switch to PostgreSQL with the same repository:
CONTRACT_API_DATABASE_URL=postgresql+psycopg://contract:contract@localhost:5432/yuqei_contract
CONTRACT_API_DATABASE_AUTO_CREATE=false
CONTRACT_API_SEED_DEMO_DATA=false
Run migrations from this service directory:
cd yuqei-contract-platform/services/contract-api
python -m alembic upgrade head
Local Run
cd yuqei-contract-platform/services/contract-api
python -m uvicorn yuqei_contract_api.main:app --app-dir src --reload --port 8100
Run the contract review worker in another terminal when testing async AI review:
cd yuqei-contract-platform/services/contract-api
$env:PYTHONPATH="src;../../../yuqei-ai-sdk-python/src"
python -m yuqei_contract_api.review_worker
Process one queued review task batch and exit:
python -m yuqei_contract_api.review_worker --run-once --limit 1
Health endpoints:
GET /healthGET /api/v1/healthGET /api/v1/runtime/config-checkpython -m yuqei_contract_api.review_worker --health
/api/v1/runtime/config-check is the deployment guardrail. It flags unsafe runtime settings such as production SQLite, production auto table creation, enabled demo seed data, invalid AI Platform URL, invalid worker intervals, inconsistent identity delivery mode, missing identity rate-limit secrets, or an empty file storage directory.
Contract review worker production variables:
CONTRACT_API_ENVIRONMENT=production
CONTRACT_API_DATABASE_URL=postgresql+psycopg://...
CONTRACT_API_DATABASE_AUTO_CREATE=false
CONTRACT_API_SEED_DEMO_DATA=false
CONTRACT_API_FILE_STORAGE_DIR=/data/contract-files
CONTRACT_API_AI_PLATFORM_BASE_URL=http://ai-platform-api:8101
CONTRACT_API_AI_PLATFORM_TIMEOUT_SECONDS=60
CONTRACT_API_UVICORN_WORKERS=1
CONTRACT_API_READ_CACHE_TTL_SECONDS=2
CONTRACT_API_REVIEW_WORKER_NAME=contract-review-worker-1
CONTRACT_API_REVIEW_WORKER_POLL_INTERVAL_SECONDS=5
CONTRACT_API_REVIEW_WORKER_BATCH_LIMIT=5
CONTRACT_API_IDENTITY_EMAIL_DELIVERY_MODE=disabled
CONTRACT_API_IDENTITY_SELF_SERVICE_ENABLED=false
CONTRACT_API_IDENTITY_MANUAL_INVITATION_ENABLED=true
CONTRACT_API_IDENTITY_RATE_LIMIT_SECRET=LOAD_A_STABLE_RANDOM_SECRET_OF_AT_LEAST_32_CHARACTERS
CONTRACT_API_AI_PLATFORM_TIMEOUT_SECONDS covers the complete Contract-to-AI request and must exceed AI_PLATFORM_PROVIDER_REQUEST_TIMEOUT_SECONDS by at least five seconds. For example, use 240 when staging a Provider timeout of 180 seconds.
The disabled mode keeps login and administrator-managed one-time invitation links available while public company registration, password reset, and email verification remain off. When enterprise email becomes available, switch to smtp, set manual invitations to false, and configure the SMTP variables from .env.example. The production web proxy must overwrite public X-Real-IP / X-Forwarded-For headers before Contract Web forwards the validated client IP to Contract API for rate limiting.
After migrations, initialize the first production administrator from a protected password file. The command is idempotent and will not replace an existing credential unless --force-rotate is supplied:
python -m yuqei_contract_api.identity_bootstrap `
--tenant-id default `
--company-name "平台租户" `
--email platform-admin@example.com `
--display-name "平台管理员" `
--password-file C:\run\secrets\bootstrap-admin-password
After deployment, verify the end-to-end review path from repository root:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File yuqei-infra\scripts\verify-contract-review-worker-flow.ps1 `
-ContractApiBaseUrl http://localhost:8100 `
-WorkerExecutionMode docker-compose `
-RequireConfidence
Use -RequirePrimarySources when the target environment has a populated knowledge base and the review must prove source-backed RAG output.
Docker Compose Baseline
From repository root:
Copy-Item yuqei-infra\compose\.env.example yuqei-infra\compose\.env
docker compose --env-file yuqei-infra\compose\.env -f yuqei-infra\compose\docker-compose.yml up --build
The compose baseline runs contract-api-migrate before contract-api, and keeps CONTRACT_API_DATABASE_AUTO_CREATE=false inside containers. For production, also set:
CONTRACT_API_ENVIRONMENT=production
CONTRACT_API_SEED_DEMO_DATA=false
After startup:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File yuqei-infra\scripts\verify-v2-runtime.ps1
Test
Run Contract API tests from this service directory. The migration tests resolve
alembic.ini and migrations/ relative to the current directory, so running
the same command from the repository root is not supported.
Give every full run a new SQLite database and an independent file-storage directory. This prevents a previous run, a local development database, or concurrently running services from changing the result:
cd yuqei-contract-platform/services/contract-api
$testRunId = [guid]::NewGuid().ToString("N")
$testRoot = Join-Path ([System.IO.Path]::GetTempPath()) "yuqei-contract-api-tests-$testRunId"
$testFiles = Join-Path $testRoot "files"
$testDatabase = (Join-Path $testRoot "contract-api.sqlite3").Replace("\", "/")
New-Item -ItemType Directory -Force -Path $testFiles | Out-Null
$env:PYTHONPATH = "src;../../../yuqei-ai-sdk-python/src"
$env:CONTRACT_API_ENVIRONMENT = "test"
$env:CONTRACT_API_DATABASE_URL = "sqlite+pysqlite:///$testDatabase"
$env:CONTRACT_API_DATABASE_AUTO_CREATE = "true"
$env:CONTRACT_API_SEED_DEMO_DATA = "false"
$env:CONTRACT_API_FILE_STORAGE_DIR = $testFiles
python -m pytest -q tests
The PostgreSQL concurrency suite is opt-in. Without
CONTRACT_API_POSTGRES_CONCURRENCY_URL it is reported as skipped. Point the
variable only at a dedicated non-production PostgreSQL database; the suite
creates a random isolated schema, runs migrations inside it, and removes the
schema after the test. Supply credentials only through the temporary process
environment and never commit them to .env, README examples, logs, or source:
$env:CONTRACT_API_POSTGRES_CONCURRENCY_URL = "postgresql+psycopg://USER:PASSWORD@HOST:5432/TEST_DATABASE" # pragma: allowlist secret
python -m pytest -q tests/test_privileged_identity_postgres_concurrency.py
Remove-Item Env:CONTRACT_API_POSTGRES_CONCURRENCY_URL