New Project Onboarding

When you spawn a new project from this monorepo starter template, you need to register it with the WS.Eng tooling so that the CLI, codemap, context packs, and documentation workflows all work correctly.

This guide covers the steps to go from a freshly forked/cloned repo to a fully integrated WS.Eng project.

Prerequisites

  • WS.Eng CLI installed and linked globally (wseng --help to verify). See ws-eng-cli README for installation.
  • GitHub CLI (gh) authenticated with access to the trilogy-group organization.
  • Access to the WS.Eng AWS account (856284715153) with a configured AWS CLI profile.

Step 1: Replace Placeholders

Follow the Setup instructions in the README to replace all template placeholders:

  • ws-mono-st → your short project name (max 12 chars, lowercase, dash-separated)
  • wseng-monorepo-starter → your full project name
  • WS.Eng Monorepo Starter → your project display name

Step 2: Initialize the WS.Eng CLI

From the root of your new repository:

wseng init

This command does several things:

  1. Creates .wseng in the repo root if it doesn't already exist (the starter template ships with one, so init will skip this step and preserve the existing file).
  2. Configures your local environment: sets up AWS credentials, Google auth, and Cursor CLI tools.
  3. Adds entries to .gitignore: .context, .aider*, .vscode/settings.json.
  4. Registers the repo in your personal CLI config (localPaths): maps the repo name to its local path. This is critical — wseng ws build-codemap uses localPaths to discover repositories when run outside a git repo.

Verify and Update the .wseng Configuration

After initialization, open the .wseng file in the repo root. The starter ships with default values, but you need to customize it for your project:

{
  "contextFolder": ".context",
  "specs": [],
  "pullRequestTemplate": "{{ ticketUrl }}",
  "defaultGitHubRepo": "your-project-name",
  "commandConfigurations": {
    "release-notes": {
      "defaultInputs": {
        "chatSpace": "Your Chat Space Name",
        "workflowName": "Deploy Production"
      }
    }
  }
}

Key fields to configure:

  • defaultGitHubRepo: Set this to your repository name (e.g., your-project) so ticket commands can resolve numeric-only IDs without the repo/ prefix. This field is not included in the default template — you must add it manually.
  • contextFolder: Defaults to ".context". This is where the CLI stores per-ticket working state (estimations, ticket metadata). It is not where context packs live (see Step 3).
  • commandConfigurations.release-notes: Update the chatSpace to your project's Google Chat space name.

Step 3: Create Context Packs

Context packs are Markdown files with YAML front matter that describe your project's products, modules, and playbooks. The CLI discovers them by filename pattern from anywhere in the repository — they are not stored in a single config file. Place them in your docs/ directory (or any subdirectory) for discoverability.

How Context Packs Are Discovered

The CLI scans the entire repository root for files matching these glob patterns:

Pattern Level Purpose
**/L1.*.md Product Defines a product (top-level domain)
**/L2.*.md Module Defines a module within a product
**/L3.*.md Function Documents a specific function within a module
**/PB.*.md Playbook Defines a runbook/playbook for a product

Files matching **/*template.md are excluded.

L1 — Product Context Pack (Required)

Every project needs at least one L1 file. This defines the product that the codemap and CLI commands reference.

Filename: L1.<product-name>.context.md (e.g., L1.my-project.context.md)

Required front matter:

---
type: product
name: my-project
description: 'A brief description of your product'
docsRoot: docs/
scripts:
  check: []
  fix: []
  test: []
files:
  cicd:
    include: ['.github/**']
  docs:
    include: ['docs/**']
  iac:
    include: ['apps/infra/**']
---
Field Required Description
type Yes Must be "product"
name Yes Product name (used as the key in the codemap)
description No Human-readable description
docsRoot No Root directory for documentation files
scripts No check, fix, test script arrays (each entry has cwd and script)
files No Glob patterns for cicd, docs, iac file categories

The Markdown body below the front matter is the product's context content — used by the CLI when generating code or answering questions.

L2 — Module Context Pack (Required for Codemap Modules)

Each module in your project gets an L2 file. Modules must reference an existing L1 product by name.

Filename: L2.<module-name>.context.md (e.g., L2.backend.context.md)

Required front matter:

---
type: module
name: backend
product: my-project
description: 'Hono REST API backend with DynamoDB'
scripts:
  check: []
  fix: []
  test:
    - cwd: '.'
      script: 'pnpm test'
files:
  sources:
    include: ['apps/backend/**']
    exclude: ['apps/backend/**/*.test.ts']
  cicd:
    include: []
  docs:
    include: []
  iac:
    include: ['apps/infra/constructs/backend.construct.ts']
