# yaml-language-server: $schema=https://schema.zeabur.app/template.json
apiVersion: zeabur.com/v1
kind: Template
metadata:
    name: Chronos
spec:
    description: |
        台灣中小企業打卡薪資管理系統。FastAPI + React + PostgreSQL.
        Attendance, payroll, leave, compliance, audit, overtime.
    variables:
        - key: PUBLIC_DOMAIN
          type: DOMAIN
          name: Client Domain
          description: The domain for the Chronos web app (e.g., chronos-app.cloud-f1.com).
        - key: API_DOMAIN
          type: DOMAIN
          name: API Domain
          description: The domain for the Chronos API server (e.g., ai-clock-api.zeabur.app).
        - key: GCR_JSON_KEY
          type: STRING
          name: GCR Service Account Key
          description: GCP service account JSON key for pulling images from Artifact Registry.
    tags:
        - Tool
        - SaaS
        - HR
        - Attendance
        - Payroll
    readme: |-
        # Chronos — 打卡薪資管理系統

        Taiwan SME attendance & payroll management. 50-500 employees.

        ## Services

        - **Server**: FastAPI + PostgreSQL (auto-runs migrations on startup)
        - **Client**: React SPA served via Nginx (runtime config.json injection)
        - **PostgreSQL**: Database (16-alpine)

        ## Post-Deploy

        1. Set `SECRET_KEY` and `REFRESH_SECRET_KEY` to random 64-char hex strings
        2. Set `ALLOWED_ORIGINS_STR` to your client domain
        3. Set `API_URL` on the client service to your API server URL
        4. (Optional) Set Google OAuth credentials for SSO
    services:
        - name: postgresql
          icon: https://raw.githubusercontent.com/zeabur/service-icons/main/marketplace/postgresql.svg
          template: PREBUILT
          spec:
            source:
                image: postgres:16-alpine
            ports:
                - id: database
                  port: 5432
                  type: TCP
            volumes:
                - id: data
                  dir: /var/lib/postgresql/data
            instructions:
                - title: Connection String
                  content: postgresql://${POSTGRES_USERNAME}:${POSTGRES_PASSWORD}@${PORT_FORWARDED_HOSTNAME}:${DATABASE_PORT_FORWARDED_PORT}/${POSTGRES_DATABASE}
                - title: PostgreSQL username
                  content: ${POSTGRES_USERNAME}
                - title: PostgreSQL password
                  content: ${POSTGRES_PASSWORD}
            env:
                PGDATA:
                    default: /var/lib/postgresql/data/pgdata
                POSTGRES_CONNECTION_STRING:
                    default: postgresql://${POSTGRES_USERNAME}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DATABASE}
                    expose: true
                POSTGRES_DATABASE:
                    default: ${POSTGRES_DB}
                    expose: true
                POSTGRES_DB:
                    default: chronos
                POSTGRES_HOST:
                    default: ${CONTAINER_HOSTNAME}
                    expose: true
                POSTGRES_PASSWORD:
                    default: ${PASSWORD}
                    expose: true
                POSTGRES_PORT:
                    default: ${DATABASE_PORT}
                    expose: true
                POSTGRES_USER:
                    default: chronos_user
                POSTGRES_USERNAME:
                    default: ${POSTGRES_USER}
                    expose: true
            configs:
                - path: /etc/postgresql/postgresql.conf
                  template: |
                    listen_addresses = '*'
                    max_connections = 100
                    shared_buffers = 128MB
                    dynamic_shared_memory_type = posix
                    max_wal_size = 1GB
                    min_wal_size = 80MB
                    log_timezone = 'Asia/Taipei'
                    datestyle = 'iso, mdy'
                    timezone = 'Asia/Taipei'
                    lc_messages = 'en_US.utf8'
                    lc_monetary = 'en_US.utf8'
                    lc_numeric = 'en_US.utf8'
                    lc_time = 'en_US.utf8'
                    default_text_search_config = 'pg_catalog.english'
                  permission: null
                  envsubst: null
            healthCheck:
                type: TCP
                port: database
        - name: server
          icon: https://service-icons.zeabur.com/git/python/fastapi.svg
          dependencies:
            - postgresql
          template: PREBUILT
          spec:
            source:
                image: asia-east1-docker.pkg.dev/common-411213/dev-app/chronos-server:dev
            ports:
                - id: web
                  port: 8088
                  type: HTTP
            env:
                ACCESS_TOKEN_EXPIRE_MINUTES:
                    default: "15"
                ALGORITHM:
                    default: HS256
                ALLOWED_ORIGINS_STR:
                    default: https://${PUBLIC_DOMAIN}
                DATABASE_URL:
                    default: postgresql+asyncpg://${POSTGRES_USERNAME}:${POSTGRES_PASSWORD}@${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DATABASE}
                DB_MAX_OVERFLOW:
                    default: "30"
                DB_POOL_SIZE:
                    default: "20"
                DEBUG:
                    default: "false"
                EMAIL_FROM:
                    default: noreply@chronos.app
                EMAIL_PROVIDER:
                    default: console
                ENVIRONMENT:
                    default: production
                    expose: true
                GOOGLE_CLIENT_ID:
                    default: ""
                GOOGLE_CLIENT_SECRET:
                    default: ""
                LOG_FORMAT:
                    default: json
                PORT:
                    default: "8088"
                    expose: true
                RATE_LIMIT_AUTH:
                    default: 5/minute
                RATE_LIMIT_GENERAL:
                    default: 200/minute
                REFRESH_SECRET_KEY:
                    default: ${PASSWORD}_refresh
                REFRESH_TOKEN_EXPIRE_DAYS:
                    default: "30"
                SECRET_KEY:
                    default: ${PASSWORD}
                SENTRY_DSN:
                    default: ""
                STORAGE_BACKEND:
                    default: local
            healthCheck:
                type: HTTP
                port: web
                http:
                    path: /health
          domainKey: API_DOMAIN
        - name: client
          icon: https://raw.githubusercontent.com/zeabur/service-icons/refs/heads/main/git/nodejs/vite.svg
          dependencies:
            - server
          template: PREBUILT
          spec:
            source:
                image: asia-east1-docker.pkg.dev/common-411213/dev-app/chronos-client:dev
            ports:
                - id: web
                  port: 3000
                  type: HTTP
            env:
                API_URL:
                    default: https://${API_DOMAIN}
            healthCheck:
                type: HTTP
                port: web
                http:
                    path: /health
          domainKey: PUBLIC_DOMAIN
