Skip to content

feat(web): bring the dashboard into the workspace - #166

Draft
userAugustos wants to merge 5 commits into
feat/api-packagefrom
feat/web-package
Draft

userAugustos wants to merge 5 commits into
feat/api-packagefrom
feat/web-package

Conversation

@userAugustos

@userAugustos userAugustos commented Sep 21, 2026

Copy link
Copy Markdown

Summary

This moves the dashboard and its component library out of the canyon-os checkout and into this workspace, on top of the API package.

packages/ui is the @repo/ui component library, copied verbatim from packages/ui. packages/web is the dashboard, still the workspace package web, copied verbatim from apps/web. This repo has no apps/ directory, so the dashboard lands beside the other packages. Its Playwright config reaches the repo root two levels up and reads its own directory through import.meta.dirname, both of which stay correct at the new depth.

The deployment inputs come with it. deploy/Caddyfile.canyonos becomes packages/web/Caddyfile, Dockerfile.web becomes packages/web/Dockerfile, and the Compose smoke stack and its script land under .docker and scripts. The web image Dockerfile now ends at the canyonos stage, so a plain build produces the self-hosted image and no longer the hosted one. The API Dockerfile copies the two new workspace manifests, which a frozen install needs.

The root commands now cover both packages. bun run check lints, type-checks and format-checks the dashboard and the library alongside the API and the Python packages. bun run test adds the dashboard unit tests and the library tests. bun run build adds the dashboard bundle. Two named commands come across as canyon-os names them: ui:test:e2e for the Playwright suite and canyonos:smoke for the image smoke.

Both images build on every pull request, on main and on demand, and the Compose smoke runs first. Nothing is pushed to a registry: the release trigger, the registry login and the tag-merge job are not here. Publishing is a separate decision.

Test

Locally, from the branch root:

  • bun install --frozen-lockfile clean, lockfile committed.
  • uv lock --check passes, uv.lock unchanged.
  • bun run check: 13 tasks, all green. Only @cc-forge/api:build runs as a dependency; the dry run confirms the Python packages depend on no build.
  • bun run test: 7 tasks. Dashboard 79 tests across 9 files, library 16 tests across 1 file, API 64, CLI 156, core 257 passed with 1 skipped, root 15.
  • bun run build: dashboard dist/index.html present, API dist present, both wheels present.
  • Verbatim check: a recursive diff against the canyon-os checkout reports only the two manifests, the Caddyfile and Dockerfile added under the dashboard, and the Playwright config.
  • Dashboard opens: built with the image build args, served by the Vite preview, opened in Chromium. Title is Canyon Code, the root node renders the local-mode sign-in screen, and the only page errors are the missing API and a font request the sandbox proxy blocks.
  • Spec split: playwright test --list gives 178 default and 20 local-mode specs, both from an ordinary path and from a copy placed under a path that repeats the repository name the way the runner does.
  • Both workflows pass actionlint, and every pinned action was re-resolved against its upstream tag.

In CI, on the branch head:

  • test (check plus test), the dashboard end-to-end job, the API end-to-end job, the security scan and Semgrep all pass.
  • The image smoke passes. It builds both images from the moved Dockerfiles, brings up Postgres, Redis, the API and the dashboard, and exercises sign-in through the dashboard origin, the /api proxy and prefix strip, the SPA deep-link fallback and the security headers. This is the strongest evidence that the two Dockerfiles, the Caddyfile and the repointed smoke script are correct.
  • Both image builds pass, for linux/amd64 and linux/arm64, pushing nothing.