---
Field Required Description
type Yes Must be "module"
name Yes Module name (must be unique within the product)
product Yes Must match the name of an L1 product context pack
description No Human-readable description
files.sources Yes Glob patterns for this module's source files (include/exclude)
files.cicd, files.docs, files.iac No Glob patterns for related file categories
scripts No check, fix, test script arrays

L3 — Function Context Pack (Optional)

L3 files document individual functions within a module. They do not require YAML front matter — the CLI identifies the product and module from the filename.

Filename pattern: L3.<module-name>.<function-name>.context.md

Example: L3.backend.create-user.context.md

The CLI matches <module-name> to an existing L2 module. If no module match is found but only one product and one module exist in the repo, the L3 file is auto-associated with them.

PB — Playbook Context Pack (Optional)

Playbooks document operational procedures, troubleshooting runbooks, or process guides.

Filename: PB.<playbook-name>.md (e.g., PB.deployment-rollback.md)

Required front matter:

---
type: playbook
name: deployment-rollback
product: my-project
description: 'How to roll back a failed production deployment'
---
Field Required Description
type Yes Must be "playbook"
name Yes Playbook name
product Yes Must match the name of an L1 product context pack
description No Human-readable description

Place context packs inside docs/ to keep them organized and co-located with your project documentation:

docs/
├── L1.my-project.context.md        # Product definition
├── L2.backend.context.md           # Backend module
├── L2.frontend.context.md          # Frontend module
├── L2.infrastructure.context.md    # Infrastructure module
├── L3.backend.create-user.context.md  # Function-level (optional)
├── PB.deployment-rollback.md       # Playbook (optional)
├── guides/                         # Scalar documentation guides
│   ├── introduction.md
│   └── ...
└── assets/

Additional Context Sources

  • Cursor rules in .cursor/rules/ also act as context for AI-assisted development. The starter includes rules for naming conventions, dependency injection, backend patterns, and more. Review and customize these for your project.
  • Additional document types can be placed in named subdirectories (second-brains/, quality-bars/, playbooks/, brain-lifts/) for discovery by the sync-context-documents command.

Step 4: Build the Codemap

The codemap is a structural index that maps your repository's products and modules. The CLI uses it for code navigation, dependency analysis, and AI-assisted development.

Prerequisites

Before building the codemap, you must have created:

  1. At least one L1 (product) context pack with valid front matter (type: product, name)
  2. At least one L2 (module) context pack with valid front matter (type: module, name, product)

The build-codemap command calls loadMetadataFromContextPacks() which parses L1 and L2 files (L3 files are skipped during codemap generation). For each L1 file, it creates a CodeMapProduct entry; for each L2 file, it creates a CodeMapModule entry linked to its product.

Building the Codemap

From the repository root:

wseng ws build-codemap

This will:

  1. Scan the repository for L1 and L2 context pack files
  2. Parse their YAML front matter to extract product and module metadata
  3. Build a codemap structure: { repo → { products, modules } }
  4. Push the codemap to GitHub (via the CodemapService)

If you are not inside a git repository when you run this command, it will instead scan all repositories defined in your personal CLI configuration (localPaths).

Verify Before Pushing

Run without pushing to verify the codemap locally first:

wseng ws build-codemap --no-push

What the Codemap Contains

For each repository, the codemap records:

Entity Fields Source
Product name, description, url, repo, modules[] L1 context pack front matter
Module name, product, description, url, repo L2 context pack front matter

The codemap enables commands like:

  • wseng context-tree — Generate dependency trees for files
  • wseng question — Answer questions about the codebase
  • wseng implement — AI-assisted implementation using codebase understanding

When to Rebuild

Rebuild the codemap after:

  • Adding or removing L1/L2 context pack files
  • Renaming products or modules in context pack front matter
  • Adding new workspace packages or backend modules
  • Major refactors that change directory structure

Step 5: Register in the Team Roster

The WS.Eng Team Roster is a Google Sheet that tracks all active projects, their repositories, and team assignments. Your project must be registered here for cross-project CLI commands to work (e.g., wseng ws clone-repositories, wseng sync-context-documents, wseng ws project-updates).

Access: The Team Roster requires membership in the WorkSmart Engineering Google group. If you don't have access, request it in the "WS.Eng Access Requests" Google Chat space.

