apiVersion: v1
kind: Namespace
metadata:
  name: platform-infra
  labels:
    app.kubernetes.io/name: platform-infra
    app.kubernetes.io/managed-by: unidesk
    unidesk.ai/runtime-node: G14
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-all
  namespace: platform-infra
  labels:
    app.kubernetes.io/name: platform-infra
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - {}
  egress:
    - {}
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: sub2api-config
  namespace: platform-infra
  labels:
    app.kubernetes.io/name: sub2api
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
data:
  AUTO_SETUP: "true"
  SERVER_HOST: "0.0.0.0"
  SERVER_PORT: "8080"
  SERVER_MODE: "release"
  RUN_MODE: "standard"
  DATABASE_HOST: "sub2api-postgres"
  DATABASE_PORT: "5432"
  DATABASE_USER: "sub2api"
  DATABASE_DBNAME: "sub2api"
  DATABASE_SSLMODE: "disable"
  DATABASE_MAX_OPEN_CONNS: "10"
  DATABASE_MAX_IDLE_CONNS: "2"
  DATABASE_CONN_MAX_LIFETIME_MINUTES: "30"
  DATABASE_CONN_MAX_IDLE_TIME_MINUTES: "5"
  REDIS_HOST: "sub2api-redis"
  REDIS_PORT: "6379"
  REDIS_PASSWORD: ""
  REDIS_DB: "0"
  REDIS_POOL_SIZE: "32"
  REDIS_MIN_IDLE_CONNS: "2"
  REDIS_ENABLE_TLS: "false"
  ADMIN_EMAIL: "admin@sub2api.platform-infra.local"
  JWT_EXPIRE_HOUR: "24"
  TZ: "Asia/Shanghai"
  SECURITY_URL_ALLOWLIST_ENABLED: "__SUB2API_SECURITY_URL_ALLOWLIST_ENABLED__"
  SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP: "__SUB2API_SECURITY_URL_ALLOWLIST_ALLOW_INSECURE_HTTP__"
  SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS: "__SUB2API_SECURITY_URL_ALLOWLIST_ALLOW_PRIVATE_HOSTS__"
  SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS: "__SUB2API_SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS__"
  UPDATE_PROXY_URL: ""
  GATEWAY_OPENAI_RESPONSE_HEADER_TIMEOUT: "0"
  GATEWAY_OPENAI_HTTP2_ENABLED: "true"
  GATEWAY_OPENAI_HTTP2_ALLOW_PROXY_FALLBACK_TO_HTTP1: "true"
  GATEWAY_OPENAI_HTTP2_FALLBACK_ERROR_THRESHOLD: "2"
  GATEWAY_OPENAI_HTTP2_FALLBACK_WINDOW_SECONDS: "60"
  GATEWAY_OPENAI_HTTP2_FALLBACK_TTL_SECONDS: "600"
  GATEWAY_IMAGE_STREAM_DATA_INTERVAL_TIMEOUT: "900"
  GATEWAY_IMAGE_STREAM_KEEPALIVE_INTERVAL: "10"
  GATEWAY_IMAGE_CONCURRENCY_ENABLED: "false"
  GATEWAY_IMAGE_CONCURRENCY_MAX_CONCURRENT_REQUESTS: "0"
  GATEWAY_IMAGE_CONCURRENCY_OVERFLOW_MODE: "reject"
  GATEWAY_IMAGE_CONCURRENCY_WAIT_TIMEOUT_SECONDS: "30"
  GATEWAY_IMAGE_CONCURRENCY_MAX_WAITING_REQUESTS: "100"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sub2api-data
  namespace: platform-infra
  labels:
    app.kubernetes.io/name: sub2api
    app.kubernetes.io/component: app
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: local-path
  resources:
    requests:
      storage: 2Gi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sub2api-redis-data
  namespace: platform-infra
  labels:
    app.kubernetes.io/name: sub2api-redis
    app.kubernetes.io/component: redis
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: local-path
  resources:
    requests:
      storage: 2Gi
---
apiVersion: v1
kind: Service
metadata:
  name: sub2api-postgres
  namespace: platform-infra
  labels:
    app.kubernetes.io/name: sub2api-postgres
    app.kubernetes.io/component: postgres
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
spec:
  selector:
    app.kubernetes.io/name: sub2api-postgres
    app.kubernetes.io/component: postgres
  ports:
    - name: postgres
      port: 5432
      targetPort: postgres
---
apiVersion: v1
kind: Service
metadata:
  name: sub2api-redis
  namespace: platform-infra
  labels:
    app.kubernetes.io/name: sub2api-redis
    app.kubernetes.io/component: redis
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
spec:
  selector:
    app.kubernetes.io/name: sub2api-redis
    app.kubernetes.io/component: redis
  ports:
    - name: redis
      port: 6379
      targetPort: redis
