Skip to content

ASK Core Service

Repo: ask-core-service-development
Language: Python ≥ 3.12
Framework: FastAPI + Uvicorn
Helm Chart: core-service v1.0.0
Port: 8000


Architecture

The Core Service is the central API gateway for the ASK platform. It handles user authentication (via Zitadel IAM), subscription/billing, API key management, notifications, and exposes the main REST API consumed by the Frontend and Assistant Service.

┌─────────────────────────────────────────────────────┐
│                  core-service (port 8000)            │
│                   uvicorn workers                    │
├──────────┬──────────────┬──────────────┬────────────┤
│ bulk-ops │  billing-    │    cron-     │  job-run   │
│ worker   │  metering-   │  scheduler-  │  worker    │
│          │  worker      │  worker      │            │
└──────────┴──────────────┴──────────────┴────────────┘
     │              │
     ▼              ▼
  PostgreSQL      Redis
  (external)    (external)

Container Images

Multi-Stage Build Pattern

All images use a two-stage build:

Stage Base Image Purpose
builder python:3.12 Install dependencies via uv sync, build venv
runtime python:3.12-slim Minimal runtime, copy venv from builder

The PROXY_PREFIX ARG allows routing base image pulls through a registry mirror.

Images Produced

Image Name Dockerfile Port Purpose
core-service Dockerfile 8000 Main FastAPI application
core-service-bulk-operations-worker Dockerfile.bulk_operations_worker Bulk data operation jobs
core-service-billing-metering-worker Dockerfile.billing_metering_worker Billing/metering async jobs
core-service-cron-scheduler-worker Dockerfile.cron_scheduler_worker Scheduled/cron job runner
core-service-job-run-worker Dockerfile.job_run_worker On-demand job execution

All images push to:

ai71uaenprodask71acr01.azurecr.io/core-service[:<suffix>]:<tag>

Build Arguments

ARG Default Description
PROXY_PREFIX "" Prefix prepended to base image names (e.g. registry-mirror.internal/)
GITLAB_USERNAME Username for private PyPI index authentication

Build secret required: gitlab_password (mounted via --secret id=gitlab_password).


Helm Chart

Chart: helm/Chart.yaml

name: core-service
version: "1.0.0"
appVersion: "0.0.1"

Chart Dependencies (Subcharts)

Subchart Version Source Condition
zitadel 1.0.1 (wraps upstream Zitadel v9.17.1) oci://registry.gitlab.com/ai71.ai/devops/devops-helm-charts zitadel.enabled

Zitadel provides the in-cluster IAM/OIDC service that core-service uses for machine-to-machine auth.

Default Resource Limits

resources:
  limits:
    memory: 768Mi
  requests:
    cpu: 300m
    memory: 500Mi

Health Probes

Probe Path Initial Delay Period
Liveness /api/v1/health/live 15s 15s
Readiness /api/v1/health/ready 20s 10s

Autoscaling

Setting Value
Min replicas 1
Max replicas 4
CPU target 80%

Environments

Environment File Environment Cloud/DC Notes
values-ai71-uaen-dev-ask71.yaml Development Azure UAE North Primary dev cluster
values-ai71-uaen-stg-ask71.yaml Staging Azure UAE North Pre-prod validation
values-ai71-mec1-stg-ask71.yaml MEC1 Staging Azure MEC1 Secondary staging
values-ai71-uaen-prod-mufti.yaml Production (Mufti) Azure UAE North Production tenant A
values-ai71-mec1-prod-mufti.yaml Production (Mufti MEC1) Azure MEC1 Production tenant A, MEC1
values-ai71-pp-auh1-prod-ask.yaml PP Production On-prem Abu Dhabi Gov cloud, air-gapped, see below

PP Environment — Core Service

Full PP environment details: PP Environment page

PP Image

registry.pp.gov.ae/ask/ask-core-service:<tag>

imagePullSecrets: harbor-registry-secret

PP Workers Enabled/Disabled

