Skip to content

Build the Platform Core, Chat, and member integrations UI #229

Build the Platform Core, Chat, and member integrations UI

Build the Platform Core, Chat, and member integrations UI #229

name: platform-design
on:
pull_request:
# The product routes and the seam they read through: the main app that serves them, the
# contracts, hooks and enterprise domains its data layer wraps, the chat modules it drives
# unchanged, the use cases its server reads run in process and the host modules its views
# import (`serverSeamHelpers`, `platformHostModules`; platform-design-workflow.test.ts holds
# this list to them), and the API routes the live suites call. A pattern's order matters: the
# ledger follows the docs exclusion so an edit to it still meets the report-based parity check.
paths:
- 'apps/sim/app/(product)/**'
- 'apps/sim/platform/**'
- '!apps/sim/platform/docs/**'
- '!apps/sim/platform/README.md'
- 'apps/sim/platform/docs/org-parity.md'
- 'apps/sim/proxy.ts'
- 'apps/sim/next.config.ts'
- 'apps/sim/turbo.json'
- 'apps/sim/lib/api/contracts/**'
- 'apps/sim/app/api/**'
- 'apps/sim/hooks/queries/**'
- 'apps/sim/lib/mothership/**'
- 'apps/sim/lib/auth/**'
- 'apps/sim/lib/billing/**'
- 'apps/sim/lib/workspaces/**'
- 'apps/sim/lib/credential-groups/**'
- 'apps/sim/lib/integrations/**'
- 'apps/sim/lib/permission-groups/**'
- 'apps/sim/lib/permissions/**'
- 'apps/sim/lib/organization-secrets/**'
- 'apps/sim/lib/settings/**'
- 'apps/sim/lib/sim-links/**'
- 'apps/sim/lib/toast/**'
- 'apps/sim/lib/core/application/**'
- 'apps/sim/lib/core/config/block-visibility.ts'
- 'apps/sim/lib/core/orchestration/types.ts'
- 'apps/sim/lib/core/utils/deadline.ts'
- 'apps/sim/lib/catalog/application/**'
- 'apps/sim/lib/credentials/application/**'
- 'apps/sim/lib/knowledge/application/**'
- 'apps/sim/lib/knowledge/search/results.ts'
- 'apps/sim/lib/users/application/**'
- 'apps/sim/lib/workflows/application/**'
- 'apps/sim/components/file-viewer/**'
- 'apps/sim/components/dashboard-panel/**'
- 'apps/sim/components/find-bar/**'
- 'apps/sim/components/paste-guard/**'
- 'apps/sim/hooks/sim-search/**'
- 'apps/sim/ee/**'
- 'apps/sim/hooks/mothership-chat/**'
- 'apps/sim/components/mothership-chat/message-content/**'
- 'apps/sim/components/workflow-editor/components/panel/components/copilot/components/user-input/hooks/**'
- 'apps/sim/scripts/platform-live-seed.ts'
- 'apps/sim/package.json'
- 'apps/realtime/**'
- 'apps/desktop/**'
- 'packages/desktop-bridge/**'
- 'apps/sim/lib/navigation/**'
- 'apps/sim/lib/organizations/**'
- 'apps/sim/app/_shell/**'
- 'apps/sim/stores/**'
- 'packages/db/**'
- 'packages/emcn/**'
- 'packages/emcn-platform/**'
- 'packages/emcn-legacy/**'
- 'scripts/emcn-packages.ts'
- 'scripts/check-platform-*'
- 'scripts/platform-*.ts'
- 'scripts/sync-platform-*.ts'
- '.github/workflows/platform-design.yml'
- '.github/scripts/http-e2e.sh'
- 'bun.lock'
workflow_dispatch:
inputs:
live_only:
description: Run only the live jobs, skipping the fixture suites.
type: boolean
default: false
grep:
description: Narrow the live suite to the specs matching this pattern.
type: string
default: ''
permissions:
contents: read
concurrency:
group: platform-design-${{ github.ref }}
cancel-in-progress: true
# What the main app reads at build and start. A fixture build never opens the database; the live
# jobs point it at their own Postgres.
env:
NEXT_PUBLIC_APP_URL: 'http://localhost:3000'
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:5432/sim_test
BETTER_AUTH_SECRET: http-e2e-ci-secret-at-least-32-characters
ENCRYPTION_KEY: '0000000000000000000000000000000000000000000000000000000000000000'
STRIPE_SECRET_KEY: 'dummy_key_for_ci_only'
STRIPE_WEBHOOK_SECRET: 'dummy_secret_for_ci_only'
AWS_REGION: 'us-west-2'
jobs:
# The main app, built once for the live jobs below. 16 vCPU for the same reason as checks.yml's
# builds: a cold build peaks near 51 GB.
build:
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-16vcpu-ubuntu-2404' || 'linux-x64-8-core' }}
timeout-minutes: 25
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
with:
persist-credentials: false
- uses: ./.github/actions/setup
with:
provider: ${{ vars.CI_PROVIDER }}
turbo-cache-key: turbo-cache-platform-design
- name: Build the main app
env:
NODE_OPTIONS: '--no-warnings --max-old-space-size=8192'
TURBO_CACHE_DIR: .turbo
# Lint's type-check already holds the routes; this build only serves the browser suites.
NEXT_BUILD_SKIP_TYPE_CHECK: 'true'
# Build only: a running app with this key sends through Resend, which refuses it and so
# fails every invite; with no mail provider the app logs each message as sent.
RESEND_API_KEY: 'dummy_key_for_ci_only'
run: bunx turbo run build --filter=@sim/app
# Everything `next start` reads beside node_modules and the source tree, which each job checks
# out and installs itself, as checks.yml's e2e-build packages it.
- name: Package the build
run: >-
tar -I 'zstd -T0' -cf "$RUNNER_TEMP/next-build.tar.zst" -C apps/sim
--exclude .next/cache --exclude .next/trace --exclude '*.map' .next dist/xlsx-worker.mjs
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: platform-next-build
path: ${{ runner.temp }}/next-build.tar.zst
if-no-files-found: error
compression-level: 0
retention-days: 1
# The main app as a fixture build, built once here for the browser and desktop jobs below.
# SIM_PLATFORM_FIXTURES=1 at build time inlines example data with no sign-in
# (`platform/lib/data/mode.ts`); the live build above, like every normal build, carries
# none. Its own Turbo cache, and turbo.json keys the build on the variable, so neither build can
# restore as the other.
fixture-build:
if: ${{ !inputs.live_only }}
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-16vcpu-ubuntu-2404' || 'linux-x64-8-core' }}
timeout-minutes: 25
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
with:
persist-credentials: false
- uses: ./.github/actions/setup
with:
provider: ${{ vars.CI_PROVIDER }}
turbo-cache-key: turbo-cache-platform-fixtures
- name: Build the main app with example data
env:
NODE_OPTIONS: '--no-warnings --max-old-space-size=8192'
TURBO_CACHE_DIR: .turbo
NEXT_BUILD_SKIP_TYPE_CHECK: 'true'
SIM_PLATFORM_FIXTURES: '1'
run: bunx turbo run build --filter=@sim/app
- name: Package the build
run: >-
tar -I 'zstd -T0' -cf "$RUNNER_TEMP/fixture-build.tar.zst" -C apps/sim
--exclude .next/cache --exclude .next/trace --exclude '*.map' .next
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: platform-fixture-build
path: ${{ runner.temp }}/fixture-build.tar.zst
if-no-files-found: error
compression-level: 0
retention-days: 1
# The design suites against the fixture build, which the Playwright config serves with
# `next start`.
browser:
needs: fixture-build
if: ${{ !inputs.live_only }}
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
with:
persist-credentials: false
- uses: ./.github/actions/setup
with:
provider: github
- run: bunx --no-install playwright install --with-deps --only-shell chromium
working-directory: apps/sim
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: platform-fixture-build
path: ${{ runner.temp }}
- run: tar -I zstd -xf "$RUNNER_TEMP/fixture-build.tar.zst" -C apps/sim
- run: bun run --cwd apps/sim test:platform:e2e
env:
PLATFORM_REPORT_PATH: ${{ runner.temp }}/platform-design/report.json
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
if: always()
with:
name: platform-design-browser
path: ${{ runner.temp }}/platform-design
retention-days: 7
# The real Electron shell against the fixture build, served here with `next start` from the
# Linux build: the server bundles are JavaScript, and `.next/node_modules` links resolve to this
# runner's own install, native modules included. The arm64 runner matches desktop-e2e.yml's, so
# the native-module cache stays compatible.
desktop:
needs: fixture-build
if: ${{ !inputs.live_only }}
runs-on: macos-26
timeout-minutes: 30
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
with:
persist-credentials: false
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: 1.4.4
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v6
with:
node-version: 24.22.1
# Electron downloads its binary on first launch, which otherwise lands inside the spec's
# first-window wait. The cache is keyed by version inside, as in desktop-e2e.yml.
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v5
with:
path: ~/Library/Caches/electron
key: desktop-downloads-${{ runner.os }}-${{ hashFiles('bun.lock') }}
restore-keys: desktop-downloads-${{ runner.os }}-
- run: bun install --frozen-lockfile
- name: Download the Electron binary
working-directory: apps/desktop
run: node "$(node -p "require.resolve('electron/install.js')")"
- uses: ./.github/actions/desktop-native-cache
- run: bun run --cwd apps/desktop build
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: platform-fixture-build
path: ${{ runner.temp }}
# macOS tar's `-I` names a file list, so the archive is decompressed through a pipe.
- run: zstd -dc "$RUNNER_TEMP/fixture-build.tar.zst" | tar -xf - -C apps/sim
- run: bun run --cwd apps/sim test:platform:desktop
env:
PLATFORM_DESKTOP_REPORT_PATH: ${{ runner.temp }}/platform-desktop/report.json
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
if: always()
with:
name: platform-desktop
path: ${{ runner.temp }}/platform-desktop
retention-days: 7
# The product routes against the real stack: Postgres, Redis, migrations and the production main
# app, hosted Enterprise and then self-hosted. Group environment and seed:
# `.github/scripts/http-e2e.sh`.
live:
name: live (${{ matrix.topology }})
needs: build
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-8vcpu-ubuntu-2404' || 'linux-x64-8-core' }}
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
include:
- topology: product
group: platform-live
- topology: self-hosted
group: platform-live-self-hosted
services:
postgres:
image: pgvector/pgvector:pg17
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: sim_test
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres -d sim_test"
--health-interval 5s
--health-timeout 5s
--health-retries 10
redis:
image: redis:8.2-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 5s
--health-retries 10
env:
PLATFORM_LIVE_GREP: ${{ inputs.grep }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
with:
persist-credentials: false
- uses: ./.github/actions/setup
with:
provider: ${{ vars.CI_PROVIDER }}
- run: bun run check:platform-parity
- name: Provision the database through migrations
working-directory: packages/db
run: bun run db:migrate
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: platform-next-build
path: ${{ runner.temp }}
- run: tar -I zstd -xf "$RUNNER_TEMP/next-build.tar.zst" -C apps/sim
- name: Map the hosted app to loopback
if: matrix.topology == 'product'
run: printf '127.0.0.1 platform-live.sim.ai\n' | sudo tee -a /etc/hosts
- name: Run the live suite
working-directory: apps/sim
run: bash ../../.github/scripts/http-e2e.sh "${{ matrix.group }}"
- name: Hold the parity ledger to this run
if: always()
run: >-
bun run check:platform-parity
--job "${{ matrix.topology }}"
--report "$RUNNER_TEMP/e2e/${{ matrix.group }}/report.json"
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
if: always()
with:
name: platform-live-${{ matrix.topology }}
path: ${{ runner.temp }}/e2e/
if-no-files-found: warn
retention-days: 7