Frontend Development (cred-web-commercial)
Prerequisites
- Node.js 20.19+ or 22.12+ (see
enginesinpackage.json) - Bun β₯1.2 β this is the package manager (
packageManager: bun@1.2.23) - Access to the
.envsecrets in 1Password
Quick Start
1. Clone Repository
git clone https://github.com/credinvest/cred-web-commercial.git
cd cred-web-commercial
2. Install Dependencies
bun install
Use Bun, not Yarn or npm
This repo uses Bun as its package manager. Running yarn install or npm install will create incorrect lockfiles.
3. Environment Setup
Copy the example env and fill in the secrets:
cp .env.example .env
The .env.example is pre-configured to point at the remote dev API (api-dev.credplatform.com). Fill in the Firebase, PostHog, and other keys from 1Password.
For local federation (local backend + Apollo Router), see Run Modes below.
4. Start Development Server
bun run dev
The app starts on http://localhost:8002 and connects to the remote dev API.
Project Structure
This is a Turborepo monorepo with the following layout:
cred-web-commercial/
βββ apps/
β βββ web-commercial/ # Main Next.js 16 app (Pages Router)
βββ libs/
β βββ cred-ui/ # Shared UI component library
β βββ cred-ui-charts/ # Chart components
βββ package.json # Root scripts and workspace config
βββ .env # Remote dev API (default)
βββ .env.local.local # Local federation (localhost:4000)
βββ turbo.json # Turborepo pipeline config
Run Modes
| Command | Env file | Connects to | When to use |
|---|---|---|---|
bun run dev |
.env |
Remote dev API | Day-to-day frontend work |
bun run dev:local |
.env.local.local |
Local federation gateway (localhost:4000) |
Testing backend changes locally |
bun run dev:staging |
.env.staging.local |
Staging API | Testing against staging data |
bun run dev:prod |
.env.production.local |
Production API | Debugging production issues |
When switching between modes, clear the Next.js cache to avoid stale env vars:
rm -rf apps/web-commercial/.next
bun run dev:local # or whichever mode
For local federation setup (running the backend locally), see the API Development guide.
GraphQL Codegen
Frontend types are generated from the federated GraphQL schema. After backend schema changes or when updating .gql query files:
bun run gql # regenerate types from remote dev schema
bun run gql:local # regenerate from local federation (restarts router)
Generated files are protected
Never hand-edit schema.graphql, schemas.tsx, operations.tsx, or hooks.tsx β these are regenerated by codegen.
Testing
Unit Tests
bun run test
bun run test:watch # watch mode
bun run test:coverage # with coverage report
Visual Tests (Playwright)
bun run test:visual # headless
bun run test:visual:headed # with browser UI
bun run test:visual:debug # debug mode
bun run test:visual:update # update snapshots
bun run test:visual:report # view report
E2E Tests (Playwright)
bun run test:e2e # headless
bun run test:e2e:headed # with browser UI
bun run test:e2e:debug # debug mode
bun run test:e2e:report # view report
Performance Tests (Playwright)
bun run test:performance # headless
bun run test:performance:headed # with browser UI
bun run test:performance:report # view report
Useful Commands
| Command | Description |
|---|---|
bun run dev |
Start dev server (port 8002) |
bun run dev:local |
Start with local federation backend |
bun run build |
Production build |
bun run lint |
Run ESLint |
bun run lint:fix |
Auto-fix lint issues |
bun run typecheck |
Run TypeScript type checking |
bun run gql |
Regenerate GraphQL types |
bun run test |
Run unit tests |
bun run test:e2e |
Run E2E tests |
bun run storybook:cred-ui |
Start Storybook for cred-ui |
Vercel Preview Deployments (Review Apps)
Frontend deploys (the cred-web-commercial Vercel project) are gated to control cost β Build CPU Minutes are by far the largest Vercel spend. Only production builds on every push; develop, staging, and PR previews build only when explicitly wanted.
How the gate works
scripts/vercel-ignore.sh (Vercel's Ignored Build Step) decides build-vs-skip for every deployment and defaults to skip β nothing fail-opens. The deploy-trigger GitHub Actions create the deployment via the Vercel API with a build.env marker that the ignore-script reads. (Vercel does not populate VERCEL_GIT_PULL_REQUEST_ID for these deploys, so a marker β not PR/label context β is how a build gets approved.)
What Builds
| Target | URL | Builds when |
|---|---|---|
Production (main) |
commercial.credplatform.com | Every push β always |
Develop (develop) |
commercial-dev.credplatform.com | (1) the 3βhour cron, if cred-web-commercial-relevant files changed in the window; (2) a PR labeled update-env-fe is merged; (3) manual workflow_dispatch. Plain merges skip. |
Staging (staging) |
commercial-staging.credplatform.com | A PR labeled update-env-fe is merged. Plain merges skip. |
| PR preview | cred-web-commercial-git-<branch>-credai.vercel.app | The PR has the deploy-preview label (builds on label and on every push while labeled); or [deploy] in a commit; or the /deploy-preview Claude command. |
Commits by jcarrharris |
β | Always |
Two deploys per develop/staging merge
Merging into develop/staging produces two Vercel deployments: the native one (no marker β shows as Ignored / Skipped β expected) and the workflow one (carries the marker β actually builds). The Skipped check is harmless.
Develop auto-build (every 3 hours)
vercel-develop-auto.yml runs on a 0 */3 * * * cron. It checks git log --since="3 hours ago" for web-build-relevant changes and only deploys develop if there are any β quiet 3-hour windows cost nothing. The same workflow handles workflow_dispatch (manual) and the update-env-fe-on-merge trigger. Each deploy is POSTed with build.env DEPLOY_DEVELOP=1.
update-env-fe label (develop / staging)
Add update-env-fe to a PR (base develop or staging); on merge that environment rebuilds. Use it when you need the env to reflect your change immediately instead of waiting for the develop cron.
deploy-preview label (PR previews)
Add the deploy-preview label to your PR β vercel-deploy-on-label.yml triggers a Vercel preview (POSTed with build.env DEPLOY_PREVIEW=1). It builds on label-add and on every subsequent push to the labeled PR. No dummy commit required.
Alternatives: [deploy] anywhere in a commit message (one-off):
git commit -m "feat: my changes [deploy]"
β¦or the /deploy-preview Claude command in the repo (creates an empty [deploy] commit and pushes it).
Before Pushing
Always pull the latest from develop before pushing to avoid stale previews:
git pull --rebase origin develop
Preview URLs
https://cred-web-commercial-git-<branch>-credai.vercel.app
These are covered by the same Vercel firewall rules as all other environments (see Deployment Guide β Vercel Firewall).
Repo name vs Vercel project name
The GitHub repo is cred-platform-ts (renamed from cred-web-commercial), but the Vercel project is still cred-web-commercial. Workflows that POST to the Vercel API must set gitSource.repo: "cred-web-commercial" (the project's connected-repo identity) and pass the marker via build.env as an object ({ "DEPLOY_DEVELOP": "1" }, not an array). Using the new GitHub name drops PR-context association and the deploy is skipped.
Code Standards
- Follow the Coding Standards guide
- Use ESLint and Prettier for formatting (
bun run lint:fix) - Write tests for new features
- Run
bun run lint && bun run typecheckbefore pushing - Never hand-edit generated GraphQL files β use
bun run gql - PR title format:
{Linear ticket id}: {Linear ticket title}