# kuploy native stack spec — LearnHouse LMS
# Self-contained: a *provision*-mode import creates these services, generates
# the `generate:` secrets, assigns a domain to the flagged component, and wires
# the DB/Redis connections — no pre-created services needed.
#
# Verified against learnhouse/learnhouse (dev branch), 2026-06-24:
#   - image is on GHCR (ghcr.io/learnhouse/app), NOT Docker Hub. It's ONE fat
#     image bundling Next.js + FastAPI + Yjs collab behind nginx (listens :80).
#   - postgres MUST be pgvector — plain postgres breaks AI/RAG (needs the ext).
#   - env var names confirmed against apps/cli/src/templates/env.ts + config.py.
# The domain is auto-wired: `${domain}` is replaced at provision time with the
# free host assigned to learnhouse-app. Only S3 (endpoint + AWS creds) needs
# real values before content uploads work.

name: learnhouse
description: LearnHouse LMS (Next.js + FastAPI + bundled Yjs/Hocuspocus collab)
components:
  - name: learnhouse-app
    type: web
    serviceType: application
    domain: true
    port: 80 # nginx inside the container fronts web(8000)/api(9000)/collab(4000)
    source:
      type: docker
      image: ghcr.io/learnhouse/app:1.2.7 # GHCR; pinned (do not use :latest)
    dependsOn:
      - learnhouse-postgres
      - learnhouse-redis
      - learnhouse-media
    env:
      # --- resolved from provider services at deploy ---
      - key: LEARNHOUSE_SQL_CONNECTION_STRING
        fromComponent: learnhouse-postgres
        field: connectionString # postgresql://user:pass@host:5432/db
      - key: LEARNHOUSE_REDIS_CONNECTION_STRING
        fromComponent: learnhouse-redis
        field: connectionString # redis://:pass@host:6379
      - key: LEARNHOUSE_REDIS_URL # the collab server reads this one
        fromComponent: learnhouse-redis
        field: connectionString
      # --- generated at provision time (must be >=32 chars or the API refuses
      #     to boot — config.py raises on a short LEARNHOUSE_AUTH_JWT_SECRET_KEY) ---
      - key: NEXTAUTH_SECRET
        generate: random32
      - key: LEARNHOUSE_AUTH_JWT_SECRET_KEY
        generate: random32
      - key: COLLAB_INTERNAL_KEY
        generate: random32
      # First-boot install: the API auto-install hard-requires an admin password
      # (verified on a live deploy — without it the API crashloops on startup).
      # The org defaults to "Default Organization"/"default" if the org vars are
      # unset; set the admin email so you know the login.
      - key: LEARNHOUSE_INITIAL_ADMIN_PASSWORD
        generate: random32
      - key: LEARNHOUSE_INITIAL_ADMIN_EMAIL
        value: "admin@lms.example.com"
      # --- app config: ${domain} is replaced at provision time with the free
      #     host assigned to learnhouse-app, so these are reachable with no edits.
      - key: LEARNHOUSE_PORT
        value: "9000"
      - key: LEARNHOUSE_DOMAIN
        value: "${domain}"
      - key: LEARNHOUSE_COOKIE_DOMAIN
        value: "${domain}"
      - key: NEXT_PUBLIC_LEARNHOUSE_DOMAIN
        value: "${domain}"
      - key: NEXT_PUBLIC_LEARNHOUSE_HTTPS
        value: "true"
      - key: NEXTAUTH_URL
        value: "https://${domain}"
      - key: NEXT_PUBLIC_LEARNHOUSE_API_URL
        value: "https://${domain}/api/v1/" # note the /api/v1/ path + trailing slash
      - key: NEXT_PUBLIC_LEARNHOUSE_BACKEND_URL
        value: "https://${domain}"
      - key: NEXT_PUBLIC_COLLAB_URL
        value: "wss://${domain}/collab"
      # --- object storage: a managed bucket on the shared cluster MinIO
      #     (kuploy-k8s#36). The kuploy server provisions a scoped bucket + a
      #     restricted access key and injects endpoint/bucket/key/secret here
      #     server-side — no hand-entered creds, no placeholder. boto3 reads the
      #     standard AWS_* chain; LearnHouse adds the two LEARNHOUSE_S3_API_*
      #     vars. The app does not auto-create the bucket — provisioning does. ---
      - key: LEARNHOUSE_CONTENT_DELIVERY_TYPE
        value: "s3api"
      - key: LEARNHOUSE_S3_API_ENDPOINT_URL
        fromComponent: learnhouse-media
        field: endpoint # http://minio.<ns>:9000 (in-cluster)
      - key: LEARNHOUSE_S3_API_BUCKET_NAME
        fromComponent: learnhouse-media
        field: bucket # the provisioned bucket name (not a hardcoded one)
      - key: AWS_ACCESS_KEY_ID
        fromComponent: learnhouse-media
        field: accessKey # bucket-scoped service-account key
      - key: AWS_SECRET_ACCESS_KEY
        fromComponent: learnhouse-media
        field: secretKey
      # boto3 needs a region; value is arbitrary for MinIO.
      - key: AWS_REGION
        fromComponent: learnhouse-media
        field: region
      - key: AWS_DEFAULT_REGION
        fromComponent: learnhouse-media
        field: region

  - name: learnhouse-postgres
    type: database
    serviceType: postgres
    engine: postgres
    source:
      type: docker
      image: pgvector/pgvector:pg16 # AI/RAG needs the pgvector extension

  - name: learnhouse-redis
    type: database
    serviceType: redis
    engine: redis
    cache: true # ephemeral cache (no PVC, capped, LRU) — LearnHouse uses redis
    #            only for cache + collab pub/sub, so no durability needed.
    #            Requires kuploy server with the cache-role support (kuploy#75).

  - name: learnhouse-media
    type: storage
    serviceType: bucket # managed object storage on the shared cluster MinIO (kuploy-k8s#36)
    # No source/engine: a bucket runs no per-stack workload. At deploy the kuploy
    # server creates the bucket + a bucket-scoped access key on the shared MinIO
    # and wires endpoint/bucket/accessKey/secretKey into learnhouse-app above.
    # Requires the shared MinIO installed (`deploy.py minio`, kuploy-k8s#36).

