# ============================================================
# OmniCommerce Cloud — Kubernetes Base (Kustomize)
# ============================================================

---
# Namespace
apiVersion: v1
kind: Namespace
metadata:
  name: omnicommerce
  labels:
    app.kubernetes.io/part-of: omnicommerce
    istio-injection: enabled

---
# ============================================================
# CONFIGMAPS
# ============================================================

apiVersion: v1
kind: ConfigMap
metadata:
  name: omnicommerce-config
  namespace: omnicommerce
data:
  ENVIRONMENT: "production"
  LOG_LEVEL: "info"
  TZ: "UTC"
  DATABASE_NAME: "omnicommerce"
  DATABASE_MAX_CONNS: "80"
  DATABASE_MIN_CONNS: "10"
  DATABASE_MAX_IDLE_TIME: "30m"
  REDIS_CLUSTER_MODE: "false"
  KAFKA_BROKERS: "kafka.omnicommerce.svc.cluster.local:9092"
  KAFKA_CONSUMER_GROUP: "omnicommerce-consumers"
  ELASTICSEARCH_URL: "https://elasticsearch.omnicommerce.svc.cluster.local:9200"
  MINIO_ENDPOINT: "minio.omnicommerce.svc.cluster.local:9000"
  MINIO_USE_SSL: "true"
  JWT_EXPIRY: "24h"
  JWT_REFRESH_EXPIRY: "30d"
  CORS_ALLOWED_ORIGINS: "https://*.omnicommerce.io,https://*.omnicommerce.com"

---
# Backend ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: backend-config
  namespace: omnicommerce
data:
  config.yaml: |
    server:
      port: 8080
      read_timeout: 30s
      write_timeout: 30s
      max_header_bytes: 1048576
    database:
      max_open_conns: 80
      max_idle_conns: 10
      conn_max_lifetime: 30m
    redis:
      pool_size: 20
      min_idle_conns: 5
      dial_timeout: 5s
      read_timeout: 3s
      write_timeout: 3s
    kafka:
      session_timeout: 30s
      heartbeat_interval: 3s
      max_poll_records: 100
    elasticsearch:
      max_retries: 3
      healthcheck_interval: 30s
    auth:
      password_min_length: 8
      password_hash_cost: 12
      mfa_issuer: "OmniCommerce"
    rate_limiter:
      requests_per_second: 100
      burst: 200
    upload:
      max_file_size: 104857600
      allowed_types: ["image/jpeg","image/png","image/webp","application/pdf"]
    notifications:
      email_retry_max: 3
      sms_retry_max: 2
      push_retry_max: 5

---
# Nginx ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-config
  namespace: omnicommerce