Review Focus

  • packages/web/package.json: adds lint, format, format:check and a test script that runs the unit suite. Everything else is unchanged.
  • packages/ui/package.json: adds lint, format, format:check and typecheck. The type check passes on the verbatim sources across all 65 files.
  • packages/web/playwright.config.ts: the two projects split on a path match, so the split is anchored to the tests directory rather than left open at the front, because an unanchored **/canyonos/** also matches this repository's own name in the checkout path and puts every spec in the local-mode project.
  • package.json: adds dotenv, which the dashboard env loader imports and canyon-os supplied from the root; adds ui:test:e2e and canyonos:smoke; adds build:sdk, which the web image invokes from the repo root.
  • turbo.json: package-scoped entries only, because both packages import the API SDK from its dist. No generic task gained a dependency.
  • pyproject.toml: the uv workspace excludes the two new TypeScript packages.
  • packages/api/Dockerfile: two more manifest copies.
  • packages/web/Dockerfile: manifest and build paths repointed, the landing page manifest dropped, the Caddyfile path changed, the hosted stage removed.
  • packages/web/Caddyfile: the header paragraph about a sibling Caddyfile and the landing page is gone. Every directive is unchanged.
  • scripts/canyonos-smoke.ts: two lines, the two Dockerfile paths the script builds from.
  • .github/workflows/ui-e2e.yml: path filters, working directory, artifact path, a read-only permission block, pins reused from this repo, and one added step that builds the API SDK. The specs import @cc-forge/api/auth, which resolves to that package's dist; canyon-os built it from a root postinstall hook that this repo does not have.
  • .github/workflows/canyonos-image.yml: path filters, matrix Dockerfile paths, the removed release path, and pins reused from this repo.

Known and accepted

  • Both images are built and verified but never published. Publishing, and the matching CLI STACK_VERSION bump, are a separate decision.
  • docs/canyonos-web-image.md is not brought over, so the two comments that cited it no longer do.
  • packages/web/src/routeTree.gen.ts is both ignored and tracked, matching canyon-os. The type check needs the file, and the router plugin regenerates it on every build.

Move the dashboard and its component library into this monorepo as the
workspace packages web and @repo/ui, copied verbatim from the canyon-os
checkout. The dashboard lands under packages/web because this repo has no
apps/ directory; its playwright config already resolves the repo root two
levels up, so the move needs no change there.

Bring the deployment inputs with it: the Caddyfile that the self-hosted image
serves, the image Dockerfile, and the Compose smoke stack and script that
exercise both images together. The web Dockerfile now ends at the canyonos
stage, so a plain build produces the self-hosted image.

Wire the packages into the root commands. Both manifests gain lint, format and
format:check, packages/web gains a unit-test script and packages/ui a type
check, and turbo gets package-scoped build dependencies because both packages
import the API SDK from its dist.
Bring the two workflows the dashboard needs. The end-to-end job runs Playwright
against a Postgres service, and the image job builds both images for both
platforms after a Compose smoke of the stack.

The image workflow no longer publishes. Its release trigger, registry login and
tag-merge job are gone, so it builds and smokes on pull requests, main pushes
and manual runs, and pushes nothing. Publishing is a separate decision.

Actions are pinned by commit with a version comment, reusing the pins already
in this repo.
@coderabbitai

coderabbitai Bot commented Sep 21, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@v4
permissions:
contents: read
steps:
- uses: actions/checkout@v4
--health-retries 10

steps:
- uses: actions/checkout@v4
await page.getByTestId('deploy-plan-set').click();
// The answers travel with it, so the path is the end of the match and not the URL.
await expect(page).toHaveURL(
new RegExp(`${canonicalDeployPath(fixture.project.id)}/performance\\?`)
await page.getByTestId('deploy-expected-load').fill(load);
await page.getByTestId('deploy-priority').click();
await page.getByTestId('deploy-plan-set').click();
await expect(page).toHaveURL(new RegExp(`/projects/${project_id}/deploy/performance\\?`));
Comment on lines +440 to +442
const source_href = new RegExp(
`/projects/${fixture.project.id}/workflows/[0-9a-f-]+/design\\?file_id=${agent.id}$`
);
Comment on lines +440 to +442
const source_href = new RegExp(
`/projects/${fixture.project.id}/workflows/[0-9a-f-]+/design\\?file_id=${agent.id}$`
);
The local-mode specs import @cc-forge/api/auth, which resolves to the API
package's dist. canyon-os built that dist from a root postinstall hook; this
repo has none, so the job has to build it itself.
The two projects split on `**/canyonos/**`, which Playwright matches against
each spec's absolute path. This repository is checked out at
/home/runner/work/canyonos/canyonos, so every spec path carries a canyonos
segment: the default project ignored all 178 of its specs and the local-mode
project took all 198, then failed on an email sign-in spec that the local-mode
dashboard does not serve.

Match on the tests directory instead, so the split depends only on where a
spec lives in the package.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants