* ci(terraform-isolation): re-evaluate the gate on label changes * test(terraform-isolation): lock the ci.yaml label-event contract * fix(terraform-isolation): do not treat terraform markdown as a mixed change * fix(ci): do not skip Frontend checks on isolation label events * ci(terraform-isolation): run label retriggers in a dedicated workflow * fix: apply eslint formatting * fix: apply additional missed eslint formatting |
||
|---|---|---|
| .cursor/rules | ||
| .github | ||
| .husky | ||
| config | ||
| docs | ||
| e2e | ||
| eslint-rules | ||
| infra/cdk | ||
| public | ||
| scripts | ||
| src | ||
| terraform | ||
| tmp/pr-descriptions | ||
| .env | ||
| .env.development | ||
| .env.example | ||
| .env.production | ||
| .gitignore | ||
| .prettierignore | ||
| .prettierrc | ||
| AGENTS.md | ||
| ARCHITECTURE_AND_CODE_QUALITY.md | ||
| commitlint.config.js | ||
| eslint.config.js | ||
| index.html | ||
| package-lock.json | ||
| package.json | ||
| playwright.config.ts | ||
| playwright.visual.config.ts | ||
| QUALITY_GATES.md | ||
| README.md | ||
| REVIEW_AND_PR_FRAMEWORK.md | ||
| tsconfig.json | ||
| tsconfig.node.json | ||
| vite.config.ts | ||
| vitest.config.ts | ||
SHOC Frontend (shoc-frontend-new)
Vite + React SPA for Sea Haven facility management (SHOC): work orders, vendor
portal, uplifts, and related admin features. This is the selective rebuild of
the legacy SHOC frontend — new code follows the IrisLoan.Admin conventions
documented in docs/ARCHITECTURE_PLAN.md.
- GitHub:
Sea-Haven-Industries/shoc-frontend-new - Hosted at: https://dev.seahaven.com (dev environment; the only environment today)
- Backend API:
https://api.dev.seahaven.com/api(called directly, cross-origin) — source:Sea-Haven-Industries/shoc-backend
Architecture
Static SPA hosting on AWS, provisioned by a CDK app local to this repo
(infra/cdk/). CloudFront serves the built dist/
from a private S3 bucket; the SPA calls the backend directly over HTTPS at
VITE_API_URL (no /api proxy at the CDN — the backend allows CORS).
graph LR
U[Browser] -->|HTTPS dev.seahaven.com| CF[CloudFront]
CF -->|OAC| S3[S3 seahaven-shoc-frontend-dev]
CF -.->|viewer-request fn| FN[SPA rewrite → /index.html]
U -->|HTTPS api.dev.seahaven.com/api CORS| API[SHOC backend API]
GH[GitHub Actions: Deploy dev content] -->|OIDC| ROLE[githubdeploy-shoc-frontend-new-dev]
ROLE -->|s3 sync + invalidation| S3
TF[HCP Terraform shoc-frontend-new-dev] -.->|adopting: bucket, CloudFront, DNS, role| S3
Dev hosting is being adopted from CDK into HCP Terraform (SH-300); see
terraform/README.md for the phase runbook and the
current ownership state.
Frontend stack: React 19, TypeScript, Vite, Tailwind CSS 4 + MUI, TanStack
Query, React Router (via @generouted/react-router), React Hook Form + Zod,
Ky HTTP client. Source layout: src/api/, src/domain/, src/app/ (see the
architecture plan for the keep/discard migration matrix).
AWS Resources
Stack shoc-frontend-dev — CDK, account 396287094661, region
us-east-1. Defined in infra/cdk/lib/frontend-stack.ts.
| Resource | Name | Purpose |
|---|---|---|
| S3 bucket | seahaven-shoc-frontend-dev |
Private origin (BLOCK_ALL, SSE, versioned; OAC-only reads) |
| CloudFront distribution | (stack output DistributionId) |
HTTPS static hosting on dev.seahaven.com, ACM *.seahaven.com |
| CloudFront Function | SpaRewrite |
Viewer-request rewrite of extensionless paths to /index.html (deep links) |
| IAM role | githubdeploy-shoc-frontend-new-dev |
GitHub Actions OIDC deploy role, trust scoped to repo:Sea-Haven-Industries/shoc-frontend-new:ref:refs/heads/dev |
| Route 53 records | A/AAAA apex alias in zone dev.seahaven.com (Z07671212N75U4YLPWZR8) |
Points the custom domain at CloudFront |
No Lambdas, queues, or databases — this stack is static hosting only.
Configuration
Secrets
No Secrets Manager or SSM parameters. AWS access is OIDC only; the deploy role ARNs are deterministic and pinned in the workflows. The one GitHub Actions repo secret is:
| Secret | Purpose |
|---|---|
SENTRY_AUTH_TOKEN |
Source-map upload by scripts/upload-sourcemaps.sh after a deploy |
Environment variables (build-time, VITE_*)
| Variable | Description | Dev value |
|---|---|---|
VITE_API_URL |
Ky API base prefix, baked into the build at vite build |
/api (dev server) / https://api.dev.seahaven.com/api (production build) |
VITE_API_TARGET |
Dev-proxy target for /api (Vite dev server only) |
http://localhost:5141 |
VITE_API_URL supplies the full API prefix — route paths in API_PATHS do
not include /api. Absolute values must end with /api;
vite.config.ts enforces this via config/api-url-contract.ts and fails the
build otherwise. See .env.example,
.env.development, and .env.production.
CDK context (domain, certificate ARN, hosted zone) lives in
infra/cdk/cdk.json so an administrator runs
cdk deploy with no flags.
Local Development
Requirements: Node.js ≥ 22.22.1 (CI/CD run Node 24), npm 11.16.0 (pinned via
packageManager).
npm ci
cp .env.example .env # then set VITE_API_URL=/api for local dev
npm run dev # Vite dev server on port 3000, proxies /api → VITE_API_TARGET
The dev proxy expects the shoc-backend API at http://localhost:5141;
override with VITE_API_TARGET (e.g. https://api.dev.seahaven.com to use
the deployed dev API).
| Command | Description |
|---|---|
npm run dev |
Start Vite dev server on port 3000 |
npm run build |
Type-check (tsc -b) and production build to dist/ |
npm run preview |
Preview the production build locally |
npm test / npm run test:watch |
Vitest unit tests (once / watch) |
npm run test:e2e / npm run test:e2e:ui |
Playwright e2e tests (headless / UI mode) |
npm run lint / npm run lint:fix |
ESLint (check / auto-fix) |
npm run format / npm run format:check |
Prettier (write / check) |
npm run governance |
Governance checks (godfile, maintainability, Terraform, CDK) |
npm run verify |
All gates: format + lint + build + test + governance |
npm run governance needs terraform and python3 on PATH for the
Terraform gates (npm run test:terraform, npm run test:terraform-import-plan,
npm run test:terraform-isolation) and installs infra/cdk for
npm run test:infra.
Husky + lint-staged run ESLint and Prettier on staged files at commit;
commitlint enforces conventional commit messages. Run npx tsc --noEmit (or
npm run build) before pushing to catch type errors early.
Contributing
- Branch from
devwith a kebab-case description and a prefix matching the work:feature/,bug/,hotfix/,chore/,docs/, orrefactor/(e.g.feature/vendor-portal-filters,chore/sea-haven-branding). - Commit messages follow Conventional Commits — commitlint rejects anything else at commit time.
- Open PRs against
dev. Bothdevandmainare protected: every PR needs a green CI run and an approving review from a code owner (@Sea-Haven-Industries/internal-dev); new pushes dismiss stale approvals. Merged branches are deleted automatically. - A PR that changes
terraform/**may not also change application code (theterraform-isolationCI job); ship Terraform in its own PR. - Promotion flow:
feature/* → dev(deployed todev.seahaven.comthrough the Deploy dev content workflow while the Terraform adoption is in progress)→ main(production promotion — no prod environment exists yet).
Deployment
No stored AWS keys — OIDC only. Infrastructure and content deploy separately:
- CI (
.github/workflows/ci.yaml) — on push and PRs tomain/dev/staging, callsSea-Haven-Industries/.github→ci-typescript-frontend.yaml(Node 24): format check, lint, build, tests; and runs a repo-ownedgovernancejob that callsnpm run verifyso every gate (including the maintainability ratchets inscripts/governance-check.mjs, the Terraform gates, and the CDK template tests) is guaranteed from this repository. Conventions and gates are documented underAGENTS.md,QUALITY_GATES.md,ARCHITECTURE_AND_CODE_QUALITY.md, andREVIEW_AND_PR_FRAMEWORK.md. - Terraform isolation
(
.github/workflows/terraform-isolation.yaml) — fails a PR that mixesterraform/**with application code, so a Terraform merge never races a content release for the HCP workspace. - Dev content (
.github/workflows/deploy.yml) —workflow_dispatchondevonly while the Terraform adoption is in progress. Runsnpm run verify, assumesgithubdeploy-shoc-frontend-new-dev, and runsscripts/deploy-web.sh:npm run build,aws s3 sync dist/(hashed assets immutable,index.htmlnever cached), CloudFront invalidation, then uploads source maps and checks the servedindex.htmlmatches the build. Push-to-devreleases return with the Terraform content-CD change. - Staging content
(
.github/workflows/deploy-staging.yml) — on push tostaging, unchanged. - Infrastructure — administrator-run. Dev: the CDK retain/transfer sequence
and the HCP Terraform workspace
shoc-frontend-new-dev(terraform/README.md). Staging:cdk deploy(infra/cdk/README.md).
Manual content deploy (emergency/reference only — needs credentials for the external-dev AWS account):
SITE_BUCKET=seahaven-shoc-frontend-dev CLOUDFRONT_DISTRIBUTION_ID=E2CWLM1AFB964P \
AWS_REGION=us-east-1 bash scripts/deploy-web.sh
Operations
- Verify: open https://dev.seahaven.com after a green Deploy dev content run in the Actions tab; confirm a deep link (e.g. a work-orders route) loads directly and API calls succeed.
- Logs: deploy logs live in GitHub Actions (CI + Deploy workflows). There are no CloudWatch application logs — the stack is static hosting; runtime errors surface in the browser and on the backend API's side.
- Common failure modes:
- Stale content after deploy — the CloudFront invalidation step failed or
is still propagating; re-run the Deploy workflow or invalidate
/*manually. - OIDC
AssumeRoleerrors — the trust policy is scoped to thedevref on this repo; dispatching the workflow from another branch is rejected by design. - Broken API requests after a build —
VITE_API_URLmissing the/apisuffix or carrying the wrong environment's host (it is baked in at build time). - CORS errors — the backend must allow the frontend origin; CloudFront does
not proxy
/api.
- Stale content after deploy — the CloudFront invalidation step failed or
is still propagating; re-run the Deploy workflow or invalidate
- Dev has no push-triggered deploy during the adoption. Merging to
devruns CI only; publish through the Deploy dev content workflow. Merging aterraform/**change also queues an HCP Terraform run that a human confirms or discards (see the operational rules interraform/README.md).
Documentation
- Infra one-time setup and stack details:
infra/cdk/README.md - Dev Terraform adoption runbook:
terraform/README.md - Rebuild strategy and conventions:
docs/ARCHITECTURE_PLAN.md; design system and UI docs underdocs/