feat(chat): add embedded assistant and MCP workflows #9641
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Klicker automated testing with cypress | |
| on: | |
| push: | |
| branches: ['v3', 'v3*'] | |
| # paths: | |
| # - apps/** | |
| # - packages/** | |
| pull_request: | |
| branches: ['v3', 'v3*'] | |
| types: [opened, synchronize, reopened, ready_for_review] | |
| paths: | |
| - apps/** | |
| - packages/** | |
| - cypress/** | |
| - .github/workflows/cypress-testing.yml | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref_name }} | |
| cancel-in-progress: true | |
| env: | |
| REGISTRY: ghcr.io | |
| # This workflow runs Cypress tests with two different strategies: | |
| # 1. Draft PRs: Fast parallel testing with cypress-split (8 containers, no Cloud) | |
| # 2. Non-draft PRs & direct v3 pushes: Full Cypress Cloud recording for production visibility | |
| # | |
| # Event handling strategy (with redundancy for reliability): | |
| # - Feature branches (v3-*): Handled by BOTH push and pull_request events for redundancy | |
| # - Draft PRs: Use parallel testing regardless of event type | |
| # - Non-draft PRs: Use Cypress Cloud with recording | |
| # - Concurrency group prevents duplicate runs when both events fire | |
| jobs: | |
| # Runs parallel Cypress tests for development (draft PRs and feature branch pushes) | |
| # Uses cypress-split to distribute tests across 8 containers for faster feedback | |
| # No Cypress Cloud recording to save costs during development | |
| cypress-run-parallel-draft: | |
| if: (github.event_name == 'pull_request' && github.event.pull_request.draft == true) | |
| runs-on: ubuntu-24.04 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| containers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] | |
| services: | |
| postgres: | |
| image: postgres:15 | |
| env: | |
| POSTGRES_USER: klicker-prod | |
| POSTGRES_PASSWORD: klicker | |
| POSTGRES_DB: klicker-prod | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432:5432 | |
| postgres_hatchet: | |
| image: postgres:15 | |
| env: | |
| POSTGRES_USER: hatchet | |
| POSTGRES_PASSWORD: hatchet | |
| POSTGRES_DB: hatchet | |
| options: >- | |
| --health-cmd "pg_isready -U hatchet -d hatchet" | |
| --health-interval 5s | |
| --health-timeout 10s | |
| --health-retries 10 | |
| --health-start-period 30s | |
| ports: | |
| - 5433:5432 | |
| redis_cache: | |
| image: redis:7 | |
| options: >- | |
| --health-cmd "redis-cli ping" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 6380:6379 | |
| redis_exec: | |
| options: >- | |
| --health-cmd "redis-cli ping" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| image: redis:7 | |
| ports: | |
| - 6379:6379 | |
| redis_assessment_exec: | |
| options: >- | |
| --health-cmd "redis-cli ping" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| image: redis:7 | |
| ports: | |
| - 6381:6379 | |
| hatchet: | |
| image: ghcr.io/hatchet-dev/hatchet/hatchet-lite:v0.73.1 | |
| ports: | |
| - '8888:8888' | |
| - '7077:7077' | |
| env: | |
| DATABASE_URL: 'postgresql://hatchet:hatchet@postgres_hatchet:5432/hatchet?sslmode=disable' | |
| SERVER_AUTH_COOKIE_DOMAIN: localhost | |
| SERVER_AUTH_COOKIE_INSECURE: 't' | |
| SERVER_GRPC_BIND_ADDRESS: '0.0.0.0' | |
| SERVER_GRPC_INSECURE: 't' | |
| SERVER_GRPC_BROADCAST_ADDRESS: localhost:7077 | |
| SERVER_INTERNAL_CLIENT_INTERNAL_GRPC_BROADCAST_ADDRESS: localhost:7077 | |
| SERVER_GRPC_PORT: '7077' | |
| SERVER_URL: http://localhost:8888 | |
| SERVER_AUTH_SET_EMAIL_VERIFIED: 't' | |
| SERVER_DEFAULT_ENGINE_VERSION: 'V1' | |
| SERVER_LOGGER_LEVEL: debug | |
| SERVER_LOGGER_FORMAT: console | |
| steps: | |
| - run: echo "Running parallel Cypress tests for draft PR (container ${{ matrix.containers }})" | |
| - name: Define node version | |
| uses: actions/setup-node@v3 | |
| with: | |
| node-version: 20 | |
| - name: Check out repository code | |
| uses: actions/checkout@v3 | |
| - uses: pnpm/action-setup@v2 | |
| with: | |
| version: 10.15.0 | |
| run_install: false | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - uses: actions/cache@v4 | |
| name: Setup pnpm cache | |
| with: | |
| path: | | |
| ${{ env.STORE_PATH }} | |
| ~/.cache/Cypress | |
| key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-store- | |
| - name: Cache turbo build artifacts | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| .turbo | |
| key: ${{ runner.os }}-turbo-${{ hashFiles('**/pnpm-lock.yaml', 'turbo.json') }}-${{ github.ref_name }} | |
| restore-keys: | | |
| ${{ runner.os }}-turbo-${{ hashFiles('**/pnpm-lock.yaml', 'turbo.json') }}- | |
| ${{ runner.os }}-turbo- | |
| - name: Install dependencies | |
| run: pnpm install | |
| - name: Build all packages and apps | |
| run: pnpm run --filter @klicker-uzh/prisma build:test && pnpm run build:test | |
| - name: Prepare .env files | |
| run: | | |
| ./util/_create_hatchet_token_cypress.sh | |
| - name: Apply migrations and seed the database | |
| run: | | |
| cd packages/prisma | |
| pnpm run prisma:reset:raw -f | |
| env: | |
| DATABASE_URL: postgres://klicker-prod:klicker@localhost:5432/klicker-prod | |
| - name: Start services and wait for readiness | |
| run: | | |
| chmod +x .github/scripts/wait-for-services.sh | |
| .github/scripts/wait-for-services.sh | |
| env: | |
| APP_SECRET: abcd | |
| DATABASE_URL: postgres://klicker-prod:klicker@localhost:5432/klicker-prod | |
| NODE_ENV: production | |
| SERVICE_ENDPOINTS: 'http://127.0.0.1:3000/healthz http://127.0.0.1:3001 http://127.0.0.1:3002 http://127.0.0.1:3003 http://127.0.0.1:3010' | |
| TIMEOUT_SECONDS: '300' | |
| CHECK_INTERVAL: '5' | |
| REDIS_HOST: localhost | |
| REDIS_PASS: '' | |
| REDIS_PORT: 6379 | |
| REDIS_ASSESSMENT_PORT: 6381 | |
| REDIS_ASSESSMENT_PASS: '' | |
| REDIS_ASSESSMENT_HOST: localhost | |
| # Provide all app origins to the services and tests | |
| APP_ORIGIN_API: http://127.0.0.1:3000 | |
| APP_ORIGIN_AUTH: http://127.0.0.1:3010 | |
| APP_ORIGIN_LTI: http://127.0.0.1:3005 | |
| APP_ORIGIN_PWA: http://127.0.0.1:3001 | |
| APP_ORIGIN_MANAGE: http://127.0.0.1:3002 | |
| APP_ORIGIN_CONTROL: http://127.0.0.1:3003 | |
| APP_ORIGIN_ASSESSMENT_API: http://127.0.0.1:3000 | |
| APP_ORIGIN_ASSESSMENT_PWA: http://127.0.0.1:3001 | |
| - name: Cypress run parallel with cypress-split | |
| uses: cypress-io/github-action@v6 | |
| timeout-minutes: 120 | |
| with: | |
| install: false | |
| wait-on: 'http://127.0.0.1:3000/healthz, http://127.0.0.1:3001, http://127.0.0.1:3002, http://127.0.0.1:3003, http://127.0.0.1:3010' | |
| wait-on-timeout: 300 | |
| browser: electron | |
| working-directory: cypress | |
| env: | |
| CYPRESS_FAIL_FAST: 'false' | |
| APP_SECRET: abcd | |
| DATABASE_URL: postgres://klicker-prod:klicker@127.0.0.1:5432/klicker-prod | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| NODE_ENV: production | |
| HATCHET_API_URL: http://127.0.0.1:8888 | |
| HATCHET_TENANT_ID: 707d0855-80ab-4e1f-a156-f1c4546cbf52 | |
| HATCHET_HOST_PORT: 7077 | |
| # Ensure Cypress process has all origins, too | |
| APP_ORIGIN_API: http://127.0.0.1:3000 | |
| APP_ORIGIN_AUTH: http://127.0.0.1:3010 | |
| APP_ORIGIN_LTI: http://127.0.0.1:3005 | |
| APP_ORIGIN_PWA: http://127.0.0.1:3001 | |
| APP_ORIGIN_MANAGE: http://127.0.0.1:3002 | |
| APP_ORIGIN_CONTROL: http://127.0.0.1:3003 | |
| APP_ORIGIN_ASSESSMENT_API: http://127.0.0.1:3000 | |
| APP_ORIGIN_ASSESSMENT_PWA: http://127.0.0.1:3001 | |
| SPLIT: ${{ strategy.job-total }} | |
| SPLIT_INDEX: ${{ strategy.job-index }} | |
| SPLIT_FILE: timings.json | |
| - if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: cypress-artifacts-draft-${{ matrix.containers }} | |
| path: | | |
| cypress/cypress/videos | |
| cypress/cypress/screenshots | |
| if-no-files-found: ignore | |
| retention-days: 1 | |
| # Runs Cypress tests with Cloud recording for production-ready code | |
| # Triggers on: | |
| # - Non-draft pull requests (for code review) | |
| # - Direct pushes to v3 branch (for hotfixes/direct commits) | |
| # Provides full video/screenshot recording and Cypress Dashboard visibility | |
| cypress-run-cloud: | |
| if: (github.event_name == 'pull_request' && github.event.pull_request.draft == false) || (github.event_name == 'push' && github.ref == 'refs/heads/v3') | |
| runs-on: ubuntu-24.04 | |
| # strategy: | |
| # fail-fast: false | |
| # matrix: | |
| # containers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] | |
| services: | |
| postgres: | |
| image: postgres:15 | |
| env: | |
| POSTGRES_USER: klicker-prod | |
| POSTGRES_PASSWORD: klicker | |
| POSTGRES_DB: klicker-prod | |
| options: >- | |
| --health-cmd pg_isready | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 5432:5432 | |
| postgres_hatchet: | |
| image: postgres:15 | |
| env: | |
| POSTGRES_USER: hatchet | |
| POSTGRES_PASSWORD: hatchet | |
| POSTGRES_DB: hatchet | |
| options: >- | |
| --health-cmd "pg_isready -U hatchet -d hatchet" | |
| --health-interval 5s | |
| --health-timeout 10s | |
| --health-retries 10 | |
| --health-start-period 30s | |
| ports: | |
| - 5433:5432 | |
| redis_cache: | |
| image: redis:7 | |
| options: >- | |
| --health-cmd "redis-cli ping" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| ports: | |
| - 6380:6379 | |
| redis_exec: | |
| options: >- | |
| --health-cmd "redis-cli ping" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| image: redis:7 | |
| ports: | |
| - 6379:6379 | |
| redis_assessment_exec: | |
| options: >- | |
| --health-cmd "redis-cli ping" | |
| --health-interval 10s | |
| --health-timeout 5s | |
| --health-retries 5 | |
| image: redis:7 | |
| ports: | |
| - 6381:6379 | |
| hatchet: | |
| image: ghcr.io/hatchet-dev/hatchet/hatchet-lite:v0.73.1 | |
| ports: | |
| - '8888:8888' | |
| - '7077:7077' | |
| env: | |
| DATABASE_URL: 'postgresql://hatchet:hatchet@postgres_hatchet:5432/hatchet?sslmode=disable' | |
| SERVER_AUTH_COOKIE_DOMAIN: localhost | |
| SERVER_AUTH_COOKIE_INSECURE: 't' | |
| SERVER_GRPC_BIND_ADDRESS: '0.0.0.0' | |
| SERVER_GRPC_INSECURE: 't' | |
| SERVER_GRPC_BROADCAST_ADDRESS: localhost:7077 | |
| SERVER_INTERNAL_CLIENT_INTERNAL_GRPC_BROADCAST_ADDRESS: localhost:7077 | |
| SERVER_GRPC_PORT: '7077' | |
| SERVER_URL: http://localhost:8888 | |
| SERVER_AUTH_SET_EMAIL_VERIFIED: 't' | |
| SERVER_DEFAULT_ENGINE_VERSION: 'V1' | |
| SERVER_LOGGER_LEVEL: debug | |
| SERVER_LOGGER_FORMAT: console | |
| steps: | |
| - run: echo "Running Cypress tests with Cloud recording for non-draft PR or push to v3" | |
| - name: Define node version | |
| uses: actions/setup-node@v3 | |
| with: | |
| node-version: 20 | |
| - name: Check out repository code | |
| uses: actions/checkout@v3 | |
| - uses: pnpm/action-setup@v2 | |
| with: | |
| version: 10.15.0 | |
| run_install: false | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - uses: actions/cache@v4 | |
| name: Setup pnpm cache | |
| with: | |
| path: | | |
| ${{ env.STORE_PATH }} | |
| ~/.cache/Cypress | |
| key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-store- | |
| - name: Cache turbo build artifacts | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| .turbo | |
| key: ${{ runner.os }}-turbo-${{ hashFiles('**/pnpm-lock.yaml', 'turbo.json') }}-${{ github.ref_name }} | |
| restore-keys: | | |
| ${{ runner.os }}-turbo-${{ hashFiles('**/pnpm-lock.yaml', 'turbo.json') }}- | |
| ${{ runner.os }}-turbo- | |
| - name: Install dependencies | |
| run: pnpm install | |
| - name: Build all packages and apps | |
| run: pnpm run --filter @klicker-uzh/prisma build:test && pnpm run build:test | |
| - name: Prepare .env files | |
| run: | | |
| ./util/_create_hatchet_token_cypress.sh | |
| - name: Apply migrations and seed the database | |
| run: | | |
| cd packages/prisma | |
| pnpm run prisma:reset:raw -f | |
| env: | |
| DATABASE_URL: postgres://klicker-prod:klicker@localhost:5432/klicker-prod | |
| - name: Start services and wait for readiness | |
| run: | | |
| chmod +x .github/scripts/wait-for-services.sh | |
| .github/scripts/wait-for-services.sh | |
| env: | |
| APP_SECRET: abcd | |
| DATABASE_URL: postgres://klicker-prod:klicker@localhost:5432/klicker-prod | |
| NODE_ENV: production | |
| SERVICE_ENDPOINTS: 'http://127.0.0.1:3000/healthz http://127.0.0.1:3001 http://127.0.0.1:3002 http://127.0.0.1:3003 http://127.0.0.1:3010' | |
| TIMEOUT_SECONDS: '300' | |
| CHECK_INTERVAL: '5' | |
| # Provide all app origins to the services and tests | |
| APP_ORIGIN_API: http://127.0.0.1:3000 | |
| APP_ORIGIN_AUTH: http://127.0.0.1:3010 | |
| APP_ORIGIN_LTI: http://127.0.0.1:3005 | |
| APP_ORIGIN_PWA: http://127.0.0.1:3001 | |
| APP_ORIGIN_MANAGE: http://127.0.0.1:3002 | |
| APP_ORIGIN_CONTROL: http://127.0.0.1:3003 | |
| APP_ORIGIN_ASSESSMENT_API: http://127.0.0.1:3000 | |
| APP_ORIGIN_ASSESSMENT_PWA: http://127.0.0.1:3001 | |
| - name: Upload service logs | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: service-logs | |
| # path: service-${{ matrix.containers }}.log | |
| path: service.log | |
| if-no-files-found: warn | |
| retention-days: 7 | |
| - name: Cypress run with Cloud recording | |
| uses: cypress-io/github-action@v6 | |
| timeout-minutes: 120 | |
| with: | |
| install: false | |
| wait-on: 'http://127.0.0.1:3000/healthz, http://127.0.0.1:3001, http://127.0.0.1:3002, http://127.0.0.1:3003, http://127.0.0.1:3010' | |
| wait-on-timeout: 300 | |
| record: true | |
| browser: electron | |
| # parallel: true | |
| working-directory: cypress | |
| env: | |
| CYPRESS_FAIL_FAST: 'false' | |
| APP_SECRET: abcd | |
| CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} | |
| DATABASE_URL: postgres://klicker-prod:klicker@127.0.0.1:5432/klicker-prod | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| NODE_ENV: production | |
| HATCHET_API_URL: http://127.0.0.1:8888 | |
| HATCHET_TENANT_ID: 707d0855-80ab-4e1f-a156-f1c4546cbf52 | |
| HATCHET_HOST_PORT: 7077 | |
| # Ensure Cypress process has all origins, too | |
| APP_ORIGIN_API: http://127.0.0.1:3000 | |
| APP_ORIGIN_AUTH: http://127.0.0.1:3010 | |
| APP_ORIGIN_LTI: http://127.0.0.1:3005 | |
| APP_ORIGIN_PWA: http://127.0.0.1:3001 | |
| APP_ORIGIN_MANAGE: http://127.0.0.1:3002 | |
| APP_ORIGIN_CONTROL: http://127.0.0.1:3003 | |
| APP_ORIGIN_ASSESSMENT_API: http://127.0.0.1:3000 | |
| APP_ORIGIN_ASSESSMENT_PWA: http://127.0.0.1:3001 | |
| - if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| # name: cypress-artifacts-cloud-${{ matrix.containers }} | |
| name: cypress-artifacts-cloud | |
| path: | | |
| cypress/cypress/videos | |
| cypress/cypress/screenshots | |
| if-no-files-found: ignore | |
| retention-days: 1 | |
| # - name: Archive code coverage results | |
| # uses: actions/upload-artifact@v3 | |
| # with: | |
| # name: code-coverage | |
| # path: cypress/coverage | |
| # - name: Coveralls | |
| # uses: coverallsapp/github-action@v2 |