data:
  nginx.conf: |
    user nginx;
    worker_processes auto;
    worker_rlimit_nofile 65535;
    error_log /var/log/nginx/error.log warn;
    pid /var/run/nginx.pid;

    events {
      worker_connections 4096;
      use epoll;
      multi_accept on;
    }

    http {
      include /etc/nginx/mime.types;
      default_type application/octet-stream;
      charset utf-8;
      sendfile on;
      tcp_nopush on;
      tcp_nodelay on;
      keepalive_timeout 65;
      types_hash_max_size 2048;
      server_tokens off;

      # Gzip
      gzip on;
      gzip_vary on;
      gzip_proxied any;
      gzip_comp_level 6;
      gzip_types text/plain text/css text/xml text/javascript application/json application/javascript application/xml+rss application/atom+xml image/svg+xml;

      # Rate limiting
      limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/s;
      limit_req_zone $binary_remote_addr zone=login_limit:10m rate=5r/s;
      limit_conn_zone $binary_remote_addr zone=conn_limit:10m;

      # Upstreams
      upstream backend {
        server backend.omnicommerce.svc.cluster.local:8080 max_fails=3 fail_timeout=30s;
        keepalive 32;
      }

      upstream web {
        server web.omnicommerce.svc.cluster.local:3000;
        keepalive 32;
      }

      upstream admin {
        server admin.omnicommerce.svc.cluster.local:3001;
        keepalive 16;
      }

      upstream vendor {
        server vendor-dashboard.omnicommerce.svc.cluster.local:3002;
        keepalive 16;
      }

      include /etc/nginx/conf.d/*.conf;
    }

---
# ============================================================
# SECRETS (Placeholder — use External Secrets Operator or Sealed Secrets)
# ============================================================

apiVersion: v1
kind: Secret
metadata:
  name: omnicommerce-secrets
  namespace: omnicommerce
type: Opaque
stringData:
  DATABASE_PASSWORD: "PLACEHOLDER_CHANGE_ME"
  DATABASE_URL: "postgres://omni:PLACEHOLDER_CHANGE_ME@postgres.omnicommerce.svc.cluster.local:5432/omnicommerce?sslmode=require"
  REDIS_PASSWORD: "PLACEHOLDER_CHANGE_ME"
  REDIS_URL: "redis://:PLACEHOLDER_CHANGE_ME@redis.omnicommerce.svc.cluster.local:6379/0"
  JWT_SECRET: "PLACEHOLDER_CHANGE_ME_AT_LEAST_64_CHARS"
  STRIPE_SECRET_KEY: "PLACEHOLDER_CHANGE_ME"
  STRIPE_WEBHOOK_SECRET: "PLACEHOLDER_CHANGE_ME"
  ELASTIC_PASSWORD: "PLACEHOLDER_CHANGE_ME"
  MINIO_ROOT_PASSWORD: "PLACEHOLDER_CHANGE_ME"
  SMTP_PASSWORD: "PLACEHOLDER_CHANGE_ME"
  SENTRY_DSN: ""

---
# ============================================================
# PostgreSQL StatefulSet
# ============================================================

apiVersion: v1
kind: Service
metadata:
  name: postgres
  namespace: omnicommerce
  labels:
    app: postgres
spec:
  type: ClusterIP
  clusterIP: None
  ports:
    - port: 5432
      targetPort: 5432
      name: postgres
  selector:
    app: postgres
---
apiVersion: v1
kind: Service
metadata:
  name: postgres-read
  namespace: omnicommerce
  labels:
    app: postgres
spec:
  type: ClusterIP
  ports:
    - port: 5432
      targetPort: 5432
      name: postgres
  selector:
    app: postgres
    role: replica
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
  namespace: omnicommerce
spec:
  serviceName: postgres
  replicas: 3
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchLabels:
                  app: postgres
              topologyKey: kubernetes.io/hostname
      containers:
        - name: postgres
          image: postgres:16.3-alpine
          ports:
            - containerPort: 5432
          env:
            - name: POSTGRES_DB
              valueFrom:
                configMapKeyRef:
                  name: omnicommerce-config
                  key: DATABASE_NAME
            - name: POSTGRES_USER
              value: "omni"
            - name: POSTGRES_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: omnicommerce-secrets
                  key: DATABASE_PASSWORD
            - name: PGDATA
              value: /var/lib/postgresql/data/pgdata
          resources:
            requests:
              cpu: "2"
              memory: "4Gi"
            limits:
              cpu: "4"
              memory: "8Gi"
          volumeMounts:
            - name: postgres-data
              mountPath: /var/lib/postgresql/data
          livenessProbe:
            exec:
              command: ["pg_isready", "-U", "omni"]
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            exec:
              command: ["pg_isready", "-U", "omni", "-d", "omnicommerce"]
            initialDelaySeconds: 5
            periodSeconds: 5
  volumeClaimTemplates:
    - metadata:
        name: postgres-data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: "ssd"
        resources:
          requests:
            storage: 500Gi

---
# ============================================================
# Redis StatefulSet
# ============================================================

apiVersion: v1
kind: Service
metadata:
  name: redis
  namespace: omnicommerce
spec:
  type: ClusterIP
  clusterIP: None
  ports:
    - port: 6379
      targetPort: 6379
  selector:
    app: redis
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis
  namespace: omnicommerce
spec:
  serviceName: redis
  replicas: 3
  selector:
    matchLabels:
      app: redis
  template:
    metadata:
      labels:
        app: redis
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchLabels:
                  app: redis
              topologyKey: kubernetes.io/hostname
      containers:
        - name: redis
          image: redis:7.2-alpine
          command: ["redis-server"]
          args:
            - "--appendonly"
            - "yes"
            - "--maxmemory"
            - "4gb"
            - "--maxmemory-policy"
            - "allkeys-lru"
            - "--requirepass"
            - "$(REDIS_PASSWORD)"
            - "--cluster-enabled"
            - "yes"
            - "--cluster-config-file"
            - "/data/nodes.conf"
            - "--cluster-node-timeout"
            - "5000"
          ports:
            - containerPort: 6379
              name: client
            - containerPort: 16379
              name: gossip
          env:
            - name: REDIS_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: omnicommerce-secrets
                  key: REDIS_PASSWORD
          resources:
            requests:
              cpu: "500m"
              memory: "2Gi"
            limits:
              cpu: "2"
              memory: "6Gi"
          volumeMounts:
            - name: redis-data
              mountPath: /data
          livenessProbe:
            exec:
              command: ["redis-cli", "--no-auth-warning", "-a", "$(REDIS_PASSWORD)", "ping"]
            initialDelaySeconds: 30
            periodSeconds: 10
          readinessProbe:
            exec:
              command: ["redis-cli", "--no-auth-warning", "-a", "$(REDIS_PASSWORD)", "ping"]
            initialDelaySeconds: 5
            periodSeconds: 5
  volumeClaimTemplates:
    - metadata:
        name: redis-data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: "ssd"
        resources:
          requests:
            storage: 100Gi

---
# ============================================================
# Elasticsearch StatefulSet
# ============================================================

apiVersion: v1
kind: Service
metadata:
  name: elasticsearch
  namespace: omnicommerce
spec:
  ports:
    - port: 9200
      name: http
    - port: 9300
      name: transport
  selector:
    app: elasticsearch
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: elasticsearch
  namespace: omnicommerce
spec:
  serviceName: elasticsearch
  replicas: 3
  selector:
    matchLabels:
      app: elasticsearch
  template:
    metadata:
      labels:
        app: elasticsearch
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchLabels:
                  app: elasticsearch
              topologyKey: kubernetes.io/hostname
      initContainers:
        - name: fix-permissions
          image: busybox:1.36
          command: ["sh", "-c", "chown -R 1000:1000 /usr/share/elasticsearch/data"]
          securityContext:
            privileged: true
          volumeMounts:
            - name: es-data
              mountPath: /usr/share/elasticsearch/data
        - name: increase-vm-max-map
          image: busybox:1.36
          command: ["sysctl", "-w", "vm.max_map_count=262144"]
          securityContext:
            privileged: true
      containers:
        - name: elasticsearch
          image: docker.elastic.co/elasticsearch/elasticsearch:8.13.0
          ports:
            - containerPort: 9200
              name: http
            - containerPort: 9300
              name: transport
          env:
            - name: node.name
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: cluster.name
              value: "omnicommerce"
            - name: discovery.seed_hosts
              value: "elasticsearch-0.elasticsearch,elasticsearch-1.elasticsearch,elasticsearch-2.elasticsearch"
            - name: cluster.initial_master_nodes
              value: "elasticsearch-0,elasticsearch-1,elasticsearch-2"
            - name: ES_JAVA_OPTS
              value: "-Xms4g -Xmx4g"
            - name: xpack.security.enabled
              value: "false"
          resources:
            requests:
              cpu: "2"
              memory: "6Gi"
            limits:
              cpu: "4"
              memory: "10Gi"
          volumeMounts:
            - name: es-data
              mountPath: /usr/share/elasticsearch/data
  volumeClaimTemplates:
    - metadata:
        name: es-data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: "ssd"
        resources:
          requests:
            storage: 500Gi

---
# ============================================================
# Kafka + Zookeeper
# ============================================================

apiVersion: v1
kind: Service
metadata:
  name: zookeeper
  namespace: omnicommerce
spec:
  ports:
    - port: 2181
      name: client
  selector:
    app: zookeeper
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: zookeeper
  namespace: omnicommerce
spec:
  replicas: 3
  selector:
    matchLabels:
      app: zookeeper
  template:
    metadata:
      labels:
        app: zookeeper
    spec:
      containers:
        - name: zookeeper
          image: confluentinc/cp-zookeeper:7.6.0
          ports:
            - containerPort: 2181
          env:
            - name: ZOOKEEPER_CLIENT_PORT
              value: "2181"
            - name: ZOOKEEPER_TICK_TIME
              value: "2000"
          resources:
            requests:
              cpu: "250m"
              memory: "512Mi"
            limits:
              cpu: "1"
              memory: "1Gi"
          volumeMounts:
            - name: zk-data
              mountPath: /var/lib/zookeeper/data
      volumes:
        - name: zk-data
          emptyDir:
            sizeLimit: 10Gi

---
apiVersion: v1
kind: Service
metadata:
  name: kafka
  namespace: omnicommerce
spec:
  ports:
    - port: 9092
      name: plaintext
  selector:
    app: kafka
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: kafka
  namespace: omnicommerce
spec:
  serviceName: kafka
  replicas: 3
  selector:
    matchLabels:
      app: kafka
  template:
    metadata:
      labels:
        app: kafka
    spec:
      containers:
        - name: kafka
          image: confluentinc/cp-kafka:7.6.0
          ports:
            - containerPort: 9092
          env:
            - name: KAFKA_BROKER_ID
              valueFrom:
                fieldRef:
                  fieldPath: metadata.name
            - name: KAFKA_ZOOKEEPER_CONNECT
              value: "zookeeper:2181"
            - name: KAFKA_LISTENERS
              value: "PLAINTEXT://:9092"
            - name: KAFKA_ADVERTISED_LISTENERS
              value: "PLAINTEXT://$(POD_NAME).kafka.omnicommerce.svc.cluster.local:9092"
            - name: KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR
              value: "3"
            - name: KAFKA_NUM_PARTITIONS
              value: "12"
          resources:
            requests:
              cpu: "1"
              memory: "2Gi"
            limits:
              cpu: "4"
              memory: "6Gi"
          volumeMounts:
            - name: kafka-data
              mountPath: /var/lib/kafka/data
  volumeClaimTemplates:
    - metadata:
        name: kafka-data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: "ssd"
        resources:
          requests:
            storage: 200Gi

---
# ============================================================
# MinIO
# ============================================================

apiVersion: v1
kind: Service
metadata:
  name: minio
  namespace: omnicommerce
spec:
  ports:
    - port: 9000
      name: api
    - port: 9001
      name: console
  selector:
    app: minio
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: minio
  namespace: omnicommerce
spec:
  serviceName: minio
  replicas: 4
  selector:
    matchLabels:
      app: minio
  template:
    metadata:
      labels:
        app: minio
    spec:
      containers:
        - name: minio
          image: minio/minio:RELEASE.2024-06-06T09-36-42Z
          args:
            - "server"
            - "--console-address"
            - ":9001"
            - "http://minio-{0...3}.minio.omnicommerce.svc.cluster.local/data"
          ports:
            - containerPort: 9000
            - containerPort: 9001
          env:
            - name: MINIO_ROOT_USER
              valueFrom:
                configMapKeyRef:
                  name: omnicommerce-config
                  key: MINIO_ROOT_USER
            - name: MINIO_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: omnicommerce-secrets
                  key: MINIO_ROOT_PASSWORD
          volumeMounts:
            - name: minio-data
              mountPath: /data
  volumeClaimTemplates:
    - metadata:
        name: minio-data
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: "ssd"
        resources:
          requests:
            storage: 1Ti

---
# ============================================================
# BACKEND (Go API) — Deployment + HPA
# ============================================================

apiVersion: v1
kind: Service
metadata:
  name: backend
  namespace: omnicommerce
spec:
  type: ClusterIP
  ports:
    - port: 8080
      targetPort: 8080
      name: http
  selector:
    app: backend
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend
  namespace: omnicommerce
  labels:
    app: backend
    version: v1
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2
      maxUnavailable: 0
  selector:
    matchLabels:
      app: backend
  template:
    metadata:
      labels:
        app: backend
        version: v1
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "8080"
        prometheus.io/path: "/metrics"
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchLabels:
                    app: backend
                topologyKey: kubernetes.io/hostname
      serviceAccountName: omnicommerce-backend
      containers:
        - name: backend
          image: registry.omnicommerce.io/omnicommerce-api:latest
          imagePullPolicy: Always
          ports:
            - containerPort: 8080
              name: http
          envFrom:
            - configMapRef:
                name: omnicommerce-config
            - configMapRef:
                name: backend-config
            - secretRef:
                name: omnicommerce-secrets
          resources:
            requests:
              cpu: "500m"
              memory: "512Mi"
            limits:
              cpu: "2"
              memory: "2Gi"
          startupProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 10
            periodSeconds: 5
            failureThreshold: 30
          livenessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 15
          readinessProbe:
            httpGet:
              path: /health
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: backend-hpa
  namespace: omnicommerce
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: backend
  minReplicas: 3
  maxReplicas: 20
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70
    - type: Resource
      resource:
        name: memory
        target:
          type: Utilization
          averageUtilization: 80

---
# ============================================================
# FRONTEND: Web Storefront
# ============================================================

apiVersion: v1
kind: Service
metadata:
  name: web
  namespace: omnicommerce
spec:
  ports:
    - port: 3000
      targetPort: 3000
  selector:
    app: web
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: omnicommerce
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2
      maxUnavailable: 0
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: registry.omnicommerce.io/omnicommerce-web:latest
          ports:
            - containerPort: 3000
          env:
            - name: NODE_ENV
              value: "production"
            - name: NEXT_PUBLIC_API_URL
              value: "https://api.omnicommerce.io/api/v1"
          resources:
            requests:
              cpu: "250m"
              memory: "256Mi"
            limits:
              cpu: "1"
              memory: "512Mi"
          readinessProbe:
            httpGet:
              path: /
              port: 3000
            initialDelaySeconds: 10
            periodSeconds: 10
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: web-hpa
  namespace: omnicommerce
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: web
  minReplicas: 3
  maxReplicas: 15
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 60

---
# ============================================================
# FRONTEND: Admin Panel
# ============================================================

apiVersion: v1
kind: Service
metadata:
  name: admin
  namespace: omnicommerce
spec:
  ports:
    - port: 3001
      targetPort: 3001
  selector:
    app: admin
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: admin
  namespace: omnicommerce
spec:
  replicas: 2
  selector:
    matchLabels:
      app: admin
  template:
    metadata:
      labels:
        app: admin
    spec:
      containers:
        - name: admin
          image: registry.omnicommerce.io/omnicommerce-admin:latest
          ports:
            - containerPort: 3001
          resources:
            requests:
              cpu: "200m"
              memory: "256Mi"
            limits:
              cpu: "500m"
              memory: "512Mi"

---
# ============================================================
# FRONTEND: Vendor Dashboard
# ============================================================

apiVersion: v1
kind: Service
metadata:
  name: vendor-dashboard
  namespace: omnicommerce
spec:
  ports:
    - port: 3002
      targetPort: 3002
  selector:
    app: vendor-dashboard
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: vendor-dashboard
  namespace: omnicommerce
spec:
  replicas: 2
  selector:
    matchLabels:
      app: vendor-dashboard
  template:
    metadata:
      labels:
        app: vendor-dashboard
    spec:
      containers:
        - name: vendor-dashboard
          image: registry.omnicommerce.io/omnicommerce-vendor:latest
          ports:
            - containerPort: 3002

---
# ============================================================
# NGINX INGRESS
# ============================================================

apiVersion: v1
kind: Service
metadata:
  name: nginx
  namespace: omnicommerce
spec:
  type: LoadBalancer
  ports:
    - port: 80
      targetPort: 80
      name: http
    - port: 443
      targetPort: 443
      name: https
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: omnicommerce
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.26-alpine
          ports:
            - containerPort: 80
            - containerPort: 443
          volumeMounts:
            - name: nginx-config
              mountPath: /etc/nginx/nginx.conf
              subPath: nginx.conf
            - name: nginx-sites
              mountPath: /etc/nginx/conf.d
      volumes:
        - name: nginx-config
          configMap:
            name: nginx-config
        - name: nginx-sites
          configMap:
            name: nginx-sites-config

---
# ============================================================
# CERT-MANAGER (for TLS)
# ============================================================

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: ops@omnicommerce.io
    privateKeySecretRef:
      name: letsencrypt-prod-key
    solvers:
      - http01:
          ingress:
            class: nginx

---
# ============================================================
# NETWORK POLICIES
# ============================================================

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: backend-policy
  namespace: omnicommerce
spec:
  podSelector:
    matchLabels:
      app: backend
  policyTypes:
    - Ingress
    - Egress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: nginx
      ports:
        - protocol: TCP
          port: 8080
  egress:
    - to:
        - podSelector:
            matchLabels:
              app: postgres
      ports:
        - protocol: TCP
          port: 5432
    - to:
        - podSelector:
            matchLabels:
              app: redis
      ports:
        - protocol: TCP
          port: 6379
    - to:
        - podSelector:
            matchLabels:
              app: elasticsearch
      ports:
        - protocol: TCP
          port: 9200
    - to:
        - podSelector:
            matchLabels:
              app: kafka
      ports:
        - protocol: TCP
          port: 9092
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: postgres-policy
  namespace: omnicommerce
spec:
  podSelector:
    matchLabels:
      app: postgres
  policyTypes:
    - Ingress
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: backend
      ports:
        - protocol: TCP
          port: 5432

---
# ============================================================
# POD DISRUPTION BUDGETS
# ============================================================

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: backend-pdb
  namespace: omnicommerce
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: backend
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: postgres-pdb
  namespace: omnicommerce
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app: postgres
---
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: elasticsearch-pdb
  namespace: omnicommerce
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app: elasticsearch

---
# ============================================================
# SERVICE ACCOUNTS
# ============================================================

apiVersion: v1
kind: ServiceAccount
metadata:
  name: omnicommerce-backend
  namespace: omnicommerce
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: omnicommerce-backend
  namespace: omnicommerce
rules:
  - apiGroups: [""]
    resources: ["configmaps", "secrets"]
    verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: omnicommerce-backend
  namespace: omnicommerce
subjects:
  - kind: ServiceAccount
    name: omnicommerce-backend
roleRef:
  kind: Role
  name: omnicommerce-backend
  apiGroup: rbac.authorization.k8s.io