---
apiVersion: v1
kind: Service
metadata:
  name: sub2api
  namespace: platform-infra
  labels:
    app.kubernetes.io/name: sub2api
    app.kubernetes.io/component: app
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
spec:
  selector:
    app.kubernetes.io/name: sub2api
    app.kubernetes.io/component: app
  ports:
    - name: http
      port: 8080
      targetPort: http
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: sub2api-postgres
  namespace: platform-infra
  labels:
    app.kubernetes.io/name: sub2api-postgres
    app.kubernetes.io/component: postgres
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
spec:
  serviceName: sub2api-postgres
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: sub2api-postgres
      app.kubernetes.io/component: postgres
  template:
    metadata:
      labels:
        app.kubernetes.io/name: sub2api-postgres
        app.kubernetes.io/component: postgres
        app.kubernetes.io/part-of: platform-infra
    spec:
      securityContext:
        fsGroup: 70
      containers:
        - name: postgres
          image: postgres:18-alpine
          imagePullPolicy: IfNotPresent
          ports:
            - name: postgres
              containerPort: 5432
          env:
            - name: POSTGRES_USER
              value: sub2api
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: sub2api-secrets
                  key: POSTGRES_PASSWORD
            - name: POSTGRES_DB
              value: sub2api
            - name: PGDATA
              value: /var/lib/postgresql/data
            - name: TZ
              value: Asia/Shanghai
          readinessProbe:
            exec:
              command:
                - sh
                - -c
                - pg_isready -U sub2api -d sub2api -h 127.0.0.1
            initialDelaySeconds: 5
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 6
          livenessProbe:
            exec:
              command:
                - sh
                - -c
                - pg_isready -U sub2api -d sub2api -h 127.0.0.1
            initialDelaySeconds: 30
            periodSeconds: 20
            timeoutSeconds: 5
            failureThreshold: 6
          volumeMounts:
            - name: postgres-data
              mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
    - metadata:
        name: postgres-data
        labels:
          app.kubernetes.io/name: sub2api-postgres
          app.kubernetes.io/component: postgres
          app.kubernetes.io/part-of: platform-infra
          app.kubernetes.io/managed-by: unidesk
      spec:
        accessModes:
          - ReadWriteOnce
        storageClassName: local-path
        resources:
          requests:
            storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sub2api-redis
  namespace: platform-infra
  labels:
    app.kubernetes.io/name: sub2api-redis
    app.kubernetes.io/component: redis
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app.kubernetes.io/name: sub2api-redis
      app.kubernetes.io/component: redis
  template:
    metadata:
      labels:
        app.kubernetes.io/name: sub2api-redis
        app.kubernetes.io/component: redis
        app.kubernetes.io/part-of: platform-infra
    spec:
      securityContext:
        fsGroup: 999
      containers:
        - name: redis
          image: redis:8-alpine
          imagePullPolicy: IfNotPresent
          command:
            - sh
            - -c
          args:
            - redis-server --save 60 1 --appendonly yes --appendfsync everysec
          ports:
            - name: redis
              containerPort: 6379
          env:
            - name: TZ
              value: Asia/Shanghai
          readinessProbe:
            exec:
              command:
                - redis-cli
                - ping
            initialDelaySeconds: 5
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 6
          livenessProbe:
            exec:
              command:
                - redis-cli
                - ping
            initialDelaySeconds: 30
            periodSeconds: 20
            timeoutSeconds: 5
            failureThreshold: 6
          volumeMounts:
            - name: redis-data
              mountPath: /data
      volumes:
        - name: redis-data
          persistentVolumeClaim:
            claimName: sub2api-redis-data
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: sub2api
  namespace: platform-infra
  labels:
    app.kubernetes.io/name: sub2api
    app.kubernetes.io/component: app
    app.kubernetes.io/part-of: platform-infra
    app.kubernetes.io/managed-by: unidesk
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app.kubernetes.io/name: sub2api
      app.kubernetes.io/component: app
  template:
    metadata:
      annotations:
        unidesk.ai/sub2api-config-hash: "__SUB2API_CONFIG_HASH__"
      labels:
        app.kubernetes.io/name: sub2api
        app.kubernetes.io/component: app
        app.kubernetes.io/part-of: platform-infra
    spec:
      securityContext:
        fsGroup: 1000
      initContainers:
        - name: wait-postgres
          image: postgres:18-alpine
          imagePullPolicy: IfNotPresent
          command:
            - sh
            - -c
            - until pg_isready -h sub2api-postgres -U sub2api -d sub2api; do sleep 2; done
        - name: wait-redis
          image: redis:8-alpine
          imagePullPolicy: IfNotPresent
          command:
            - sh
            - -c
            - until redis-cli -h sub2api-redis ping | grep -q PONG; do sleep 2; done
      containers:
        - name: sub2api
          image: __SUB2API_IMAGE__
          imagePullPolicy: __SUB2API_IMAGE_PULL_POLICY__
          ports:
            - name: http
              containerPort: 8080
          envFrom:
            - configMapRef:
                name: sub2api-config
          env:
            - name: DATABASE_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: sub2api-secrets
                  key: POSTGRES_PASSWORD
            - name: ADMIN_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: sub2api-secrets
                  key: ADMIN_PASSWORD
            - name: JWT_SECRET
              valueFrom:
                secretKeyRef:
                  name: sub2api-secrets
                  key: JWT_SECRET
            - name: TOTP_ENCRYPTION_KEY
              valueFrom:
                secretKeyRef:
                  name: sub2api-secrets
                  key: TOTP_ENCRYPTION_KEY
          readinessProbe:
            httpGet:
              path: /health
              port: http
            initialDelaySeconds: 10
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 6
          livenessProbe:
            httpGet:
              path: /health
              port: http
            initialDelaySeconds: 30
            periodSeconds: 20
            timeoutSeconds: 5
            failureThreshold: 6
          startupProbe:
            httpGet:
              path: /health
              port: http
            periodSeconds: 10
            timeoutSeconds: 5
            failureThreshold: 30
          volumeMounts:
            - name: sub2api-data
              mountPath: /app/data
      volumes:
        - name: sub2api-data
          persistentVolumeClaim:
            claimName: sub2api-data