Worker PP Status Replicas
bulkOperationsWorker ✅ Enabled 3
billingMeteringWorker ❌ Disabled
cronSchedulerWorker ❌ Disabled
cronRunWorker ❌ Disabled

Billing and cron workers are disabled because the PP environment does not use Stripe or metered billing.

PP Non-Secret Configuration (TOML)

Config Key PP Value Notes
app.env ai71-pp-auh1-prod-ask Dynaconf env selector
database.host postgresql.ask.svc.cluster.local In-cluster Bitnami PostgreSQL
database.port 5432
database.name core-service
database.user core-service
iam_service.base_url http://core-service-zitadel.ask.svc.cluster.local:8080 In-cluster Zitadel gRPC
iam_service.public_base_url https://sso.ask.pp.gov.ae External SSO domain
iam_service.default_org_id 357511184963905565 PP tenant org
iam_service.session_lifetime 2592000s (30 days)
foundry.base_url http://litellm.foundry.svc.cluster.local:4000 In-cluster LiteLLM
foundry.default_tpm 5000000
foundry.default_rpm 500
storage.type azure Azure Blob for CDN static assets only
storage.azure.account_name ai71uaensask71sa03
storage.cdn_base_url https://cdn.ask.stg.ai71services.ai
redis.host assistant-service-redis-master.ask.svc.cluster.local In-cluster Bitnami Redis
redis.port 6379
redis.ssl true
redis.cluster_mode true
feature_flags.billing_enabled false No billing in PP
feature_flags.public_signup_enabled false Invite-only
public.core_services_base_url https://api.ask.pp.gov.ae/ask71/v2/svc
knowledge_management_service.base_url http://knowledge-management-service.ask.svc.cluster.local

PP Secrets (from Vault kv/data/ask/prod/core-service/environment-secrets)

Secret Key Description
DATABASE__PASSWORD PostgreSQL password
SECURITY__API_KEY_SALT API key salt
SECURITY__MASTER_ENCRYPTION_KEY Master encryption key
IAM_SERVICE__PAT Zitadel PAT
NOTIFICATIONS__MAILCHIMP_API_KEY Mailchimp key
STORAGE__ACCOUNT_KEY Azure Blob key (CDN only)
STORAGE__SAS_TOKEN Azure Blob SAS token
HATCHET__CLIENT_TOKEN Hatchet token
REDIS__PASSWORD Redis password
FOUNDRY__API_KEY LiteLLM API key
APP__CORE_SERVICES_MACHINE_TOKEN Internal machine token

PP Ingress

Host Path Rewrite
api.ask.pp.gov.ae /ask71/v2/svc/(.*) /$1
api.ask.pp.gov.ae /(.*) (catch-all) /$1

TLS: ask-pp-gov-ae-cert (private CA).

PP Zitadel Subchart

Zitadel v4.5.0 is deployed as a subchart with the following PP overrides:

Setting Value
zitadel.ExternalDomain sso.ask.pp.gov.ae
zitadel.ExternalSecure true
zitadel.TLS.Enabled false (TLS handled by F5/ingress)
Database host postgresql.ask.svc.cluster.local:5432
Database name zitadel
Login UI image tag v4.5.0
Login UI ingress path /ui/v2/login
masterkeySecretName zitadel-secret

core42 Environment — Core Service (ai71-modgpt-auh1-dev-ask)

core42 Images

Container core42 Registry Path
Main API harbor.cl1.sq4.aegis.internal/ask/core-service:<git-sha>
bulk-operations-worker harbor.cl1.sq4.aegis.internal/ask/core-service-bulk-operations-worker:<git-sha>
billing-metering-worker harbor.cl1.sq4.aegis.internal/ask/core-service-billing-metering-worker:<git-sha>
cron-scheduler-worker harbor.cl1.sq4.aegis.internal/ask/core-service-cron-scheduler-worker:<git-sha>
job-run-worker harbor.cl1.sq4.aegis.internal/ask/core-service-job-run-worker:<git-sha>