Adding Your Project

There is no CLI command to add entries to the Team Roster — it is managed manually in the Google Sheet. You will need to add rows to the following sheets:

  1. Projects sheet — Optional, add a row with:

    • ID: A unique project identifier (e.g., YourProject)
    • Short Name: An abbreviation (e.g., YP)
    • Friendly Name: Human-readable project name
    • Company: The parent company
    • Product: The product name (should match the name in your L1 context pack)
  2. Repositories sheet — Add a row for your new repository with:

    • Name: Repository name (e.g., your-project)
    • Description: Brief description
    • URL: Full GitHub URL (e.g., https://github.com/trilogy-group/your-project)
    • Type: Repository type
    • Project: Must match the Project ID from the Projects sheet

After Registration

Once registered, team members can clone all project repositories at once:

wseng ws clone-repositories

Registration also enables the wseng sync-context-documents command to discover your repository's context packs and catalog them in the Team Roster's "Context Documents" sheet. This is a team-level maintenance command (not a project setup step) that scans all registered repositories for L1/L2/L3 context pack files and documents in second-brains/, quality-bars/, playbooks/, and brain-lifts/ directories.

Step 6: Set Up Scalar Documentation

Documentation is published to Scalar for both production and integration environments. Each environment gets its own Scalar project, custom domain, and environment-specific configuration (API URL, OAuth, logo). Ephemeral (PR) environments do not publish docs. The Scalar projects, CNAMEs, and logo bucket are one of the out-of-repo identities tracked in the External Identity Inventory.

6a. Create Scalar Projects

Two Scalar projects are needed — one for production, one for integration. Scalar does not support project deletion via CLI or API, so these are permanent.

Prerequisites: Node.js 24+, @scalar/cli installed globally.

npm i -g @scalar/cli

# Authenticate with the team Scalar token (obtain from Scalar dashboard or AWS Secrets Manager)
npx @scalar/cli auth login --token=<SCALAR_TOKEN>

# Create production project
npx @scalar/cli project create --name "Your Project Docs" --slug your-project-docs

# Create integration project
npx @scalar/cli project create --name "Your Project Docs (Integration)" --slug your-project-docs-int

6b. Add DNS CNAME Records

Add two CNAME records in your project's Route 53 hosted zone, both pointing to dns.scalar.com:

Record Name Type Value
your-project-docs.<your-domain> CNAME dns.scalar.com
your-project-docs-int.<your-domain> CNAME dns.scalar.com

For reference, the monorepo starter uses the wseng.rp.devfactory.com hosted zone in AWS account 856284715153.

6c. Configure Custom Domains in Scalar Dashboard

DNS alone is not sufficient — Scalar must also be told about the custom domains:

  1. Go to https://dashboard.scalar.com
  2. Open the production project → Settings → Custom Domain → enter your-project-docs.<your-domain>
  3. Open the integration project → Settings → Custom Domain → enter your-project-docs-int.<your-domain>

6d. Prepare Logo Assets

Logos are stored in an S3 bucket and referenced by URL. Prepare two logos:

  • Production logo (docs/assets/logo.svg) — default branding
  • Integration logo (docs/assets/logo-int.svg) — should include a visual "STAGING" indicator to distinguish from production

6e. Update .doc.json

Update the configuration to match your project:

{
  "meta": {
    "title": "Your Project Docs",
    "description": "Documentation for Your Project.",
    "logo": "https://wseng-docs.s3.us-east-1.amazonaws.com/scalar/assets/<your-project>/logo.svg"
  },
  "content": {
    "references": [
      {
        "type": "openapi",
        "slug": "api-reference",
        "name": "API Reference",
        "specPath": "https://api-<your-project>.<your-domain>/docs/openapi.json",
        "config": {
          "ignoreTags": ["Debug"]
        }
      }
    ],
    "assetsDir": "docs/assets"
  },
  "targets": {
    "scalar": {
      "projectSlug": "your-project-docs",
      "customDomain": "your-project-docs.<your-domain>"
    }
  }
}

Key fields to update:

  • meta.title and meta.description — your project name
  • meta.logo — S3 URL from step 6d
  • specPath — your production API's OpenAPI endpoint
  • targets.scalar.projectSlug — must match the slug from step 6a
  • targets.scalar.customDomain — must match the domain from step 6b/6c

6f. Update Workflow Overrides

In base-deploy.yml, the publish-docs job dynamically generates overrides for each environment. Update the "Compute Scalar overrides" step with your project's integration domain and the "Generate overrides file" step with your integration logo URL.

6g. Update .doc.overrides.env for Local Publishing

The .doc.overrides.env file is committed to the repo so the whole team can publish staging/integration docs from their local machine. Update it with your project's integration-specific values:

targets.scalar.projectSlug=your-project-docs-int
targets.scalar.customDomain=your-project-docs-int.<your-domain>
references.api-reference.specPath=https://api-<your-project>-integration.<your-domain>/docs/openapi.json
meta.logo=https://wseng-docs.s3.us-east-1.amazonaws.com/scalar/assets/<your-project>/logo-int.svg

Then publish locally with:

wseng cicd publish-docs --overrides .doc.overrides.env

To publish to production instead, omit the --overrides flag (.doc.json defaults are used):

wseng cicd publish-docs

6h. Trigger Initial Deploys

Before merging, publish both docs sites once via the CLI to ensure the Scalar projects are populated and custom domains are active:

# Publish production docs (uses .doc.json defaults)
wseng cicd publish-docs

# Publish integration docs (uses overrides)
wseng cicd publish-docs --overrides .doc.overrides.env

After merging the docs configuration to main, CI takes over:

  1. Integration docs auto-publish on merge (via deploy-integration.yml)
  2. Production docs require a manual trigger: GitHub → Actions → Deploy Production → Run workflow

Step 7: Seed Your AWS Account

Your AWS account needs shared prerequisites (created once, reused across all environments). The CI deploy pipelines handle this automatically — the deploy orchestrator calls seedAllReservations() before every CDK deploy, so the first pipeline run on a fresh account provisions everything.

For local development, the update-env script handles this automatically — it calls seedAllReservations() internally and upserts the resulting env vars into your .env:

pnpm script update-env --env integration

This is idempotent — policies are content-addressed (wseng-auto-policy-<hash>), so identical configs across projects and environments resolve to the same policy automatically. Stale policies are swept during post-destroy (CloudFront prevents deletion of any policy still attached to a distribution). Currently it provisions:

  • CloudFront Origin Request Policies for Mixpanel and Sentry analytics proxy behaviors (defined in apps/infra/policies/)

Extending: Add new policy entries to ORIGIN_REQUEST_POLICIES in apps/infra/policies/origin-request-policies.constant.ts. The env var is automatically included in destroy-safe synthesis verification.

Step 8: Configure CI/CD

The CI/CD workflows reference specific values that need updating for your project (the secret and analytics/auth credentials they consume are catalogued in the External Identity Inventory):

  1. AWS IAM Role ARN — Update the aws-role default in .github/actions/aws-setup/action.yml (the single home for the deploy-role ARN, inherited by every deploy job) to your project's deploy role. See Deploy Role Permissions for the exact permission set this role needs and a reference least-privilege policy to attach.
  2. Secret ID — Create secrets in AWS Secrets Manager following the structure in the README. All non-production environments (integration, PR/ephemeral, and local dev) intentionally share this one integration secret; per-environment secret scoping is out of scope by design — see the reasoning in the README's Secret Structure section.
  3. Domain and certificate — Update apps/infra/constants/account.constant.ts (HOSTED_ZONE_DOMAIN, ACM_CERTIFICATE_ID); per-environment subdomains stay in apps/infra/app.ts.

If you are deploying to a dedicated AWS account (not the WS.Eng shared account), follow the consolidated checklist in the next section, which supersedes the ad-hoc edits above.

Adopting into a Dedicated AWS Account

The starter defaults to the WS.Eng shared account and works out of the box there — the shipped values (account id, Postgres networking, hosted zone, deploy role, db-helper) are the shared-account defaults, so nothing below is needed for a WS.Eng-account project. This section is only for a fork that deploys to its own dedicated AWS account.

Automatic database provisioning on first deploy is out of scope here (tracked separately); this covers pointing the config surface at your account.

Edit these surfaces, in priority order. The first is the single CDK config surface; the rest are the layers (CI YAML, dotenv, docs JSON, platform config) that cannot import it.

  1. Primary edit — CDK config module apps/infra/constants/account.constant.ts. Set:

    • AWS_ACCOUNT_ID, AWS_REGION
    • POSTGRES_DB_HOST, POSTGRES_VPC_ID, POSTGRES_SECURITY_GROUP_ID (only if you run Postgres — see step 8)
    • HOSTED_ZONE_DOMAIN, ACM_CERTIFICATE_ID

    The certificate ARN and each stack's env.account derive from these automatically — you do not edit apps/infra/app.ts for account values.

  2. CI — deploy role. Update the aws-role default in .github/actions/aws-setup/action.yml to your account's OIDC deploy-role ARN. Every deploy job inherits it. Attach the reference least-privilege policy from Deploy Role Permissions; a CDK-only role fails with AccessDenied in the orchestrator's pre-CDK steps.

  3. CI — database helper. If you keep Postgres, update the db-helper-arn default in .github/actions/create-db-schema/action.yml to your account's provisioning Lambda (or replace the mechanism). Database provisioning itself is tracked separately.

  4. Local env — .env.example and your .env. Set AWS_ACCOUNT_ID and AWS_REGION.

  5. Docs publishing — .doc.json and .doc.overrides.env. Set the Scalar custom domain and the OpenAPI specPath host to your domain (see Step 6).

  6. Local dev tunnel — .nex.json. Set the Postgres tunnel targetHost to your DB host, or remove the tunnel if unused.

  7. CDK context cache — apps/infra/cdk.context.json. Delete the WS.Eng-keyed hosted-zone entry so it regenerates for your account and domain on the next synth with account access. A stale entry is harmless (its account/domain-scoped key simply misses), but keeping WS.Eng identifiers is confusing.

  8. Secrets Manager. Create the ws-mono-st/backend/{integration,production}/secrets entries in your account (see the README Secret Structure section).

  9. Persistence reconciliation. The default is postgres (single source: packages/shared/ts/constants/persistence.constant.ts), which attaches the VPC/security group and expects the DB host above. A dedicated account without an equivalent shared Postgres cluster must either provision equivalent networking and set the three POSTGRES_* values in step 1, or run DynamoDB-only by setting PERSISTENCE=dynamodb (the persistence input on base-deploy.yml, or the persistence:dynamodb PR label for ephemeral environments).

After these edits, grep the repo for the WS.Eng account id, VPC id, security group id, and DB host: every remaining occurrence sits in one of the surfaces above, none loose in apps/infra/app.ts or inline in a workflow step.

External Identity Inventory

The .sync tool rewrites in-repo strings only (packages/sync/utils/replacement.util.ts) and provisions nothing out-of-repo. Every third-party identity below therefore stays the starter's until you recreate it in your own account/console and repoint the in-repo reference — a fresh clone with the sync applied still authenticates, emails, publishes docs, and reports analytics as the starter until you work this list. This is the single "recreate these before go-live" inventory; following it once leaves no external identity pointing at the starter.

Identity What it is Shape / specifics Where the app points at it (repoint target)
AWS Secrets Manager secrets Two secrets holding all runtime credentials. Integration one is shared by integration + every ephemeral + local + CI; production has its own. Names ws-mono-st/backend/integration/secrets and ws-mono-st/backend/production/secrets. JSON shape (MIXPANEL_TOKEN, SENTRY_DSN, TIMEBACK_CLIENT_ID/TIMEBACK_CLIENT_SECRET, GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET, MCP_SERVERS, CHAT_MODEL, plus DB_USERNAME/DB_PASSWORD when running Postgres) is documented in the README Secret Structure section — create both with that shape. Imported by name in CDK (apps/infra/constructs/backend.construct.ts), ids wired in apps/infra/app.ts. .sync renames the ws-mono-st prefix in the secret name only; it never touches the secret contents, so the token/DSN/client values are always yours to fill in.
Google OAuth client + Cognito redirect URI The Google Cloud OAuth 2.0 client that backs "Sign in with Google" via the Cognito user pool. Create the client in Google Cloud Console; put its id/secret in the secret as GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET. Register, once per environment, the Authorized redirect URI https://<APP_NAME>-<env>-userauth.auth.<region>.amazoncognito.com/oauth2/idpresponse (the Cognito hosted-domain prefix is getResourceName(env, 'userauth')). Integration example: https://ws-mono-st-integration-userauth.auth.us-east-1.amazoncognito.com/oauth2/idpresponse. This per-environment registration is why Google login is disabled on ephemeral environments by default (the README notes the same caveat under Extra Features). GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET in the secret (consumed in apps/infra/constructs/backend.construct.ts). The Cognito app-client callback URLs are provisioned by CDK and need no console action; only the Google-side idpresponse redirect URI is manual.
SES verified sending identity The Amazon SES identity transactional email is sent from. Verify the domain or address behind SES_FROM_EMAIL (defaults to no-reply@<domainName>, e.g. no-reply@wseng.rp.devfactory.com; override with the sesFromEmail stack prop). SES rejects sends until the identity is verified; a new account is in the SES sandbox, so request production access to send to unverified recipients. SES_FROM_EMAIL Lambda env (apps/infra/constructs/backend.construct.ts), consumed by SesService (apps/backend/app/common/integrations/aws/services/ses.service.ts). See the README Transactional Email (SES) section.
Scalar docs projects Hosted API-docs projects (production + integration) for the published reference. Two Scalar projects, two custom-domain CNAMEs pointing to dns.scalar.com, the custom domains configured in the Scalar dashboard, a SCALAR_TOKEN for publishing, and logo assets uploaded to the shared wseng-docs S3 bucket. Full procedure in Step 6 — work that step; this row is the inventory pointer. .doc.json (targets.scalar.projectSlug, customDomain, meta.logo, references[].specPath) and .doc.overrides.env for integration.
Mixpanel project + Sentry project Your own analytics (Mixpanel) and error-tracking (Sentry) projects. Create a Mixpanel project (its token → MIXPANEL_TOKEN) and a Sentry project (its DSN → SENTRY_DSN). SENTRY_DSN is read both at runtime and at CDK synth (apps/infra/app.ts) to derive the analytics-proxy origin host, so it must be set in the secret before the first deploy, not only at runtime. MIXPANEL_TOKEN/SENTRY_DSN in the secret; the frontend consumes them via VITE_* build env.

AWS-account infrastructure the fork also needs — Route 53 hosted zone, ACM certificate, deploy-role ARN, and VPC/DB networking — is in-repo config, not a third-party identity, and is covered by Adopting into a Dedicated AWS Account above.

Checklist

Use this checklist when onboarding a new project:

  • Replace all placeholders (ws-mono-st, wseng-monorepo-starter, WS.Eng Monorepo Starter)
    • The .sync/config.json file contains the known patterns that we should use and would be replaced in downstream forks.
  • Run wseng init and configure .wseng
  • Set defaultGitHubRepo in .wseng
  • Create an L1 product context pack (docs/L1.<product>.context.md) with valid front matter
  • Create L2 module context packs (docs/L2.<module>.context.md) for each module
  • Run wseng ws build-codemap --no-push to verify context packs parse correctly
  • Run wseng ws build-codemap to push the codemap to GitHub
  • Ensure access to the WS.Eng Team Roster (join WorkSmart Engineering Google group if needed)
  • Add project to the Team Roster: Projects, Repositories, and People sheets
  • Create Scalar projects for production and integration (scalar project create) — the docs identity in the External Identity Inventory
  • Add DNS CNAME records pointing to dns.scalar.com
  • Configure custom domains in Scalar dashboard for both projects
  • Upload production and integration logos to S3
  • Update .doc.json with project slug, custom domain, spec URL, and logo URL
  • Update base-deploy.yml overrides with integration domain and logo URL
  • Update .doc.overrides.env with integration values for local publishing
  • Run pnpm script update-env --env integration for local dev (seeds account prerequisites and syncs stack outputs)
  • Recreate every external identity before go-live — see External Identity Inventory:
    • Create the two AWS Secrets Manager secrets with the full JSON shape (ws-mono-st/backend/{integration,production}/secrets)
    • Register the Google OAuth client and add the per-environment .../oauth2/idpresponse Authorized redirect URI in Google Cloud Console
    • Verify the SES sending identity for SES_FROM_EMAIL (request production access if sending to real recipients)
    • Point Mixpanel and Sentry at your own projects (MIXPANEL_TOKEN, SENTRY_DSN; SENTRY_DSN is also needed at CDK synth)
  • Dedicated account only: edit apps/infra/constants/account.constant.ts (account id, region, VPC, security group, DB host, hosted zone, certificate id) — see "Adopting into a Dedicated AWS Account"
  • Dedicated account only: update the aws-setup and create-db-schema composite-action defaults (deploy role ARN, db-helper ARN)
  • Dedicated account only: regenerate apps/infra/cdk.context.json for your account/domain
  • Dedicated account only: decide persistence — replicate the Postgres networking or set PERSISTENCE=dynamodb
  • Deploy the integration environment (git push to main)
  • Verify docs publish on first integration deploy