livrare lot 2

This commit is contained in:
EVOTECH IT SRL 2026-07-10 03:39:53 -07:00
commit 8ecc78e729
763 changed files with 164593 additions and 0 deletions

View file

@ -0,0 +1,31 @@
# Kong 3.9 — the declarative config uses fields (ai_metrics, rate-limiting
# redis block) introduced after 3.4; the running gateway is 3.9.1.
FROM kong:3.9
# Switch to root to install curl and set permissions
USER root
# Install curl for configuration import
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
# Copy custom entrypoint and configuration.
# kong.yml is the JWT-enforcing declarative config (RS256 via Keycloak public
# keys + jwt plugin on every protected route). Baked to the path Kong reads by
# default so `docker run` of this image is SECURE BY DEFAULT — no reliance on a
# runtime volume mount. (The previous image baked a config with `consumers: []`
# and no jwt plugin; see kong.yml.insecure-legacy for that reference.)
COPY entrypoint.sh /entrypoint.sh
COPY declarative/kong.yml /kong/declarative/kong.yml
# DBless + point Kong at the baked config. A volume mount at the same path can
# still override this for environment-specific configs (cluster vs local).
ENV KONG_DATABASE=off
ENV KONG_DECLARATIVE_CONFIG=/kong/declarative/kong.yml
# Make entrypoint executable
RUN chmod +x /entrypoint.sh
# Switch back to kong user
USER kong
ENTRYPOINT ["/entrypoint.sh"]

View file