imagePullSecrets: harbor-pull-secret

core42 TOML Config Changes vs PP

Config Key PP Value core42 Value
app.env ai71-pp-auh1-prod-ask ai71-modgpt-auh1-dev-ask
storage.type azure s3 (Ceph RGW)
storage.azure.* Azure blob config Remove — replaced by S3
storage.s3.endpoint_url https://s3.mod.auh1.dev.dir (RGW VIP)
storage.s3.bucket_name core-service
storage.s3.region us-east-1
iam_service.public_base_url https://sso.ask.pp.gov.ae https://sso.cl1.sq4.aegis.internal
iam_service.default_org_id 357511184963905565 TBD — from Zitadel after setup
redis.ssl true false (in-cluster, no TLS)
public.core_services_base_url https://api.ask.pp.gov.ae/ask71/v2/svc https://api.cl1.sq4.aegis.internal/ask71/v2/svc
All other keys ✅ Same as PP

configTomlFileMountPath: /app/config/ai71-modgpt-auh1-dev-ask.toml

core42 Vault Secrets

Vault path: secret/cl1/core-service

Env Var Vault Key Description
STORAGE__S3__ACCESS_KEY_ID storage_s3_access_key_id Ceph RGW S3 access key
STORAGE__S3__SECRET_ACCESS_KEY storage_s3_secret_access_key Ceph RGW S3 secret key
IAM_SERVICE__PAT iam_service_pat Zitadel PAT
NOTIFICATIONS__MAILCHIMP_API_KEY notifications_mailchimp_api_key Mailchimp key
FOUNDRY__API_KEY foundry_api_key LiteLLM API key
HATCHET__CLIENT_TOKEN hatchet_client_token Hatchet token
REDIS__PASSWORD redis_password Redis password
DB_PASSWORD db_password PostgreSQL password

core42 Ingress

Host Path
api.cl1.sq4.aegis.internal /ask71/v2/svc/(.*)
api.cl1.sq4.aegis.internal /(.*) (catch-all)

core42 Zitadel Subchart

Setting core42 Value
zitadel.ExternalDomain sso.cl1.sq4.aegis.internal
zitadel.ExternalSecure true
zitadel.TLS.Enabled false
Database host postgresql.ask.svc.cluster.local:5432
Login UI ingress host sso.cl1.sq4.aegis.internal

Configuration Variables

Configuration uses Dynaconf with config/default.toml as the base. Environment-specific overrides are in config/override.toml (injected by Helm as a ConfigMap mount).

Non-Secret Config (representative, from dev values)

Variable Example (dev) Description
DATABASE__HOST ai71-uaen-dev-ask71-psql-01.postgres.database.azure.com PostgreSQL hostname
DATABASE__PORT 5432 PostgreSQL port
DATABASE__NAME core_service Database name
REDIS__HOST ai71-uaen-dev-ask71-amr-01.uaenorth.redis.azure.net Redis hostname
REDIS__PORT 6380 Redis port (TLS)
IAM_SERVICE__HOST zitadel.iam-service.svc.cluster.local Zitadel in-cluster host
IAM_SERVICE__PORT 8080 Zitadel gRPC port
FOUNDRY__BASE_URL https://foundry.core.uaen.ai71services.ai AI71 Foundry LLM proxy
STORAGE__ACCOUNT_NAME ai71uaendask71sa03 Azure storage account
STORAGE__CONTAINER_NAME $web Azure blob container
APP__ENV dev Dynaconf environment name

Secrets

Secrets are injected via Azure Key Vault + External Secrets Operator (ExternalSecret CRD). Key Vault secret names follow the pattern: {release-name}--{SECTION__KEY}.

