Skip to content

Monorepo & dev workflow

The portal framework lives in a single pnpm workspace with two top-level groups:

  • packages/ — the five published @drawnagency/* packages
  • apps/ — the in-repo dev site (apps/dev), admin provisioner (apps/admin), and this docs site (apps/docs)

Clone the monorepo and install:

Terminal window
git clone git@github.com:Drawn-Agency/portal.git
cd portal
pnpm install

pnpm links all workspace packages via workspace:* entries. No separate build step is needed before starting the dev server. The repo is pnpm-only — a preinstall hook runs npx only-allow pnpm, so npm install / yarn are rejected.

Terminal window
pnpm dev

This runs apps/dev on localhost. apps/dev depends on the packages via workspace:*, so Vite’s HMR picks up changes to package source files immediately — no rebuild needed for:

  • Routes and middleware (packages/core/src/pages/, packages/core/src/middleware.ts)
  • Components, hooks, and schemas (packages/primitives/src/)
  • Auth adapters (packages/auth-supabase/src/, packages/core/src/lib/password.ts)
  • GitHub client (packages/github/src/)

HMR only covers files that Vite can hot-reload. A full package rebuild is needed when you change compiled files — anything tsc processes into the dist/ output that other packages or consumers import from dist/:

  • packages/core/src/config.ts, index.ts, integration.ts, vite-plugin.ts
  • packages/primitives/src/**/index.ts (barrel exports)
  • Type declarations
Terminal window
pnpm -r --filter './packages/*' build

Then restart the dev server. The build script in every package runs tsup && rm -f tsconfig.tsbuildinfo && tsc --emitDeclarationOnly — tsup produces the ESM bundle, tsc emits declaration files only.

Terminal window
pnpm vitest run # run all tests once
pnpm vitest run --watch # watch mode
pnpm vitest run tests/lib/auth # specific directory

Tests live in tests/ mirroring src/, and use Vitest + @testing-library/react.

primitives (leaf — no internal deps)
├── authoring (depends on primitives)
├── github (depends on primitives)
├── auth-supabase (depends on primitives)
└── core (depends on primitives + github)

Build order for the full workspace is: primitives → authoring → github → auth-supabase → core. scripts/publish.sh enforces this order automatically; when building manually use pnpm -r --filter './packages/*' build (pnpm respects the workspace dependency graph and builds in the correct order).

Running a client site against your local packages

Section titled “Running a client site against your local packages”

pnpm dev runs the in-repo apps/dev site — the fastest loop for iterating on package code. To instead see your local changes in a real client portal (with its actual content and config), link your local packages into a client checkout. The dev-link script automates this; pack/link are the manual alternatives.

Section titled “pnpm dev-link <client-site-path> (recommended)”

scripts/dev-link.sh wires your local packages into an existing client repo, runs its dev server, and cleans up after itself on exit:

Terminal window
pnpm dev-link ~/flavcity-portal
# equivalent: bash scripts/dev-link.sh ~/flavcity-portal

The client repo must already exist locally with a package.json (e.g. a checkout of a Drawn-Agency/*-portal repo). The script:

  1. Backs up the client’s package.json (to package.json.devlink-backup).
  2. Adds pnpm overrides pointing @drawnagency/primitives, @drawnagency/core, @drawnagency/auth-supabase, and @drawnagency/github at your local packages/* via link:. (@drawnagency/authoring is not linked.)
  3. Adds missing transitive deps — scans those four packages’ dependencies and adds any the client repo doesn’t already declare, so its Vite can resolve them.
  4. Runs pnpm install in the client repo.
  5. Clears the client’s on-disk GitHub API cache (.portal/api-cache) — it’s keyed only by branch, so a cache written by an older package build would otherwise be served stale.
  6. Starts the client dev server with PORTAL_DEV_CACHE=true pnpm dev --host. GitHub API responses are cached locally for speed; append ?refresh=true to a request to bust the cache.
  7. On exit (Ctrl-C), a trap restores the original package.json and reinstalls, leaving the client repo clean.

Edits to package source files reflect live (the packages are linked); changes to compiled files still need a package rebuild (see When a rebuild is required above), then restart.

Manual option A: pack (simulates a real publish)

Section titled “Manual option A: pack (simulates a real publish)”
Terminal window
pnpm -r --filter './packages/*' build
cd packages/primitives && pnpm pack
# repeat for other packages as needed
# In the client repo:
pnpm install ~/portal/packages/primitives/drawnagency-primitives-X.Y.Z.tgz
Terminal window
# In the client repo:
pnpm link ~/portal/packages/primitives
pnpm link ~/portal/packages/authoring
pnpm link ~/portal/packages/github
pnpm link ~/portal/packages/auth-supabase
pnpm link ~/portal/packages/core
# Unlink when done:
pnpm unlink @drawnagency/primitives @drawnagency/authoring @drawnagency/github @drawnagency/auth-supabase @drawnagency/core
pnpm install # restore published versions