_format_version: "1.1"

# Kong declarative config for local dev.
# Routes: /rest/ → postgrest, /auth/ → gotrue, /storage/ → storage-api,
#         /realtime/ → realtime, /functions/ → edge-runtime

services:
  - name: auth-v1
    url: http://auth:9999/
    routes:
      # /auth/v1/* catch-all. Brute-force protection for password attempts is
      # handled by Keycloak's native `bruteForceProtected` flag at the realm
      # level (see keycloak/realm-export.json) — Kong-level rate-limiting on
      # /auth/v1/token would interfere with legitimate PKCE code exchanges
      # during E2E runs, since the same endpoint handles both.
      - name: auth-v1-all
        strip_path: true
        paths:
          - /auth/v1/
    plugins:
      - name: cors

  - name: rest-v1
    url: http://rest:3000/
    routes:
      # Invitations POST — rate-limited per-auth-token: 20/hour.
      # (Using `limit_by: header` on Authorization gives us per-token quota
      # which is effectively per-session; the PKCE access token rotates every
      # hour so this doubles as a short-window leak protection.)
      - name: rest-v1-invitations
        strip_path: true
        methods:
          - POST
        paths:
          - /rest/v1/collective_invitations
        plugins:
          - name: rate-limiting
            config:
              hour: 20
              policy: local
              fault_tolerant: true
              limit_by: header
              header_name: Authorization
          # strip_path: true on the full table path sends "/" upstream, which
          # PostgREST rejects with PGRST117 "Unsupported HTTP method". Rewrite
          # the URI back to the table path so PostgREST routes it correctly.
          - name: request-transformer
            config:
              replace:
                uri: /collective_invitations
      - name: rest-v1-all
        strip_path: true
        paths:
          - /rest/v1/
    plugins:
      - name: cors
      - name: key-auth
        config:
          hide_credentials: false
      - name: acl
        config:
          hide_groups_header: true
          allow:
            - anon
            - service

  - name: graphql-v1
    url: http://rest:3000/rpc/graphql
    routes:
      - name: graphql-v1-all
        strip_path: true
        paths:
          - /graphql/v1
    plugins:
      - name: cors
      - name: key-auth
        config:
          hide_credentials: false
      - name: request-transformer
        config:
          add:
            headers:
              - Content-Profile:graphql_public

  - name: realtime-v1
    url: http://realtime:4000/socket
    routes:
      - name: realtime-v1-all
        strip_path: true
        paths:
          - /realtime/v1/
    plugins:
      - name: cors

  - name: storage-v1
    url: http://storage:5000/
    routes:
      - name: storage-v1-all
        strip_path: true
        paths:
          - /storage/v1/
    plugins:
      - name: cors

  - name: meta
    url: http://meta:8080/
    routes:
      - name: meta-all
        strip_path: true
        paths:
          - /pg/

consumers:
  - username: anon
    keyauth_credentials:
      - key: ${SUPABASE_ANON_KEY}
    acls:
      - group: anon

  - username: service_role
    keyauth_credentials:
      - key: ${SUPABASE_SERVICE_KEY}
    acls:
      - group: service