Environment Variable Key Vault Key Suffix Description
DATABASE__PASSWORD DATABASE__PASSWORD PostgreSQL password
SECURITY__API_KEY_SALT SECURITY__API_KEY_SALT API key hashing salt
SECURITY__MASTER_ENCRYPTION_KEY SECURITY__MASTER_ENCRYPTION_KEY Master key for connector token encryption
IAM_SERVICE__PAT IAM_SERVICE__PAT Zitadel Personal Access Token (machine account)
APP__CORE_SERVICES_MACHINE_TOKEN APP__CORE_SERVICES_MACHINE_TOKEN Internal machine-to-machine auth token
NOTIFICATIONS__MAILCHIMP_API_KEY NOTIFICATIONS__MAILCHIMP_API_KEY Mailchimp transactional email API key
NOTIFICATIONS__SENDGRID_API_KEY NOTIFICATIONS__SENDGRID_API_KEY SendGrid API key
NOTIFICATIONS__SMTP_PASSWORD NOTIFICATIONS__SMTP_PASSWORD SMTP relay password
STORAGE__ACCOUNT_KEY STORAGE__ACCOUNT_KEY Azure Storage account key
STORAGE__SAS_TOKEN STORAGE__SAS_TOKEN Azure Blob SAS token
HATCHET__CLIENT_TOKEN HATCHET__CLIENT_TOKEN Hatchet job queue client token
BILLING_METERING__AUTUMN_API_KEY BILLING_METERING__AUTUMN_API_KEY Autumn billing API key
BILLING_METERING__BILLING_HATCHET_CLIENT_TOKEN BILLING_METERING__BILLING_HATCHET_CLIENT_TOKEN Hatchet token for billing worker
BILLING_METERING__SERVICE_API_KEY_SALT BILLING_METERING__SERVICE_API_KEY_SALT Billing service API key salt
BILLING_METERING__STRIPE_WEBHOOK_SECRET BILLING_METERING__STRIPE_WEBHOOK_SECRET Stripe webhook signing secret
REDIS__PASSWORD REDIS__PASSWORD Redis AUTH password
SENTRY__DSN SENTRY__DSN Sentry error tracking DSN
FOUNDRY__API_KEY FOUNDRY__API_KEY AI71 Foundry API key

ExternalSecret refresh interval: 1 minute. The secretAutoReloadOnUpdate: true Helm value triggers Stakater Reloader to roll pods when the secret changes.


Key Dependencies

Python Packages

Package Version Purpose
fastapi 0.135.2 HTTP framework
uvicorn 0.34 ASGI server
sqlalchemy 2.0.38 ORM (async)
asyncpg 0.31 Async PostgreSQL driver
psycopg2 2.9.10 Sync PostgreSQL driver
alembic 1.18.4 Database migrations
dynaconf 3.2.13 Configuration management
pydantic v2 Data validation
hatchet-sdk 1.32.0 Async job queue
iam-client 2.1.0 Zitadel IAM SDK (private)
foundry-client 0.1.2 AI71 Foundry SDK (private)
storage-lib 0.2.0 Azure/MinIO storage SDK (private)
stripe 8.0.0+ Stripe billing API
redis 7.4 Redis client
sentry-sdk 2.57 Error tracking
mailchimp-transactional 1.4.1 Email notifications
jinja2 3.1.6 Email template rendering
email-validator 2.0.0 Email address validation
phonenumbers 9.0.27 Phone number validation

Private GitLab PyPI Indexes

Index Name Package Provided
connectors-lib External connector integrations
iam-client Zitadel IAM SDK
logger-sdk Structured logging SDK
foundry-client AI71 Foundry LLM proxy SDK
storage-lib Azure Blob / MinIO abstraction

CI/CD Pipeline

File: .gitlab-ci.yml
Tool: GitLab CI

Stage Key Jobs Description
validate pre-commit, pytest, sonarcloud, keyvault-validation Code quality and tests
build docker-acr-build Build all 5 Docker images and push to ACR
helm-release helm-release, helm-release-oci-with-acr Publish chart to GitLab OCI and ACR

Key CI variables:

Variable Value
UV_VERSION 0.9.21
PYTHON_VERSION 3.12
CI base image ghcr.io/astral-sh/uv