@ -0,0 +1,208 @@
# didiKong - Index
API Gateway pentru platforma DIDI. Toate requesturile externe trec prin Kong inainte sa ajunga la serviciile backend. Gestioneaza rutare, rate limiting, CORS, SSL si headere.
**Imagine**: didi-kong:latest (Kong 3.9.1)
**Container**: didi-kong (activ, pe masina de deployment)
**Mod**: DB-less declarativ (`KONG_DATABASE=off`)
**Porturi** (doar loopback `127.0.0.1`): 18000 (proxy HTTP -> container 8000), 18001 (admin API -> 8001), 18443 (proxy TLS -> 8443 ssl)
---
## Deployment: container local DB-less (activ)
Kong ruleaza ca un singur container `didi-kong` pe masina de deployment, in mod **DB-less** (`KONG_DATABASE=off`). Nu exista Kong Cluster, Control Plane, Data Planes sau HAProxy, si nu exista PostgreSQL pentru Kong.
- Config declarativa din `declarative/kong.yml.didi11-local`, montata in container la `/kong/declarative/kong.yml`.
- Porturile sunt legate exclusiv pe loopback (`127.0.0.1`): proxy `18000`, admin API `18001`, proxy TLS `18443`. Kong nu e expus public direct; traficul extern intra prin edge/tunel catre proxy-ul local.
- Single source of truth = fisierul declarativ `kong.yml.didi11-local`. Orice modificare de rute/plugin-uri se face in acest fisier + reload.
---
## Mod de operare: DB-less (declarativ)
Configuratia vine integral din fisierul `declarative/kong.yml.didi11-local`. Kong nu are baza de date proprie.
```
KONG_DATABASE=off
KONG_DECLARATIVE_CONFIG=/kong/declarative/kong.yml
```
Nu exista mod PostgreSQL / productie separata pentru Kong: acelasi fisier declarativ este sursa unica de adevar.
---
## Servicii inregistrate
Kong ruteaza catre 2 servicii backend (conform `kong.yml.didi11-local`):
| Serviciu | Target | Status |
|----------|--------|--------|
| didi-agent-v3 | http://didi-agent-v3:24803 | activ |
| didi-framework | http://didi-framework:3005 | activ |
Nota: rutele agent-v3 au timeout mare (660s = 11 min) pentru procesarea video.
---
## Rute definite
### Agent service (activ)
| Path | Metode | Destinatie |
|------|--------|------------|
| /agent/health | GET | agent-api |
| /agent/status | GET | agent-api |
| /api/pipelines | GET | agent-api |
| /api/analyze | POST | agent-api |
| /api/sessions | GET | agent-api |
| /api/upload | POST | agent-api |
| /api/abort | POST | agent-api |
| /api/v3/* | toate | agent-api (acopera si /api/v3/moderation/*) |
### didiFramework (config + HIL moderation)
| Path | Metode | Destinatie |
|------|--------|------------|
| /api/* | toate | didiFramework (acopera /api/moderation-config, /api/sensitive-topics, /api/moderation-roles) |
Nota: rutele de moderatie (HIL) calatoresc pe regulile generale `/api/v3/*` (agent-v3) si `/api/*` (didiFramework) — nu sunt necesare reguli Kong dedicate.
> Notă: serviciile Python legacy `orchestrator-api` și `analysis-api` (rute `/api/v1/catalog|pipelines|runs/*`,
> `/analysis/*`) NU mai există în config-ul local — au fost eliminate odată cu migrarea pe agent-v3. Config-ul
> `kong.yml.didi11-local` rutează exclusiv către `didi-agent-v3` și `didi-framework`.
### Admin dashboard
| Path | Metode | Destinatie |
|------|--------|------------|
| /admin | toate | admin-dashboard |
| /admin/api | toate | admin-dashboard |
---
## Plugin-uri globale
5 plugin-uri active pe toate rutele:
### 1. CORS
- Origins: localhost:3000, localhost:3001, localhost:8100, * (wildcard)
- Metode: GET, POST, PUT, DELETE, OPTIONS, PATCH
- Headere: Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, Authorization, X-Request-ID
- Exposed headers: X-Auth-Token, X-Request-ID
- Credentials: activat
- Max age: 3600s
- Preflight continue: nu
### 2. Rate Limiting
- 100 requests/minut per consumer
- 2000 requests/ora per consumer
- 10000 requests/zi per consumer
- Politica: local (fara state distribuit)
- Fault tolerant: da
### 3. Correlation ID (Request ID Tracking)
- Header: X-Request-ID
- Generator: UUID
- Echo downstream: da (returnat in raspuns)
### 4. Request Size Limiting
- Max payload: 100MB (pentru upload media)
- Require content-length: nu
### 5. Response Transformer
- Adauga: X-Gateway: DIDI-Kong, X-API-Version: 2.0
- Sterge: Server, Via (ascunde detalii interne)
---
## Upstreams (load balancing)
Config-ul local (`kong.yml.didi11-local`) NU definește upstream-uri — rutarea se face
direct către serviciile `didi-agent-v3:24803` și `didi-framework:3005`. Scalarea orizontală
a workerilor se face la nivel de agent-v3 (`scale-workers.sh`), nu prin upstream-uri Kong.
---
## SSL/TLS
- Certificat self-signed pentru <host-local>
- Locatie: certs/server.crt, certs/server.key
- Valabil: feb 2026 - feb 2027
- Emitent: DIDI, Bucharest, RO
- Servit pe proxy-ul TLS local `127.0.0.1:18443`
---
## Integrare Keycloak (LOCAL) + enforcement JWT (Modul 4 Gateway)
Kong valideaza token-urile emise de instanta Keycloak **locala** (`didi-keycloak`, port `28080`, servita sub `/auth`). Realm-urile locale sunt `didi-clients` (useri finali) si `didi-admins` (operatori). Issuer-ele locale au forma `http://localhost:28080/auth/realms/didi-clients` si `.../didi-admins`.
Enforcement-ul se face prin pluginul Kong `jwt` (nu OIDC/introspection): validare de semnatura **RS256** cu chei publice statice, `key_claim_name: iss` (Kong potriveste tokenul dupa claim-ul `iss` cu un `jwt_secret` inregistrat pe consumer).
Consumer: **`didi-keycloak-users`** — detine `jwt_secrets` (RS256, `rsa_public_key`) pentru toate issuer-ele acceptate, cheia fiind chiar valoarea `iss`:
- local: `http://localhost:28080/realms/didi-clients`, `http://localhost:28080/realms/didi-admins`
- plus issuer-ele externe/edge folosite in fata proxy-ului: `https://didi365.eu/auth/realms/{didi-clients,didi-admins}`, `https://<sso-extern>/realms/...`, `https://<sso-extern>/realms/...`, `https://<host-local>/auth/realms/...`, `https://10.11.10.11:{3001,8443}/auth/realms/...`
Pluginul `jwt` este activ pe **16 rute protejate** de pe cele doua servicii (`didi-agent-v3` si `didi-framework`), incluzand ruta **`/framework`** (route `didi-framework-direct`, jwt adaugat 2026-07-08). Rutele publice raman fara jwt (health/status, media public, verify-email, waitlist), iar rutele de extensie folosesc autentificare separata prin `X-API-Key` + rate-limiting.
JWT validation flow:
1. Clientul (SPA/extensie) obtine token JWT de la Keycloak local (`/auth/realms/didi-clients` sau `/auth/realms/didi-admins`).
2. Trimite request cu `Authorization: Bearer {token}`.
3. Kong potriveste `iss` cu `jwt_secret`-ul consumer-ului `didi-keycloak-users` si valideaza semnatura RS256; token invalid/lipsa -> `401`.
4. Daca valid, ruteaza requestul catre serviciul backend local (`didi-agent-v3:24803` / `didi-framework`).
5. Serviciul backend decodeaza tokenul pentru `user_id`/`email`/`realm_access.roles` (fara re-validare — Kong a validat deja).
---
## Configurare performanta
```
KONG_NGINX_WORKER_PROCESSES=auto
KONG_MEM_CACHE_SIZE=256m
KONG_NGINX_PROXY_PROXY_BUFFER_SIZE=128k
KONG_NGINX_PROXY_PROXY_BUFFERS=4 256k
KONG_NGINX_PROXY_PROXY_BUSY_BUFFERS_SIZE=256k
KONG_NGINX_HTTP_LARGE_CLIENT_HEADER_BUFFERS=4 64k
```
Buffer-urile mari sunt necesare pentru headerele JWT de la Keycloak (token-urile pot fi foarte mari).
---
## Fisiere
```
Dockerfile -- Imagine didi-kong (Kong 3.9), instaleaza curl, entrypoint
entrypoint.sh -- Pornire Kong DB-less + wait for ready + log servicii
declarative/
kong.yml.didi11-local -- Configurare declarativa activa (single source of truth, montata la /kong/declarative/kong.yml)
certs/
server.crt -- Certificat SSL self-signed
server.key -- Cheie privata SSL
```
Zero cod custom. Zero plugin-uri Lua custom. Doar configurare declarativa si certificat SSL.
---
## Health check
```
kong health (interval 30s, timeout 10s, retries 3, start period 60s)
```
---
## Consumers
Configuratia declarativa defineste un singur consumer Kong: **`didi-keycloak-users`** (username + custom_id `didi-keycloak-users`), care detine `jwt_secrets`-urile RS256 pentru toate issuer-ele Keycloak locale/edge acceptate (vezi sectiunea Integrare Keycloak). Acest consumer este cel pe care pluginul `jwt` il rezolva la validarea tokenului.
Limitele per-tier (free/paid/enterprise) provin din atributele de grup Keycloak (realm-urile locale `didi-clients` / `didi-admins`) si sunt disponibile in claim-urile JWT pentru rate limiting; rutele de extensie au propriul rate-limiting per `X-API-Key` (30/min).
## Recent Changes
- **2026-07-08 — jwt pe `/framework`**: pluginul `jwt` (RS256, `key_claim_name: iss`) adaugat pe ruta `didi-framework-direct` (path `/framework`). Enforcement JWT acum activ pe 16 rute protejate pe `didi-agent-v3` + `didi-framework`.
- **jwt_secrets pentru issuer-ele locale** pe consumer `didi-keycloak-users`: `http://localhost:28080/realms/didi-clients` + `.../didi-admins`, alaturi de issuer-ele edge (`didi365.eu/auth`, `<sso-extern>`, `<sso-extern>`, `<host-local>/auth`, `10.11.10.11:{3001,8443}/auth`) pentru realm-urile `didi-clients` si `didi-admins`.
- **Rute de extensie** (`didi-agent-extension-analyze`, `-async`, `-status`, `-upload`): autentificare `X-API-Key` + `rate-limiting` 30/min + `request-transformer`; CORS extins cu origins `chrome-extension://[a-z]+`, `moz-extension://[a-z0-9-]+` + header `X-API-Key`.
- **Single source of truth** = `declarative/kong.yml.didi11-local` (DB-less). Fara cluster, fara decK sync.

View file

@ -0,0 +1,121 @@
# Kong — migrat pe cluster shared (2026-04-28)
> **TL;DR**: containerul local `didi-kong` nu mai rulează. Tot traficul public DIDI trece prin clusterul Kong shared extern: `HAProxy 10.11.10.175``Kong DP1/DP2 (10.11.10.177/178)`. Configurația DIDI declarativă e în `declarative/kong-cluster.yml`.
---
## Ce era aici (înainte de 2026-04-28)
`didi-kong` — un container Kong 3.4.2 standalone (`image: didi-kong:latest`) definit în `backend/production/docker-compose.yml`. Mod Postgres (DB pe clusterul Patroni). Servea singur tot traficul `didi365.eu`. Avea 16 servicii + 35 rute + 5 plugin-uri globale + 1 consumer JWT.
## Ce e acum
Tot traficul DIDI a fost migrat pe **Kong cluster extern** (același folosit de `lege365`, `rafai`, `biddie`, `notify`, `firme`).
| Component cluster | IP:Port | Rol |
|---|---|---|
| HAProxy LB | `10.11.10.175:443` | edge → DP, terminare TLS pentru DIDI |
| Kong CP (Control Plane) | `10.11.10.176:8001` | configurare via Admin API (DB-attached) |
| Kong DP1 | `10.11.10.177:8000/8443` | proxy trafic |
| Kong DP2 | `10.11.10.178:8000/8443` | proxy trafic |
Cluster Kong rulează versiunea 3.14.0.1 în mod Hybrid CP/DP, cu DB Postgres pe clusterul Patroni.
## Servicii DIDI consolidate pe cluster (4)
| Service cluster | Tag | Upstream | Routes |
|---|---|---|---|
| `didi-agent-v3` | `product:didi,env:prod,kind:api` | `10.11.10.12:24803` | 16 (15 API + 1 prefix /agent-v3) |
| `didi-framework` | `product:didi,env:prod,kind:api` | `10.11.10.12:3005` | 6 |
| `didi-keycloak` | `product:didi,env:prod,kind:auth` | `10.11.10.12:28000` | 2 |
> `didi-admin` NU e migrat — accesibil intern via VPN, păstrează Docker network DNS.
Toate rutele matchează pe `Host: didi365.eu, www.didi365.eu, <host-local>`.
## Servicii droppate complet
- `analysis-api`, `orchestrator-api` (legacy, 0 routes)
- `agent-v3`, `keycloak` (alias-uri orfane)
- `minio-storage` (deja în cluster MinIO 4-node, vezi `didiStorage/MIGRATION.md`)
- `pgadmin`, `redis-commander`, `rabbitmq-management`, `minio-console` (tooling în dispariție)
## Configurația declarativă
```
declarative/
├── kong-cluster.yml ← config-ul curent al DIDI pe cluster (sursa de adevăr)
├── kong-local-backup.yml ← snapshot complet al Kong-ului local înainte de migrare
└── kong.yml ← config-ul declarativ legacy (DB-less staging)
```
Apply / sync:
```bash
docker run --rm --network host -v $(pwd)/declarative:/cfg kong/deck:latest \
gateway sync /cfg/kong-cluster.yml --kong-addr http://10.11.10.176:8001
```
Validare fără modificări:
```bash
docker run --rm --network host -v $(pwd)/declarative:/cfg kong/deck:latest \
gateway diff /cfg/kong-cluster.yml --kong-addr http://10.11.10.176:8001
```
## Edge nginx (Contabo)
Edge nginx pe Contabo (`213.136.83.198`, `/srv/edge-nginx/conf.d/didi365.conf`) a fost actualizat să trimită `/auth/`, `/api/`, `/agent-v3/` la `https://10.11.10.175` (în loc de `https://<host-local>` care era kong local). Backup: `didi365.conf.bak.pre-kong-cluster-20260428`.
## Admin nginx
`backend/admin-dashboard/nginx-ssl.conf``location /api/` proxy_pass schimbat de la `https://kong:8443` (Docker DNS local) la `https://10.11.10.175` cu `Host: didi365.eu` overridden. Restul (`/auth/`, `/agent-v3/`, `/framework/`) bypass-ează Kong, merg direct la backend.
## Cum verifici că merge prin cluster
Răspunsurile prin cluster Kong au header-ul `X-Gateway: DIDI-Kong-Cluster`. Răspunsurile (vechile) prin Kong local aveau `X-Gateway: DIDI-Kong-Staging`.
```bash
curl -sI https://didi365.eu/auth/realms/didi-clients | grep -i x-gateway
# expect: x-gateway: DIDI-Kong-Cluster
```
## Rollback (dacă apar probleme)
Kong local nu mai există ca container, dar imaginea `didi-kong:latest` e intactă local. Pași rollback:
1. **Restore docker-compose**: revert commitul care a scos `kong:` din `production/docker-compose.yml`
2. **Repornește kong**: `cd backend/production && docker compose up -d kong`
3. **Rollback edge Contabo**:
```
cp /srv/edge-nginx/conf.d/didi365.conf.bak.pre-kong-cluster-20260428 \
/srv/edge-nginx/conf.d/didi365.conf
nginx -s reload
```
4. **Rollback admin nginx**: revert commit-ul nginx-ssl.conf, rebuild `didi-admin:latest`
DB-ul Kong-ului local (`KONG_PG_DATABASE`) era pe clusterul Patroni — datele sunt încă acolo (nu s-au șters).
## Lecții importante (capcane confirmate)
1. **decK default `protocols: [https]` rupe HAProxy passthrough.** Cluster Kong returna `426 Please use HTTPS` deși edge termina TLS. HAProxy LB forwardează HTTP intern la DP — Kong vede HTTP. Fix: `_info.defaults.route.protocols: [http, https]`.
2. **Port binding upstream.** Original `didi-agent-v3` era `127.0.0.1:24803` și `didi-framework` deloc expus. Modificat în docker-compose la `10.11.10.12:24803`/`3005` ca DPs cluster să ajungă (LAN VLAN 10).
3. **strip_path nu e uniform.** Match local: `/agent/health`, `/auth`, `/framework`, `/agent-v3` au `strip_path: true`. Restul `false`. Verifică înainte să copiezi.
4. **Host header obligatoriu.** Cluster shared filtrează rute pe Host. Edge nginx și admin nginx fac `proxy_set_header Host didi365.eu`. Fără asta — 404.
5. **JWT plugin per-rută.** Cluster shared, alți tenanți nu vor JWT didi-clients. Plugin aplicat explicit pe 13 rute.
## Linkuri rapide
- Cluster Admin API: `http://10.11.10.176:8001`
- Cluster ghid onboarding: `landingzone/kong-api/README.md` (repo `git.finesynergy.eu/lucian/landingzone`)
- Documentație decK: <https://docs.konghq.com/deck/>
## Status
- ✅ Migrare aplicată: 2026-04-28
- ✅ Kong local oprit și șters din docker-compose
- ✅ Edge nginx Contabo actualizat
- ✅ Admin nginx actualizat
- ⏳ Soak 24-48h în desfășurare; eliminarea volumelor Kong după validare

View file

@ -0,0 +1,537 @@
_format_version: "3.0"
_info:
select_tags:
- product:didi
- env:prod
defaults:
route:
# Routes accept both HTTP and HTTPS (matches cluster pattern for lege365/rafai/etc).
# HAProxy LB terminates TLS at edge, forwards HTTP to Kong DP — Kong must accept HTTP
# internally or it returns 426 "Please use HTTPS protocol".
protocols: [http, https]
# ============================================================
# DIDI tenant configuration for shared Kong cluster
# Cluster CP: 10.11.10.176:8001 | DP1: 10.11.10.177 | DP2: 10.11.10.178 | LB: 10.11.10.175
# Hosts: didi365.eu (public) + www.didi365.eu + localhost (internal alias)
# Upstreams: 10.11.10.12 (DIDI host) on exposed ports
# Plugins are applied per-service (NOT global) — cluster shared with lege365/rafai/biddie/notify
# ============================================================
# ============================================================
# CONSUMERS — JWT issuers preserved from local Kong (Keycloak realm didi-clients)
# ============================================================
consumers:
- username: didi-keycloak-users
custom_id: didi-keycloak-users
tags: [product:didi, env:prod]
jwt_secrets:
- algorithm: RS256
key: https://localhost/auth/realms/didi-clients
secret: 1qG51hpfTte1TGQzcAhKWjVkXsMWNIun
rsa_public_key: |-
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlpv0lfjAFPGV4hLK6jp6
EsVlxax2nPA9I2IzGwNUIK8AsKwC9qu+737jarsjewx3ya/0s1uDP0ilbdh+wEzW
Do/8jjWd0DxgTxMxCTS7DU07UZKXJWGc/Z+ansUPUcjqJ+uLTdu331z7ajK2FIZF
7yYH2WgjzApF6YSMx/dqybp/bdmBrvsPDGv1EJK4a72jV3P86WCW4ZDax2Qayw1t
iKnO3+o6xvyoVSMeVJbs9ArjpAldueMLfTZqYBSmWe/rlBSIMWYkKTSgS+pdakez
G71qs2RcSkI+GxlfJw0DJA8TfSjol6zc+EIUtAYG0pwwAqPB2PvkxMoDbL2UDkZE
/wIDAQAB
-----END PUBLIC KEY-----
- algorithm: RS256
key: https://didi365.eu/auth/realms/didi-clients
secret: IS8AJNbvC3taNROALc4bHslsZnSKELQD
rsa_public_key: |
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlpv0lfjAFPGV4hLK6jp6
EsVlxax2nPA9I2IzGwNUIK8AsKwC9qu+737jarsjewx3ya/0s1uDP0ilbdh+wEzW
Do/8jjWd0DxgTxMxCTS7DU07UZKXJWGc/Z+ansUPUcjqJ+uLTdu331z7ajK2FIZF
7yYH2WgjzApF6YSMx/dqybp/bdmBrvsPDGv1EJK4a72jV3P86WCW4ZDax2Qayw1t
iKnO3+o6xvyoVSMeVJbs9ArjpAldueMLfTZqYBSmWe/rlBSIMWYkKTSgS+pdakez
G71qs2RcSkI+GxlfJw0DJA8TfSjol6zc+EIUtAYG0pwwAqPB2PvkxMoDbL2UDkZE
/wIDAQAB
-----END PUBLIC KEY-----
# SSO cluster (sso.local) — added 2026-04-29 after migration la Keycloak SSO public.
# Same RSA public key (realm exported/imported from local with key preserved).
- algorithm: RS256
key: https://sso.local/realms/didi-clients
secret: lEyVoR2eXLgWmQQ5q6fZRbCkVJhSaTuB
rsa_public_key: |-
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlpv0lfjAFPGV4hLK6jp6
EsVlxax2nPA9I2IzGwNUIK8AsKwC9qu+737jarsjewx3ya/0s1uDP0ilbdh+wEzW
Do/8jjWd0DxgTxMxCTS7DU07UZKXJWGc/Z+ansUPUcjqJ+uLTdu331z7ajK2FIZF
7yYH2WgjzApF6YSMx/dqybp/bdmBrvsPDGv1EJK4a72jV3P86WCW4ZDax2Qayw1t
iKnO3+o6xvyoVSMeVJbs9ArjpAldueMLfTZqYBSmWe/rlBSIMWYkKTSgS+pdakez
G71qs2RcSkI+GxlfJw0DJA8TfSjol6zc+EIUtAYG0pwwAqPB2PvkxMoDbL2UDkZE
/wIDAQAB
-----END PUBLIC KEY-----
# Internal SSO host (used during transition; also kept for proxy fallback paths)
- algorithm: RS256
key: https://sso-admin.local/realms/didi-clients
secret: kPwQjA4nFsUzMxRyV8tDeBcGhJlOvIuS
rsa_public_key: |-
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlpv0lfjAFPGV4hLK6jp6
EsVlxax2nPA9I2IzGwNUIK8AsKwC9qu+737jarsjewx3ya/0s1uDP0ilbdh+wEzW
Do/8jjWd0DxgTxMxCTS7DU07UZKXJWGc/Z+ansUPUcjqJ+uLTdu331z7ajK2FIZF
7yYH2WgjzApF6YSMx/dqybp/bdmBrvsPDGv1EJK4a72jV3P86WCW4ZDax2Qayw1t
iKnO3+o6xvyoVSMeVJbs9ArjpAldueMLfTZqYBSmWe/rlBSIMWYkKTSgS+pdakez
G71qs2RcSkI+GxlfJw0DJA8TfSjol6zc+EIUtAYG0pwwAqPB2PvkxMoDbL2UDkZE
/wIDAQAB
-----END PUBLIC KEY-----
# didi-admins realm — admin-dashboard SPA auth (added 2026-05-04)
# Different RSA key than didi-clients (separate realm).
- algorithm: RS256
key: https://didi365.eu/auth/realms/didi-admins
secret: aDmInS001PuBlIcEdge2026May04PaSsKonGvErY
rsa_public_key: |-
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkcx2UE88P4j4XzWQ/bsd
0C69xZuxo/VXvhyKPj/t7u6ILIpD3/KL0sI0Ei4ZOlfjZ8PHmmEhWVwOYRCyhxgN
aq5EMk4MKmUJ0KZd6pixvufKp8ddnI/xKdUROLbdzEHSxP251uHUUCYzpsKYisZ7
t6UidWgDBDrcU42YsV4OggvPlvemtQKFawv0CpQ7BLhyTm2WUD4iq7H17OEI975i
ocC7Zqrk9itl2o0w8x9fSMOyMgsEafkVQ/KIuZA1/kKugtpG9eyYE49RFH7iQZd9
KmQow/XDxtKHfaLi1CEU4X2fHCThMWKdRQeK8N1n6qS+yanygcYJlUf8FKybgRxZ
NwIDAQAB
-----END PUBLIC KEY-----
- algorithm: RS256
key: https://sso.local/realms/didi-admins
secret: aDmInS002SsOcLuStEr2026May04PaSsKonGvErY
rsa_public_key: |-
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkcx2UE88P4j4XzWQ/bsd
0C69xZuxo/VXvhyKPj/t7u6ILIpD3/KL0sI0Ei4ZOlfjZ8PHmmEhWVwOYRCyhxgN
aq5EMk4MKmUJ0KZd6pixvufKp8ddnI/xKdUROLbdzEHSxP251uHUUCYzpsKYisZ7
t6UidWgDBDrcU42YsV4OggvPlvemtQKFawv0CpQ7BLhyTm2WUD4iq7H17OEI975i
ocC7Zqrk9itl2o0w8x9fSMOyMgsEafkVQ/KIuZA1/kKugtpG9eyYE49RFH7iQZd9
KmQow/XDxtKHfaLi1CEU4X2fHCThMWKdRQeK8N1n6qS+yanygcYJlUf8FKybgRxZ
NwIDAQAB
-----END PUBLIC KEY-----
- algorithm: RS256
key: https://sso-admin.local/realms/didi-admins
secret: aDmInS003LoCaLcLuStEr2026May04PaSsKonGv
rsa_public_key: |-
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkcx2UE88P4j4XzWQ/bsd
0C69xZuxo/VXvhyKPj/t7u6ILIpD3/KL0sI0Ei4ZOlfjZ8PHmmEhWVwOYRCyhxgN
aq5EMk4MKmUJ0KZd6pixvufKp8ddnI/xKdUROLbdzEHSxP251uHUUCYzpsKYisZ7
t6UidWgDBDrcU42YsV4OggvPlvemtQKFawv0CpQ7BLhyTm2WUD4iq7H17OEI975i
ocC7Zqrk9itl2o0w8x9fSMOyMgsEafkVQ/KIuZA1/kKugtpG9eyYE49RFH7iQZd9
KmQow/XDxtKHfaLi1CEU4X2fHCThMWKdRQeK8N1n6qS+yanygcYJlUf8FKybgRxZ
NwIDAQAB
-----END PUBLIC KEY-----
- algorithm: RS256
key: https://localhost/auth/realms/didi-admins
secret: aDmInS004DiDi11LoCaL2026May04PaSsKonGvE
rsa_public_key: |-
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkcx2UE88P4j4XzWQ/bsd
0C69xZuxo/VXvhyKPj/t7u6ILIpD3/KL0sI0Ei4ZOlfjZ8PHmmEhWVwOYRCyhxgN
aq5EMk4MKmUJ0KZd6pixvufKp8ddnI/xKdUROLbdzEHSxP251uHUUCYzpsKYisZ7
t6UidWgDBDrcU42YsV4OggvPlvemtQKFawv0CpQ7BLhyTm2WUD4iq7H17OEI975i
ocC7Zqrk9itl2o0w8x9fSMOyMgsEafkVQ/KIuZA1/kKugtpG9eyYE49RFH7iQZd9
KmQow/XDxtKHfaLi1CEU4X2fHCThMWKdRQeK8N1n6qS+yanygcYJlUf8FKybgRxZ
NwIDAQAB
-----END PUBLIC KEY-----
# ============================================================
# SERVICES (4 consolidated from 9 local) + ROUTES + PER-SERVICE PLUGINS
# ============================================================
services:
# ----------------------------------------------------------
# SERVICE 1: didi-agent-v3 (was: agent-api + agent-v3 + agent-v3-api)
# ----------------------------------------------------------
- name: didi-agent-v3
protocol: http
host: 10.11.10.12
port: 24803
retries: 5
connect_timeout: 60000
write_timeout: 660000
read_timeout: 660000
tags: [product:didi, env:prod, kind:api]
plugins:
- name: cors
tags: [product:didi, env:prod]
config:
# chrome-extension://* and moz-extension://* required for browser extension API
origins: [https://didi365.eu, https://www.didi365.eu, "chrome-extension://[a-z]+", "moz-extension://[a-z0-9-]+"]
methods: [GET, POST, PUT, DELETE, OPTIONS, PATCH]
# X-API-Key header required for extension auth
headers: [Accept, Authorization, Content-Type, X-Request-ID, X-API-Key]
exposed_headers: [X-Request-ID]
credentials: true
max_age: 3600
preflight_continue: false
- name: request-size-limiting
tags: [product:didi, env:prod]
config:
allowed_payload_size: 104857600
size_unit: bytes
require_content_length: false
- name: response-transformer
tags: [product:didi, env:prod]
config:
add:
headers: ["X-Gateway:DIDI-Kong-Cluster", "X-API-Version:2.0"]
remove:
headers: [Server, Via]
- name: correlation-id
tags: [product:didi, env:prod]
config:
header_name: X-Request-ID
generator: uuid
echo_downstream: true
routes:
# JWT-protected endpoints
- name: didi-agent-abort
paths: [/api/abort]
methods: [POST, OPTIONS]
hosts: &didi-hosts [didi365.eu, www.didi365.eu, localhost]
strip_path: false
preserve_host: true
tags: [product:didi, env:prod]
plugins:
- name: jwt
config: &jwt-config
key_claim_name: iss
claims_to_verify: [exp]
header_names: [authorization]
uri_param_names: [jwt]
run_on_preflight: true
secret_is_base64: false
maximum_expiration: 0
- name: didi-agent-admin-services
paths: [/api/v1/admin/services]
methods: [GET, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod]
plugins:
- name: jwt
config: *jwt-config
- name: didi-agent-analysis
paths: [/api/analysis]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod]
plugins:
- name: jwt
config: *jwt-config
- name: didi-agent-analyze
paths: [/api/analyze]
methods: [POST, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod]
plugins:
- name: jwt
config: *jwt-config
- name: didi-agent-jobs
paths: [/api/v1/jobs]
methods: [GET, POST, DELETE, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod]
plugins:
- name: jwt
config: *jwt-config
- name: didi-agent-pipelines
paths: [/api/pipelines]
methods: [GET, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod]
plugins:
- name: jwt
config: *jwt-config
- name: didi-agent-progress
paths: [/api/progress]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod]
plugins:
- name: jwt
config: *jwt-config
- name: didi-agent-sessions
paths: [/api/sessions]
methods: [GET, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod]
plugins:
- name: jwt
config: *jwt-config
- name: didi-agent-storage
paths: [/api/storage]
methods: [GET, POST, DELETE, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod]
plugins:
- name: jwt
config: *jwt-config
- name: didi-agent-subscriptions-v1
# Legacy v1 endpoint on agent-v3 (current v2 is on framework-api)
paths: [/api/v1/subscriptions]
methods: [GET, POST, DELETE, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod, legacy:v1]
plugins:
- name: jwt
config: *jwt-config
- name: didi-agent-upload
paths: [/api/upload]
methods: [POST, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod]
plugins:
- name: jwt
config: *jwt-config
# Public endpoints (no JWT)
- name: didi-agent-health
# Local had strip_path=true: /agent/health -> "/" on agent-v3 (root, returns 200)
paths: [/agent/health]
methods: [GET, OPTIONS]
hosts: *didi-hosts
strip_path: true
preserve_host: true
tags: [product:didi, env:prod, public:true]
- name: didi-agent-status
paths: [/api/status]
methods: [GET, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod, public:true]
- name: didi-agent-media-public
# Public media playback proxy (range-supported, served by agent-v3 itself)
paths: [/api/v3/media/file]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod, public:true]
- name: didi-agent-v3-prefix
# Edge nginx forwards /agent-v3/* here. Local Kong stripped the prefix
# (e.g. /agent-v3/api/v3/health -> /api/v3/health on agent-v3).
# Local had JWT plugin on this route — preserved here to match security model.
paths: [/agent-v3]
hosts: *didi-hosts
strip_path: true
preserve_host: true
tags: [product:didi, env:prod]
plugins:
- name: jwt
config: *jwt-config
# Browser extension API endpoints — NO JWT (X-API-Key validated in agent-v3).
# All four routes share the same request-transformer pattern + rate-limit.
# Regex paths (~ prefix) with `$` anchor prevent /analyze matching /analyze-async.
- name: didi-agent-extension-analyze
# Sync analyze (legacy — small text only, hits Cloudflare 100s timeout otherwise)
paths: [~/agent-v3/api/v3/pipeline/extension/analyze$]
methods: [POST, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod, public:true, auth:api-key]
plugins:
- name: request-transformer
config:
replace:
uri: /api/v3/pipeline/extension/analyze
- name: rate-limiting
config: &ext-rate-limit
minute: 30
hour: 500
policy: local
limit_by: header
header_name: X-API-Key
fault_tolerant: true
hide_client_headers: false
error_code: 429
error_message: "API rate limit exceeded"
- name: didi-agent-extension-analyze-async
# Async dispatch — returns 202 + session_id (used by extension for all flows)
paths: [~/agent-v3/api/v3/pipeline/extension/analyze-async$]
methods: [POST, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod, public:true, auth:api-key]
plugins:
- name: request-transformer
config:
replace:
uri: /api/v3/pipeline/extension/analyze-async
- name: rate-limiting
config: *ext-rate-limit
- name: didi-agent-extension-upload
# Multipart media upload (screenshot/video) — multer expects "file" field
paths: [~/agent-v3/api/v3/pipeline/extension/upload$]
methods: [POST, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod, public:true, auth:api-key]
plugins:
- name: request-transformer
config:
replace:
uri: /api/v3/pipeline/extension/upload
- name: rate-limiting
config: *ext-rate-limit
- name: didi-agent-extension-status
# Polling endpoint with sessionId capture — rewrite preserves the UUID
paths: ['~/agent-v3/api/v3/pipeline/extension/status/(?<sid>[\w-]+)$']
methods: [GET, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod, public:true, auth:api-key]
plugins:
- name: request-transformer
config:
replace:
uri: /api/v3/pipeline/extension/status/$(uri_captures.sid)
- name: rate-limiting
config:
# Polling can hit this every 2s — bump per-minute limit
minute: 120
hour: 2000
policy: local
limit_by: header
header_name: X-API-Key
fault_tolerant: true
hide_client_headers: false
error_code: 429
error_message: "Polling rate limit exceeded"
# ----------------------------------------------------------
# SERVICE 2: didi-framework (was: framework-api + didi-framework)
# ----------------------------------------------------------
- name: didi-framework
protocol: http
host: 10.11.10.12
port: 3005
retries: 5
connect_timeout: 60000
write_timeout: 60000
read_timeout: 60000
tags: [product:didi, env:prod, kind:api]
plugins:
- name: cors
tags: [product:didi, env:prod]
config:
origins: [https://didi365.eu, https://www.didi365.eu]
methods: [GET, POST, PUT, DELETE, OPTIONS, PATCH]
headers: [Accept, Authorization, Content-Type, X-Request-ID]
exposed_headers: [X-Request-ID]
credentials: true
max_age: 3600
preflight_continue: false
- name: request-size-limiting
tags: [product:didi, env:prod]
config:
allowed_payload_size: 104857600
size_unit: bytes
require_content_length: false
- name: response-transformer
tags: [product:didi, env:prod]
config:
add:
headers: ["X-Gateway:DIDI-Kong-Cluster", "X-API-Version:2.0"]
remove:
headers: [Server, Via]
- name: correlation-id
tags: [product:didi, env:prod]
config:
header_name: X-Request-ID
generator: uuid
echo_downstream: true
routes:
- name: didi-framework-auth
paths: [/api/auth]
methods: [GET, POST, PUT, DELETE, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod]
plugins:
- name: jwt
config: *jwt-config
- name: didi-framework-auth-verify-email
# PUBLIC route — must beat /api/auth (JWT) on priority
paths: [/api/auth/verify-email]
methods: [GET, POST]
hosts: *didi-hosts
strip_path: false
preserve_host: true
regex_priority: 100
tags: [product:didi, env:prod, public:true]
- name: didi-framework-history
paths: [/api/history]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod]
plugins:
- name: jwt
config: *jwt-config
- name: didi-framework-subscriptions
# Current /api/subscriptions endpoint (v2). Legacy /api/v1/subscriptions is on agent-v3.
paths: [/api/subscriptions]
methods: [GET, POST, DELETE, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod]
plugins:
- name: jwt
config: *jwt-config
- name: didi-framework-waitlist
# PUBLIC waitlist signup. Local Kong had this duplicated (one with JWT, one without).
# Keeping no-JWT version — public signup is correct behavior.
paths: [/api/waitlist]
methods: [GET, POST, DELETE, OPTIONS]
hosts: *didi-hosts
strip_path: false
preserve_host: true
tags: [product:didi, env:prod, public:true]
- name: didi-framework-direct
# Legacy /framework prefix — local had strip_path=true so /framework/api/X -> /api/X on framework
paths: [/framework]
hosts: *didi-hosts
strip_path: true
preserve_host: true
tags: [product:didi, env:prod]
# ----------------------------------------------------------
# NOTE: didi-admin NOT migrated — internal-only (VPN access to 10.11.10.12 directly).
# Will be revisited after admin nginx is replaced with simpler setup.
# ----------------------------------------------------------
# ----------------------------------------------------------
# NOTE: didi-keycloak service REMOVED 2026-04-29.
# DIDI now uses the external SSO cluster (https://sso.local/realms/didi-clients) directly
# — SPA goes browser→sso.local, no proxy through cluster Kong needed.
# JWT consumer didi-keycloak-users still validates tokens for SSO issuer.
# ----------------------------------------------------------

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,392 @@
_format_version: "3.0"
_transform: true
# Service definitions for new architecture
services:
# Agent Service (NEW - replaces orchestration layer)
- name: agent-api
url: http://didi-agent:18789
retries: 3
connect_timeout: 120000
write_timeout: 660000
read_timeout: 660000
tags:
- agent
- analysis
# Legacy: Orchestrator API Service (to be removed after migration)
- name: orchestrator-api
url: http://orchestrationLayer-orchestrator:8000
retries: 5
connect_timeout: 60000
write_timeout: 60000
read_timeout: 60000
tags:
- orchestrator
- legacy
# Legacy: Analysis Service (to be removed after migration)
- name: analysis-api
url: http://orchestrationLayer-analysis:8004
retries: 3
connect_timeout: 120000
write_timeout: 120000
read_timeout: 120000
tags:
- analysis
- legacy
# didiAI Platform Gateway (external) - disabled, configure via DIDIAI_GATEWAY_URL env var
# - name: didiai-platform
# url: ${DIDIAI_GATEWAY_URL}
# retries: 3
# connect_timeout: 60000
# write_timeout: 60000
# read_timeout: 60000
# tags:
# - didiai
# - external
# Admin Dashboard
- name: admin-dashboard
url: http://didi-admin:80
retries: 3
connect_timeout: 30000
write_timeout: 30000
read_timeout: 30000
tags:
- ui
- dashboard
# Routes
routes:
# ============================================
# Agent Service Routes (NEW)
# ============================================
# Agent Health Check
- name: agent-health
service: agent-api
paths:
- /agent/health
strip_path: true
methods:
- GET
# Agent Status (detailed)
- name: agent-status
service: agent-api
paths:
- /agent/status
strip_path: false
methods:
- GET
# Agent Pipelines List
- name: agent-pipelines
service: agent-api
paths:
- /api/pipelines
strip_path: false
methods:
- GET
# Agent Analysis (non-streaming)
- name: agent-analyze
service: agent-api
paths:
- /api/analyze
strip_path: false
methods:
- POST
# Agent Session Status
- name: agent-sessions
service: agent-api
paths:
- /api/sessions
strip_path: false
methods:
- GET
# Agent File Upload
- name: agent-upload
service: agent-api
paths:
- /api/upload
strip_path: false
methods:
- POST
# Agent Abort Session
- name: agent-abort
service: agent-api
paths:
- /api/abort
strip_path: false
methods:
- POST
# ============================================
# Legacy Orchestrator Routes (to be removed)
# ============================================
# Orchestrator Routes
- name: orchestrator-catalog
service: orchestrator-api
paths:
- /api/v1/catalog
strip_path: false
methods:
- GET
- POST
- PUT
- DELETE
- name: orchestrator-pipelines
service: orchestrator-api
paths:
- /api/v1/pipelines
strip_path: false
methods:
- GET
- POST
- PUT
- DELETE
- PATCH
- name: orchestrator-runs
service: orchestrator-api
paths:
- /api/v1/runs
strip_path: false
methods:
- GET
- POST
- name: orchestrator-health
service: orchestrator-api
paths:
- /orchestrator/health
strip_path: true
methods:
- GET
# Analysis Service Routes
- name: analysis-health
service: analysis-api
paths:
- /analysis/health
strip_path: true
methods:
- GET
- name: analysis-stats
service: analysis-api
paths:
- /analysis/stats
strip_path: true
methods:
- GET
# didiAI Platform Routes (proxied) - disabled, enable when DIDIAI_GATEWAY_URL is configured
# - name: didiai-extractors
# service: didiai-platform
# paths:
# - /didiai/extractors
# strip_path: true
# methods:
# - POST
# - GET
#
# - name: didiai-models
# service: didiai-platform
# paths:
# - /didiai/models
# strip_path: true
# methods:
# - POST
# - GET
#
# - name: didiai-discovery
# service: didiai-platform
# paths:
# - /didiai/discovery
# strip_path: true
# methods:
# - GET
# Admin Dashboard Routes
- name: admin-ui
service: admin-dashboard
paths:
- /admin
strip_path: false
preserve_host: true
- name: admin-api
service: admin-dashboard
paths:
- /admin/api
strip_path: false
# Global Plugins
plugins:
# CORS Configuration
- name: cors
config:
origins:
- "http://localhost:3000"
- "http://localhost:3001"
- "http://localhost:8100"
- "*"
methods:
- GET
- POST
- PUT
- DELETE
- OPTIONS
- PATCH
headers:
- Accept
- Accept-Version
- Content-Length
- Content-MD5
- Content-Type
- Date
- Authorization
- X-Request-ID
exposed_headers:
- X-Auth-Token
- X-Request-ID
credentials: true
max_age: 3600
preflight_continue: false
# Rate Limiting (Global)
- name: rate-limiting
config:
minute: 100
hour: 2000
day: 10000
policy: local
fault_tolerant: true
hide_client_headers: false
limit_by: consumer
# Request ID Tracking
- name: correlation-id
config:
header_name: X-Request-ID
generator: uuid
echo_downstream: true
# Request Size Limiting (100MB for media files)
- name: request-size-limiting
config:
allowed_payload_size: 104857600
size_unit: bytes
require_content_length: false
# Response Headers
- name: response-transformer
config:
add:
headers:
- X-Gateway:DIDI-Kong
- X-API-Version:2.0
remove:
headers:
- Server
- Via
# Consumers for future authentication (consumer_groups not supported in Kong 3.4)
consumers: []
# Upstreams for load balancing (prepared for scaling)
upstreams:
# Agent Service Upstream (NEW)
- name: agent-upstream
algorithm: round-robin
slots: 10000
healthchecks:
active:
concurrency: 5
healthy:
http_statuses:
- 200
interval: 10
successes: 2
http_path: /health
timeout: 10
type: http
unhealthy:
http_failures: 3
http_statuses:
- 429
- 500
- 503
interval: 10
tcp_failures: 3
timeouts: 3
targets:
- target: didi-agent:18789
weight: 100
tags:
- agent
# Legacy: Orchestrator Upstream
- name: orchestrator-upstream
algorithm: round-robin
slots: 10000
healthchecks:
active:
concurrency: 10
healthy:
http_statuses:
- 200
- 302
interval: 5
successes: 3
http_path: /health
timeout: 5
type: http
unhealthy:
http_failures: 3
http_statuses:
- 429
- 500
- 503
interval: 5
tcp_failures: 3
timeouts: 3
targets:
- target: orchestrationLayer-orchestrator:8000
weight: 100
tags:
- orchestrator
- legacy
- name: analysis-upstream
algorithm: least-connections
slots: 10000
healthchecks:
active:
concurrency: 5
healthy:
http_statuses:
- 200
interval: 10
successes: 2
http_path: /health
timeout: 10
type: http
unhealthy:
http_failures: 5
interval: 10
timeouts: 5
targets:
- target: orchestrationLayer-analysis:8004
weight: 100
tags:
- analysis

View file

@ -0,0 +1,21 @@
#!/bin/bash
# Start Kong in the background
/docker-entrypoint.sh kong docker-start &
KONG_PID=$!
# Wait for Kong to be ready
echo "Waiting for Kong to start..."
until kong health; do
sleep 2
done
echo "Kong is ready!"
echo "Configuration should already be imported by migrations container."
# Check current services count
SERVICE_COUNT=$(curl -s http://localhost:8001/services 2>/dev/null | grep -o '"id"' | wc -l)
echo "Current services in Kong: $SERVICE_COUNT"
# Keep Kong running in foreground
wait $KONG_PID