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
The legal-QA browser flow uses POST /api/v1/legal/qa/jobs, polls
GET /api/v1/legal/qa/jobs/{job_id}, and exposes explicit retry and human
handoff actions. Contract API only applies tenant/user authorization and proxies
these operations; the durable model task and provider audit remain owned by AI
Platform. The older synchronous legal-QA endpoint remains temporarily available
for compatible internal callers.
Run Enterprise Playbook calendar schedules, impact analysis, notifications, secret-grace cleanup, and dead-letter alert evaluation in a separate worker:
cd yuqei-contract-platform/services/contract-api
$env:PYTHONPATH="src;../../../yuqei-ai-sdk-python/src"
python -m yuqei_contract_api.playbook_governance_worker
This worker also leases and runs the P1-07.1 pilot anomaly scanner, reconciles strict reliable-contract-decision evidence, and enqueues work-calendar SLA escalations into the existing notification delivery queue. Run python -m yuqei_contract_api.playbook_governance_worker --run-once after deployment to verify the complete governance cycle.
Google Calendar and Microsoft Graph sources require a provider client ID and
secret plus exactly one dedicated OAuth token-encryption secret source. The
authorization callback defaults to http://localhost:3000/admin/playbook; use
an HTTPS callback outside local development. See .env.example for the exact
variables. Refresh tokens and incremental cursors are encrypted at rest, and
scheduled sources are claimed by a database lease before synchronization.
DingTalk and WeCom sources use each tenant's internal-app credentials instead
of a global OAuth client. Admins enter DingTalk AppKey/AppSecret plus a calendar
owner UnionID, or WeCom CorpID/CorpSecret plus cal_id; the secrets and
short-lived access tokens use the same dedicated encryption key and are never
returned. DingTalk persists the provider syncToken; WeCom performs a complete
calendar snapshot and computes the materialized difference locally because the
schedule-list API does not expose an equivalent incremental cursor.
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=30
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.
GET /api/v1/identity/platform-access requires a valid configured proxy key on this endpoint independently of global development mode. It returns only the current identity's platform-access boolean and capability codes; it does not expose the administrator roster.
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.
Reliable decision evidence uses local Ed25519 only for development and isolated
UAT. Production must set CONTRACT_API_RELIABLE_EVIDENCE_SIGNING_BACKEND to
kms_gateway, mount the gateway service token and CA read-only, and select an
immutable asymmetric key version. Keep that signing key separate from the
Playbook credential-encryption key. Rotation is performed by registering a new
version and submitting a lifecycle change for approval by a different platform
administrator. Retirement preserves historical verification, while revocation
is irreversible. External audit credentials are issued, rotated, and revoked only
after approval by a different platform administrator; complete bearer values are
returned once after approval. P1-07.6 uses
CONTRACT_API_RELIABLE_EVIDENCE_PROBE_TARGETS_JSON for independent regional KMS
gateway probes and CONTRACT_API_RELIABLE_EVIDENCE_ANCHOR_TARGETS_JSON for external
immutable checkpoint witnesses. Staging and production fail the runtime
configuration gate when either list is empty. Witness credentials and public keys
are mounted read-only, and only receipt hashes, witness fingerprints, and external
references enter the operations ledger.
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
Persisted drafting continuation (TP06.24.2)
yuqei-drafting-continuation-worker is a separate polling process, not a thread
automatically started inside the API. CONTRACT_API_DRAFTING_WORKER_ENABLED is
false by default. After isolated deployment verification, an explicitly enabled
worker can reconnect persisted ordinary draft/semantic-review jobs using their
original idempotency keys, and continue an opted-in one-generation repair chain.
It never adopts a contract or retries a completed, failed, or cancelled model
execution. --once explicitly runs one bounded scan even when the daemon switch
is off; use it only against an intentionally selected environment.
Candidate leases and reconnect backoff live in the existing workspace JSON; this increment adds no database migration. Use distinct worker names for separate instances. Network reconnects have bounded exponential delays, not a final retry count; failed model executions retain their separate fixed attempt budgets. See the isolated continuation runbook.