DIWA Checkbox / Technical turnover

DIWA Checkbox Technical Turnover

From the old repository to a working change

This handbook teaches a developer to:

  • find the right code;
  • run the platform locally;
  • make and test a change;
  • debug the first failure;
  • submit it through CodeCommit; and
  • understand how an accepted revision reaches UAT and production.

Operations exercises come after the developer path.

DIWA Checkbox / Technical turnover

How to use this handbook

Each lesson follows the same loop:

  1. Understand the concept and where it lives.
  2. Run the exact command or procedure.
  3. Compare the result with the expected output.
  4. Recover from the common failure.
  5. Practice the smallest useful variation.
  6. Record the result only when evidence is needed.

An output block shows the shape you should expect. Timestamps, IDs, and counts will differ. Record what you actually observe.

DIWA Checkbox / Technical turnover

Contents

  1. Bridge from diwa-checkbox-old
  2. Run the repository locally
  3. Make the first change
  4. Find the right place for a change
  5. Test, migrate, and follow patterns
  6. Run the test layers
  7. Trace and debug one feature
  8. Bonus: recommended CodeCommit workflow
  9. UAT, operations, and acceptance

Command reference · Repository map · Troubleshooting · Evidence and glossary · TypeScript patterns

The evidence workbook is an operational acceptance artifact. It is not required for a developer's first local run.

DIWA CHECKBOX / MODULE 01 / BRIDGE FROM THE OLD REPOSITORY

Module 01 — Bridge from diwa-checkbox-old

Your existing product knowledge is useful. The repository shape and runtime are different enough that copying old assumptions can lead you to the wrong file, command, or deployment target.

DIWA CHECKBOX / MODULE 01 / BRIDGE FROM THE OLD REPOSITORY

What changed since the old repository

Concern Current repository Practical consequence
Package manager Bun workspaces Use Bun commands from the repository root.
API runtime One checkbox-api gateway Normal product routes belong in packages/core/api-*; the gateway binds them to public prefixes.
Web apps React Router SSR apps Routes, loaders, API adapters, and server entrypoints are separate.
Domain code packages/core/feat-* Reusable business behavior belongs in feature packages.
Database access Kysely queries; Drizzle migration/schema support Do not hand-write migration files.
Shared UI packages/shared/util-ui and feature UI packages Prefer shared primitives and package exports.
Deployment source AWS CodeCommit main today Future staging promotion is described later as a target process.

The old repository may still be useful for product terminology and history. It is not the authority for current paths or commands.

DIWA CHECKBOX / MODULE 01 / BRIDGE FROM THE OLD REPOSITORY

Translate the product idea into the current code path

Your product concepts still transfer. The code boundaries do not. When a familiar task arrives, start with the current shape:

If you are thinking about... In this repository, start with...
A dashboard screen apps/admin-web/app/routes.ts → route shell → packages/core/feat-admin-app-ui
A browser API call App feature adapter → checkbox-apipackages/core/api-admin
Business behavior packages/core/feat-*, not a large transport handler
A database query Kysely through the owning dbMain or dbAuth client
A schema change The owning db-* package and its generated migration
A shared component The public export from packages/shared or the owning feature package

The useful shift is from “which controller or model is this?” to “which boundary owns this behavior?”

DIWA CHECKBOX / MODULE 01 / BRIDGE FROM THE OLD REPOSITORY

The current runtime in one picture

Current AWS runtime topology with web apps, checkbox-api, EC2, Aurora, S3, SQS, SES, and deployment services

Legend: green = AWS-managed service; purple = DIWA application; white = user or external entry point.

For local work, replace AWS-managed services with Docker Postgres and LocalStack. For production work, use the maintained assets under deploy/aws.

DIWA CHECKBOX / MODULE 01 / AWS SERVICES AND APPLICATION COMPONENTS

AWS services vs application components

The topology mixes AWS infrastructure with DIWA code and general platform concepts. This distinction tells you which repository or console to inspect next.

Item AWS-managed? Plain-language role
ACM + ALB Yes TLS certificates and public traffic routing.
EC2 Yes Virtual machine hosting the Docker Compose runtime.
Aurora + private S3 Yes Relational data and uploaded objects.
SQS + SES Yes Notification queue and outbound email.
Secrets Manager + ECR + CloudWatch + SSM Yes Configuration, image registry, logs/metrics, and instance operations.
Web surfaces + checkbox-api No DIWA application code running on EC2.
notifications worker No DIWA background process consuming notification jobs.
Browsers + DNS + Docker Compose No User client, naming concept, and runtime tool. DNS may be provided by AWS Route 53 or another provider.

When tracing a problem, first identify the boundary: browser, public AWS edge, EC2 runtime, DIWA process, AWS data service, or external email delivery.

DIWA CHECKBOX / MODULE 01 / AWS SERVICES AND APPLICATION COMPONENTS

Repository map

diwa-checkbox/
├── monorepo/apps/                 web apps, checkbox-api, worker, demos
├── monorepo/packages/core/        domain features, API actors, databases
├── monorepo/packages/shared/      UI and cross-cutting utilities
├── tests/                         UAT manifests and Playwright specs
├── tools/                         repository-owned scripts and checks
├── deploy/local/                  Docker Postgres and LocalStack
├── deploy/aws/                    AWS deployment source and runbooks
└── docs/                          maintained engineering and turnover docs

Start at the root README.md for orientation. Start at docs/turnover/local-development.md for the shortest current local path. Use this handbook to learn why those paths exist.

DIWA CHECKBOX / MODULE 01 / AWS SERVICES AND APPLICATION COMPONENTS

Where to look when you need to change something

Need Start here Do not start here
Web page or route monorepo/apps/-web/app/routes.ts and the app feature folder checkbox-api
Browser API adapter monorepo/apps/-web/app/features/.../api/ API route handler
Domain API endpoint monorepo/packages/core/api-/src/ A new endpoint in checkbox-api
Business logic monorepo/packages/core/feat-* Large logic blocks in transport handlers
Main database query monorepo/packages/core/db-main or the owning feature method A web loader with direct SQL
Auth/session database monorepo/packages/core/db-auth db-main by assumption
Shared component monorepo/packages/shared/util-ui or an owning UI package A copied one-off primitive
Unit or pure helper test Beside the source as *.spec.ts or *.spec.tsx A mock-heavy integration test
Browser workflow tests/uat/specs/ and its manifest A unit test pretending to be a browser
Deployment or recovery deploy/aws/ and the matching docs runbook A local app README
DIWA CHECKBOX / MODULE 01 / AWS SERVICES AND APPLICATION COMPONENTS

Checkpoint: choose the next repository boundary

A ticket asks you to change the Recent Questions heading on the admin dashboard.

Before editing, answer these questions:

  1. Where would you search first?
  2. Which package owns the visible text?
  3. If the browser still shows the old text, which boundary would you check next?
  4. What evidence would confirm your answer?

Pause here. Say the path aloud or write a short answer before continuing.

DIWA CHECKBOX / MODULE 01 / AWS SERVICES AND APPLICATION COMPONENTS

Answer: start at the first useful boundary

For a static heading, the expected path is:

browser
  → admin-web route/shell
  → feat-admin-app-ui page
  → browser result

Start with a repository search:

rg -n --fixed-strings 'Recent Questions' monorepo

For this marker, no API or database change is required. If the heading changes but the list data is wrong, continue through checkbox-apiapi-admindb-main.

Good reasoning identifies the next boundary and the evidence that would confirm it. Do not trace to the database when the requested change is only static UI text.

DIWA CHECKBOX / MODULE 02 / RUN THE REPOSITORY LOCALLY

Module 02 — Run the repository locally

The first useful result is a working browser screen. Setup is complete only when the API responds, the web app loads, and local authentication can reach the same gateway.

DIWA CHECKBOX / MODULE 02 / RUN THE REPOSITORY LOCALLY

Check the machine before installing

From the repository root:

bun run setup:doctor

Expected result shape:

PASS  bun                 Found Bun 1.3.9
PASS  lockfile            bun.lock matches the root workspace
WARN  dependencies        node_modules is missing
PASS  docker              Docker daemon is reachable
PASS  port:8787           Port is available

The exact list depends on your machine. Missing node_modules before installation is normal. A missing Bun version, unavailable Docker daemon, or occupied required port needs attention.

DIWA CHECKBOX / MODULE 02 / RUN THE REPOSITORY LOCALLY

Setup doctor: common failures

Output Meaning Next action
Expected Bun 1.3.9 Wrong Bun version Install or switch to the version in package.json.
node_modules is missing Dependencies are not installed Run bun install --frozen-lockfile.
Docker daemon unavailable Docker is installed but not running Start Docker Desktop, then rerun doctor.
Port is occupied Another service owns the fixed port Stop the intended stale process or use normal port cleanup.
Less than 5 GiB free Full UAT artifacts may fail Free disk before running browser evidence.

Do not skip a failed prerequisite and interpret an application error as the root cause.

DIWA CHECKBOX / MODULE 02 / RUN THE REPOSITORY LOCALLY

Install the exact workspace graph

bun install --frozen-lockfile

Expected result shape:

bun install v1.3.9
Resolving dependencies
Saved lockfile

The important result is that the command exits successfully without changing bun.lock.

If Bun proposes a lockfile change, stop and check the Bun version before committing anything.

DIWA CHECKBOX / MODULE 02 / RUN THE REPOSITORY LOCALLY

Bootstrap local infrastructure, environment, and data

bun run dev:bootstrap

This runs the repository-owned sequence:

dev:infra
→ wait for Postgres and LocalStack
→ dev:env from local development templates
→ migrate db-main
→ migrate db-auth
→ seed db-main
→ seed local superadmin accounts

This local path does not require AWS Secrets Manager. bun run secrets is a separate AWS-backed path for managed values.

DIWA CHECKBOX / MODULE 02 / RUN THE REPOSITORY LOCALLY

Bootstrap: expected output and stop points

Expected output shape:

[dev:bootstrap] dev:infra
[dev:bootstrap] wait:postgres
[dev:bootstrap] wait:localstack
[dev:bootstrap] dev:env
[dev:bootstrap] migrate:db-main
[dev:bootstrap] migrate:db-auth
[dev:bootstrap] seed:db-main
[dev:bootstrap] seed:diwa-superadmins

If a step fails, preserve the first failing step and its original error. Do not start all web apps and create unrelated errors on top of it.

DIWA CHECKBOX / MODULE 02 / RUN THE REPOSITORY LOCALLY

Bootstrap: common failures

Failure Check first Safe recovery
Postgres connection refused docker ps and port 55432 Start Docker or run bun run dev:infra.
LocalStack connection refused Port 4566 and Docker logs Restart local infra, then rerun bootstrap.
Migration already applied migrate:list in the affected DB package Do not delete migration files; inspect state.
Duplicate seed data Reused local volumes If data can be discarded, run dev:infra:reset, then bootstrap.
Missing .env values dev:env output Regenerate local files; never copy UAT or production env files.
DIWA CHECKBOX / MODULE 02 / RUN THE REPOSITORY LOCALLY

Start the API and authentication

Use two terminals. Each command is long-running, so leave both terminals open.

Terminal 1 — API gateway:

cd monorepo/apps/checkbox-api
bun run dev

Terminal 2 — authentication:

cd monorepo/apps/auth-web
bun run dev

Expected result shape:

checkbox-api: listening on http://localhost:8787
auth-web:     Local: http://localhost:5176/

The exact wording depends on the app runner; the ports are the useful check. If either terminal exits, capture the first error before trying another command.

DIWA CHECKBOX / MODULE 02 / RUN THE REPOSITORY LOCALLY

Start the admin web

Open a third terminal. Keep the API and authentication terminals running.

cd monorepo/apps/admin-web
bun run dev

Expected result:

admin-web:    Local: http://localhost:5173/

If the terminal exits, check the compile output, missing environment variables, and whether port 5173 is already in use. Do not proceed to the browser until the process stays running.

When all three processes are alive, continue to the API health check before opening the application.

DIWA CHECKBOX / MODULE 02 / RUN THE REPOSITORY LOCALLY

Confirm the API before opening the browser

curl -sS http://localhost:8787/health

Expected result:

{"status":"ok","service":"checkbox-api"}

Then open:

Admin: http://localhost:5173
Auth:  http://localhost:5176

If health fails, debug checkbox-api and local environment values before debugging the browser app.

DIWA CHECKBOX / MODULE 02 / RUN THE REPOSITORY LOCALLY

Sign in locally without sharing credentials

Use the local account generated by the approved seed path when the exercise requires a role-specific workflow.

bun run monorepo/scripts/seed-diwamail-accounts.ts

Expected result shape:

Created local-only accounts
Wrote credentials to outputs/diwamail-accounts/

Read credentials locally. Do not paste them into the handbook, evidence, chat, screenshots, or commits. If authentication redirects to the wrong host, check AUTH_API_URL, AUTH_WEB_URL, and ALLOWED_REDIRECT_ORIGINS.

DIWA CHECKBOX / MODULE 02 / RUN THE REPOSITORY LOCALLY

Stop, reset, and restart local infrastructure

Stop containers while keeping local data:

bun run dev:infra:down

Discard local containers and data:

bun run dev:infra:reset

Expected result shape:

[dev:infra] stopped local services
[dev:infra] reset completed

Reset is destructive to local data. Never use it as a first response to a failed test unless duplicate or stale data is the suspected cause.

DIWA CHECKBOX / MODULE 02 / RUN THE REPOSITORY LOCALLY

Checkpoint: prove one working screen

Complete this sequence:

[ ] setup doctor reviewed
[ ] dependencies installed
[ ] local bootstrap completed
[ ] checkbox-api health returned 200
[ ] admin-web loaded on :5173
[ ] auth-web was available on :5176
[ ] local sign-in path was confirmed or intentionally blocked

Exit condition: you can restart the API and admin web independently without asking which directory or port to use.

This is a hands-on checkpoint. The terminal output, browser URL, and sign-in result are the answer; there is no separate answer slide to memorize.

DIWA CHECKBOX / MODULE 03 / MAKE THE FIRST CHANGE

Module 03 — Make the first change

The exercise uses a harmless visible marker because immediate browser feedback is easier to interpret than a complex feature change.

The same workflow applies to a real ticket later.

DIWA CHECKBOX / MODULE 03 / MAKE THE FIRST CHANGE

Start from a known branch state

git fetch origin main
git switch main
git pull --ff-only origin main
git status --short --branch
git branch --show-current

Expected clean shape:

## main...origin/main
main

If switching or pulling would overwrite local work, stop. If you see modified files that are not yours, preserve them. Do not use git reset --hard or git checkout -- to make the tree look clean.

DIWA CHECKBOX / MODULE 03 / MAKE THE FIRST CHANGE

Create a short-lived working branch

For the exercise:

git switch -c feat/turnover-dashboard-marker
git branch --show-current

Expected result:

Switched to a new branch 'feat/turnover-dashboard-marker'
feat/turnover-dashboard-marker

If the branch already exists, use git switch feat/turnover-dashboard-marker only after confirming it contains the intended work. Do not reuse another developer's branch.

DIWA CHECKBOX / MODULE 03 / MAKE THE FIRST CHANGE

Find the component that owns the visible text

From the repository root:

rg -n --fixed-strings 'Recent Questions' monorepo

Expected result shape:

monorepo/packages/core/feat-admin-app-ui/src/feat-dashboard/pages/overview.page.tsx:...

Open the matching file and confirm the text is inside the dashboard component. A search result is a lead; reading the surrounding component is the confirmation.

DIWA CHECKBOX / MODULE 03 / MAKE THE FIRST CHANGE

Why the component is in a package

admin-web route shell
  supplies runtime URLs and services
        │
        ▼
feat-admin-app-ui package
  owns reusable dashboard UI
        │
        ▼
checkbox-api → api-admin → db-main

Change the text at the owning package. Do not duplicate the component in admin-web just because the browser starts there.

DIWA CHECKBOX / MODULE 03 / MAKE THE FIRST CHANGE

The page component owns visible UI

This is the kind of TypeScript/JSX you should expect at the feature boundary:

function EncoderDashboardComponent({
  dashboard,
  onNavigate,
}: {
  dashboard?: EncoderDashboard;
  onNavigate: (href: string) => void;
}) {
  return (
    <div>
      <h2>Recent Questions</h2>
      {/* render dashboard.recentActivity.recentQuestions here */}
    </div>
  );
}

This component renders UI. It does not register /dashboard, bind the public API prefix, or query the database directly.

DIWA CHECKBOX / MODULE 03 / MAKE THE FIRST CHANGE

Make one visible change

Edit only:

monorepo/packages/core/feat-admin-app-ui/src/feat-dashboard/pages/overview.page.tsx

Change:

-Recent Questions
+Recent Questions · Turnover Check

Do not change data, API requests, styles, configuration, dependencies, or unrelated files for this exercise.

DIWA CHECKBOX / MODULE 03 / MAKE THE FIRST CHANGE

Verify the browser result

Refresh:

http://localhost:5173/dashboard

Expected result:

Recent Questions · Turnover Check

The text proves the edited UI code is being served. It does not prove that the API request or database read works. Confirm the dashboard request separately in the browser Network panel.

DIWA CHECKBOX / MODULE 03 / MAKE THE FIRST CHANGE

When the browser does not show the change

Check in this order:

  1. Did the browser load the expected port 5173?
  2. Did the file save at the expected path?
  3. Does git diff -- show the change?
  4. Is the running process the current admin-web process?
  5. Did the terminal report a compile or route error?
  6. Is the visible heading rendered by another component?

Do not change a second file until the first failure is understood.

DIWA CHECKBOX / MODULE 03 / MAKE THE FIRST CHANGE

Inspect the intended diff

git diff -- monorepo/packages/core/feat-admin-app-ui/src/feat-dashboard/pages/overview.page.tsx

Expected shape:

- Recent Questions
+ Recent Questions · Turnover Check

If the diff contains generated files, env files, lockfile changes, or unrelated edits, stop and separate those changes before staging.

DIWA CHECKBOX / MODULE 03 / MAKE THE FIRST CHANGE

Commit only the intended file

git add monorepo/packages/core/feat-admin-app-ui/src/feat-dashboard/pages/overview.page.tsx
git diff --cached --check
git commit -m "chore: add dashboard turnover marker"
git rev-parse HEAD

Expected result shape:

[feat/turnover-dashboard-marker abc1234] chore: add dashboard turnover marker
1 file changed, 1 insertion(+), 1 deletion(+)
<40-character commit SHA>

If the staged diff is wrong, unstage the file with git restore --staged . Do not rewrite or delete unrelated working changes.

DIWA CHECKBOX / MODULE 03 / MAKE THE FIRST CHANGE

Checkpoint: prove your first change

You have completed this module when you can show:

Branch:       feat/turnover-dashboard-marker
Changed file: overview.page.tsx
Browser:      marker visible locally
Diff:         one intended line
Commit:       full SHA recorded

This is the first reusable unit of the developer ladder: branch, change, observe, inspect, commit.

This is a hands-on checkpoint. The browser result, focused diff, and commit SHA are the answer.

DIWA CHECKBOX / MODULE 04 / FIND THE RIGHT PLACE FOR A CHANGE

Module 04 — Find the right place for a change

The repository is large because ownership is split across apps and packages. The goal is not to memorize every directory. The goal is to identify the next boundary from the type of change you have.

DIWA CHECKBOX / MODULE 04 / FIND THE RIGHT PLACE FOR A CHANGE

Component boundaries for one dashboard feature

Component boundaries from the admin dashboard route through the shell, feature UI, API adapter, checkbox-api, api-admin, and db-main

The arrows show wiring and data flow. The package names show ownership. These are related, but they are not the same thing.

For a new web route:

Create the page file
→ register it in app/routes.ts
→ run the app's type generation/check
→ verify the route through the browser
DIWA CHECKBOX / MODULE 04 / FIND THE RIGHT PLACE FOR A CHANGE

Route config points to the shell

The route file registers which app module receives /dashboard:

// monorepo/apps/admin-web/app/routes.ts
...prefix("dashboard", [
  index("features/feat-dashboard/pages/overview-shell.page.tsx"),
]),

The route config decides which shell loads. It does not own the dashboard's domain UI or database query.

DIWA CHECKBOX / MODULE 04 / FIND THE RIGHT PLACE FOR A CHANGE

The shell injects runtime services

The shell reads environment/runtime context, builds the service, and passes it into the package page:

// overview-shell.page.tsx
const dashboardService = useMemo(
  (): DashboardService => ({
    getEncoderDashboard: () =>
      fetchEncoderDashboard({ baseUrl: apiBaseUrl }),
  }),
  [apiBaseUrl],
);

return <OverviewPage user={user} dashboardService={dashboardService} onNavigate={navigate} />;

This is why the reusable page can render UI without knowing which environment-specific API URL it should use.

DIWA CHECKBOX / MODULE 04 / FIND THE RIGHT PLACE FOR A CHANGE

API change map

Browser request
  → checkbox-api gateway
  → api-admin / api-auth / api-school / api-learn
  → route module and validation
  → feature client
  → db-main or db-auth

The gateway normally dispatches. Domain API actors own normal product endpoints. Add gateway code only for gateway-owned concerns such as a new top-level prefix, actor binding, uploads, or request diagnostics.

DIWA CHECKBOX / MODULE 04 / FIND THE RIGHT PLACE FOR A CHANGE

The browser adapter owns transport details

The adapter turns a service call into an HTTP request and returns typed application data:

// monorepo/apps/admin-web/app/features/feat-dashboard/api/encoder-dashboard.api.ts
export async function fetchEncoderDashboard(
  options: EncoderDashboardFetcherOptions = {},
): Promise<EncoderDashboard> {
  const fullPath = options.baseUrl
    ? `${options.baseUrl}/dashboard/encoder`
    : "/dashboard/encoder";
  const response = await apiClient<EncoderDashboardResponse>({
    path: fullPath,
  });
  return response.data;
}

It is a browser-side adapter. It does not decide database scope or authorization rules.

DIWA CHECKBOX / MODULE 04 / FIND THE RIGHT PLACE FOR A CHANGE

The API actor owns auth and durable reads

The domain route receives the request after gateway dispatch:

// monorepo/packages/core/api-admin/src/core/routes/dashboard.ts
app.get("/dashboard/encoder", authMiddleware, async (c) => {
  const user = c.get("user");
  const { dbMain } = c.get("dbContext");

  // authorize, query dbMain, then return the response contract
});

The gateway routes traffic. api-admin owns admin behavior. dbMain owns the durable data boundary.

DIWA CHECKBOX / MODULE 04 / FIND THE RIGHT PLACE FOR A CHANGE

Add a feature without crossing package boundaries

For domain behavior, follow the existing package shape:

monorepo/packages/core/feat-<domain>/src/features/<feature>/
├── contract.ts
├── client.ts
├── methods/
│   ├── index.ts
│   └── <method>.ts
└── index.ts

The usual order is:

  1. Define Zod contracts and public types.
  2. Implement one focused method per file.
  3. Inject dbMain, dbAuth, or services.
  4. Compose the client.
  5. Export only the public surface.
DIWA CHECKBOX / MODULE 04 / FIND THE RIGHT PLACE FOR A CHANGE

Boundary mistakes to catch early

Mistake Why it causes trouble Check
Importing another package's src path Bypasses the public contract Search for @packages/.../src/.
Putting business logic in checkbox-api Couples the gateway to one feature Check the owning api-* and feat-* package.
Calling the database from browser code Exposes server concerns Check browser/server package boundaries.
Handwriting a migration file Bypasses migration metadata Use the owning package's migrate:generate.
Copying a shared button or form primitive Creates visual and behavior drift Check util-ui and nearby feature usage.
DIWA CHECKBOX / MODULE 04 / FIND THE RIGHT PLACE FOR A CHANGE

Add a web route: exact verification path

After creating a page file and registering it in app/routes.ts:

cd monorepo/apps/admin-web
bun run check-types
bun run dev

Expected type-check shape:

react-router typegen completed
tsc --build --noEmit

Expected browser result:

GET http://localhost:5173/<route>
200 OK

If route types fail, rerun the affected app's check-types; do not manually edit generated route metadata.

DIWA CHECKBOX / MODULE 04 / FIND THE RIGHT PLACE FOR A CHANGE

Add an API route: exact verification path

Choose the actor first:

auth behavior       → packages/core/api-auth
admin behavior      → packages/core/api-admin
school behavior     → packages/core/api-school
student behavior    → packages/core/api-learn

Then verify through the gateway:

cd monorepo/apps/checkbox-api
bun run dev
curl -i http://localhost:8787/health

Expected result:

HTTP/1.1 200 OK
content-type: application/json
{"status":"ok","service":"checkbox-api"}

Do not test only the actor's internal route if the user reaches it through checkbox-api.

DIWA CHECKBOX / MODULE 04 / FIND THE RIGHT PLACE FOR A CHANGE

Checkpoint: choose the owner

A ticket adds a new field to the admin dashboard and displays it in the browser. Which boundaries do you inspect or change?

Choose from:

admin-web route/shell
feat-admin-app-ui
browser API adapter
checkbox-api gateway
api-admin actor
db-main

Explain which boundary you would start at, which boundaries are only involved if data changes, and what evidence would prove the route is wired end to end.

DIWA CHECKBOX / MODULE 04 / FIND THE RIGHT PLACE FOR A CHANGE

Answer: follow the path inward

The likely path is:

admin-web route/shell
  → feat-admin-app-ui
  → browser API adapter
  → checkbox-api gateway
  → api-admin actor
  → db-main, only if the new field is durable data

Start at the visible route and its nearest feature package. Add the API actor and database only when the field is read from or written to durable state. Confirm each boundary with the route wiring, request in the browser Network panel, API response, and focused test.

Do not put business logic in checkbox-api just because it is the public gateway. Do not add a database migration for a field that is only display text.

DIWA CHECKBOX / MODULE 05 / TEST, MIGRATE, AND FOLLOW PATTERNS

Module 05 — Test, migrate, and follow patterns

This module teaches the work that turns a local change into a maintainable change: tests, database migrations, and repository conventions.

DIWA CHECKBOX / MODULE 05 / TEST, MIGRATE, AND FOLLOW PATTERNS

Choose the smallest truthful test

Change First test/check
Pure helper or validation Colocated *.spec.ts or *.spec.tsx
API query validation or route behavior Nearby API actor spec
Web route registration App route spec and type check
Browser-visible workflow tests/uat/specs/ and its manifest
Formatting or boundary issue bun run check or the dedicated rule
Broad change bun run ci after focused checks

Tests should prove behavior. Do not add a test merely to make a file look complete.

DIWA CHECKBOX / MODULE 05 / TEST, MIGRATE, AND FOLLOW PATTERNS

Zod contracts are runtime checks plus TypeScript types

The repository commonly defines a schema once, then derives the TypeScript type from it:

// packages/core/feat-admin/src/features/questions/contract.ts
export const QuestionFiltersSchema = z.object({
  status: z.enum(["draft", "submitted", "validated", "approved", "rejected"]).optional(),
  search_term: z.string().min(1).max(200).optional(),
});

export type QuestionFilters = z.infer<typeof QuestionFiltersSchema>;

The schema can validate runtime input. The inferred type helps the compiler understand valid code. Do not create a second handwritten type that can drift from the schema.

DIWA CHECKBOX / MODULE 05 / TEST, MIGRATE, AND FOLLOW PATTERNS

Kysely expresses the query at the owning boundary

Database access is explicit and receives the database client as an input:

const recentQuestions = await dbMain
  .selectFrom("questions")
  .where("questions.created_by", "=", mainUserId)
  .where("questions.deleted_at", "is", null)
  .select(["questions.id", "questions.created_at"])
  .orderBy("questions.created_at", "desc")
  .limit(5)
  .execute();

This is a query, not an Active Record model call. Keep it behind the owning server/API boundary; browser code should receive the mapped response instead.

DIWA CHECKBOX / MODULE 05 / TEST, MIGRATE, AND FOLLOW PATTERNS

Run focused checks first

From a touched package:

bun run check
bun run check-types

From the repository root:

bun run test:unit

Expected result shape:

Checked files: <count>
No diagnostics found
<test count> pass

Run bun run ci before handing back a broad product change. It includes repository checks, boundaries, type checks, and unit tests.

DIWA CHECKBOX / MODULE 05 / TEST, MIGRATE, AND FOLLOW PATTERNS

Write a pure test beside the source

Typical shape:

src/utils/parse-value.ts
src/utils/parse-value.spec.ts

The test should:

  1. import the public function;
  2. provide a small input;
  3. assert the output or error contract;
  4. avoid mocking dependencies for pure behavior.

Run only the file while iterating:

bun test path/to/parse-value.spec.ts

Expected result:

pass  path/to/parse-value.spec.ts
DIWA CHECKBOX / MODULE 05 / TEST, MIGRATE, AND FOLLOW PATTERNS

Generate a migration from its schema owner

Use the package that owns the schema:

cd monorepo/packages/core/db-main
bun run migrate:generate -- --name=<short-description>

For auth schema changes:

cd monorepo/packages/core/db-auth
bun run migrate:generate -- --name=<short-description>

Expected result shape:

Created kysely migration at src/migrations/<timestamp>_<short-description>.ts
DIWA CHECKBOX / MODULE 05 / TEST, MIGRATE, AND FOLLOW PATTERNS

Inspect a generated migration before applying it

For db-main, the command may also report the generated Drizzle migration. If it reports no schema changes, inspect the schema diff before continuing.

Before applying it:

  • Confirm the generated file matches the intended schema change.
  • Run the owning package checks.
  • Confirm the target environment before applying it.
  • Use the generated migration metadata and naming; do not create migration files manually.
DIWA CHECKBOX / MODULE 05 / TEST, MIGRATE, AND FOLLOW PATTERNS

Apply and inspect local migrations

cd monorepo/packages/core/db-main
bun run migrate:list
bun run migrate:latest

Expected result shape:

Migration list: <known migrations>
Applied migration: <generated migration name>

If the migration is already applied, do not edit its contents. If it fails halfway, preserve the database error and inspect the migration status before attempting migrate:down.

Production migrations follow the deployed runtime path and require the deployment safety guide. Local success is not production compatibility proof.

DIWA CHECKBOX / MODULE 05 / TEST, MIGRATE, AND FOLLOW PATTERNS

Migration safety decision

Before writing the migration, classify the change:

Change Local action Release concern
Additive column/table/index Generate and test Confirm old app can still run if versions overlap.
Rename or remove Use expand/contract Do not release destructive change in one opaque step.
Heavy backfill Separate data operation Estimate runtime and lock impact.
Data correction Script and review separately Preserve rollback or backup evidence.

If you cannot explain how the previous application version behaves against the new schema, stop before promotion.

DIWA CHECKBOX / MODULE 05 / TEST, MIGRATE, AND FOLLOW PATTERNS

Patterns are shortcuts for future readers

Before inventing a structure, check:

  • docs/patterns/ for shared conventions;
  • the nearest existing feature for local shape;
  • package README files for public exports;
  • docs/guides/adding-a-feature.md and adding-a-route.md;
  • the package's own package.json scripts.

Follow the existing pattern when it expresses the same behavior. Deviate when the behavior is genuinely different, and explain the boundary in the change.

DIWA CHECKBOX / MODULE 05 / TEST, MIGRATE, AND FOLLOW PATTERNS

Checkpoint: plan before code

You need to add a new field that is stored in db-main, returned by an admin API route, and shown in the dashboard.

Before editing, answer:

  1. Which package owns the schema and migration?
  2. Which command generates the migration?
  3. What is the smallest truthful test?
  4. What must remain compatible if old and new application versions overlap?
  5. Which focused checks and browser flow will you run?

Pause here. Write the plan in plain language, not just a list of files.

DIWA CHECKBOX / MODULE 05 / TEST, MIGRATE, AND FOLLOW PATTERNS

Answer: make the change verifiable

Expected plan:

Schema owner:    packages/core/db-main
Migration:       generate it from the db-main package
Test:            prove the changed pure/query/route behavior at its boundary
Checks:          focused test, bun run check-types, bun run check
Workflow:        verify the field in the browser after the API returns it
Compatibility:   use expand/contract for a rename, removal, or mixed-version deploy

Generate the file; do not create it manually:

cd monorepo/packages/core/db-main
bun run migrate:generate -- --name=<short-description>
bun run migrate:list

If the change belongs to authentication data, use db-auth instead. If the migration is already applied or fails halfway, preserve the error and inspect migration state before trying recovery commands.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Module 06 — Run the test layers

Unit tests, browser tests, and load tests answer different questions. Start with the smallest layer that can prove the change, then move outward when the behavior crosses a boundary.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Three test layers, three different questions

unit tests       → does this code behavior still work?
E2E / UAT        → can a real user complete this workflow?
load tests       → can the deployed runtime handle this traffic shape?
Layer Public command Main boundary Needs
Unit bun run test:unit TypeScript helpers, contracts, scripts Installed dependencies
E2E / UAT bun run test:e2e Browser → app stack → API Local stack, fixtures, Chromium
Load bun run test:load AWS CodeBuild → deployed runtime Dedicated students, CSV credentials, AWS access

Passing one layer does not prove the next one. A unit test can pass while a route is unregistered; a browser test can pass while the runtime fails under load.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Start at the public testing commands

# code behavior
bun run test:unit

# browser workflow
bun run test:e2e -- --rows TCH-001 --workers 1 --run-id teacher-smoke

# deployed capacity
bun run test:load -- --profile smoke

The -- separator belongs to Bun. Everything after it is forwarded to the repository-owned runner.

Use the live command help when a flag is unfamiliar:

bun run test:e2e -- --help
bun run test:load -- --help

Start with test:*. The lower-level uat:*, AWS, and direct k6 commands are escape hatches for debugging the machinery underneath.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Unit tests: fast feedback for code behavior

# all repository-owned unit tests
bun run test:unit

# one file while debugging
bun test path/to/file.spec.ts

Unit tests cover pure functions, contracts, helpers, and script behavior. They should answer one small question without needing a browser, UAT services, AWS, or a live database.

They do not prove that a route is registered, a browser can sign in, or a deployed image can handle traffic. Move to E2E when the user workflow matters.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

What test:unit actually runs

The public command is a repository-owned wrapper around Bun:

collect monorepo/**/*.spec.ts[x] and tools/**/*.spec.ts[x]
  → exclude tests/uat, build output, node_modules, and generated folders
  → regular files run with max concurrency 8
  → files using mock.module run in isolation with concurrency 1

There are no repository-specific test:unit flags. Use the public command for the full suite; use direct bun test <file> only for focused debugging.

If a test passes in isolation but fails in bun run test:unit, suspect shared state, timing, or a test that depends on another test's setup.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Checks sit beside unit tests

bun run check         # formatting, workspace rules, boundaries, package checks
bun run check-types   # TypeScript across the workspaces
bun run ci            # check + boundaries + types + unit tests

Use the narrowest useful command first, then the full suite before submitting a change:

changed pure helper  → focused bun test
changed package/API  → package check + check-types
changed behavior     → bun run ci, then E2E if a browser path is involved

The full local CI command does not run Playwright or AWS load tests. Those are separate because they need different environments and credentials.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

E2E starts with a running local stack

Complete local bootstrap first:

bun run dev:bootstrap

Then use two terminals:

# Terminal 1 — keep the UAT app stack alive
bun run test:e2e:setup
# Terminal 2 — plan first, then run
bun run test:e2e -- --dryRun --rows TCH-001 --workers 1 --run-id local-smoke
bun run test:e2e -- --rows TCH-001 --workers 1 --run-id local-smoke

The dry run prints the selected lanes without launching browsers. If setup or type generation fails, fix that before interpreting a row failure.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Choose E2E rows with filters

# exact row, range, or prefix
bun run test:e2e -- --rows TCH-001,ENC-010..ENC-015,SCH-* --workers 1

# role, phase, or execution group
bun run test:e2e -- --role teacher --phase smoke --workers 2
bun run test:e2e -- --group readonly --workers 4
Flag What it selects What it does not do
--rows Row IDs, ranges, or prefixes from the UAT catalog It does not set the artifact folder
--role A role slug such as teacher or student It does not create the account
--phase A manifest phase such as smoke It does not change the workflow steps
--group A scheduling lane such as readonly or serialized-mutate It does not make mutations safe to parallelize

The selected row still needs its fixture, credentials, and local service path.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

E2E flags that change how the run is observed

bun run test:e2e -- \
  --rows ENC-010 \
  --workers 1 \
  --run-id encoder-enc-010 \
  --headed \
  --no-clean
Flag Meaning Use it when
--run-id <id> Names the immutable artifact run You need predictable evidence paths
--workers <count> Sets maximum concurrent scheduler lanes You are deliberately changing parallelism
--dryRun Prints the plan without browsers You want to verify selection first
--headed Shows the browser window You need to watch an interaction
--no-clean Preserves existing deterministic outputs You are debugging artifacts, not starting clean
-h, --help Prints the runner's current option help You need to confirm syntax

--run-id is hyphenated because the runner uses that exact option name. The camel-case --runId is not an alias.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Select a row with --rows, not --run-id

# Correct: select the UAT row and name the artifact run
bun run test:e2e -- --rows ENC-010 --run-id encoder-smoke

# Wrong meaning: this names an artifact run; it does not select ENC-010
bun run test:e2e -- --run-id ENC-010

# Invalid spelling: the runner does not define --runId
bun run test:e2e -- --runId ENC-010

Think of the distinction this way:

--rows     = which workflows should run?
--run-id   = where should their evidence be written?

If no rows match, the runner stops before Playwright starts. Preserve that error; do not replace it with a broader run and assume the intended row was included.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

More E2E workers are not always faster

--workers controls the scheduler's maximum concurrent lanes. The default is 4, but the effective count is also limited by role account pools and the execution group.

readonly groups       → may use several role/account lanes
mutation-heavy groups → stay serial for safety
each child Playwright lane → UAT_WORKERS=1
student role          → default primary pool has 1 slot

Start conservatively:

# focused debugging or account/session failures
bun run test:e2e -- --rows ENC-010 --workers 1

# broader read-only coverage after the local stack is stable
bun run test:e2e -- --group readonly --workers 2

Too many workers can exhaust account pools, compete for CPU, overload local databases, or make session failures look nondeterministic. More lanes increase pressure; they do not create more valid test accounts.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Read E2E output by run ID

artifacts/uat/runs/<run-id>/
├── run.json
├── summary.md
├── results.json
├── playwright-report/index.html
└── lanes/

Export the catalog and latest row evidence for a known run:

bun run test:e2e:csv -- --run-id encoder-smoke

If you omit --run-id, CSV export follows artifacts/uat/latest.json. If the result belongs to a different run, the CSV can be correct but still describe the wrong execution.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Load tests measure a deployed runtime

bun run test:load -- --profile smoke

The public wrapper starts a manual AWS CodeBuild k6 run, optionally watches CloudWatch logs, waits for completion, downloads S3 artifacts, and renders report.md.

Load tests are not local E2E tests and do not run on every commit. They require:

  • AWS access in the target region;
  • a deployed load-test CodeBuild runner;
  • dedicated student accounts and credentials; and
  • runtime monitoring while the traffic runs.

Never point a load test at a shared account pool or treat a login failure as an application-capacity result.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Load credentials are part of the fixture

Provision the academic fixture and start small:

bun run aws:load-test:fixture:ssm -- \
  --fixture-key bsp-load-2026 \
  --school-name "BSP Load Test" \
  --group-name "BSP Load Grade 4" \
  --student-count 2000 \
  --start-index 1 \
  --limit 10 \
  --output /tmp/bsp-load-students.csv \
  --dry-run

After checking the plan, rerun the same command without --dry-run to provision the students. Then upload the CSV:

# repeat the command above without --dry-run
bun run aws:load-test:upload-credentials

The credentials must map to real dedicated student records in both db-main and db-auth. --credential-count only records report metadata; it does not seed users. No seed user or no uploaded CSV means login failures before capacity is measured.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Load profile shapes

Profile Traffic shape What it is for
debug 1 VU, 1 iteration, max 1m Check wiring with minimal traffic
smoke 5 VUs for 2m Credentials, routing, artifacts
baseline Ramp to 300 VUs, hold, ramp down Normal capacity signal
scale1000 Ramp to 1000 VUs, hold, ramp down Step capacity test
scale2000 Ramp to 2000 VUs, hold, ramp down High-risk capacity test
peak Slow ramp to 2000 VUs and hold Peak behavior after baseline passes
spike Fast ramp to 2000 VUs Deliberate burst behavior

Each profile also carries different failure-rate, latency, and check-rate thresholds. A “pass” means the selected shape stayed within that profile's gates; it is not a universal capacity claim.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Read the profile gates

Profile Failed requests p95 latency p99 latency Checks
debug
smoke < 1% < 2s > 99%
baseline < 2% < 2s < 5s > 98%
scale1000, scale2000, peak < 3% < 3s < 8s > 97%
spike < 5% < 5s < 10s > 95%

These are k6 gates: rate<0.01 means fewer than 1% of requests fail, p(95)<2000 means 95% complete under 2 seconds, and rate>0.99 means more than 99% of checks pass. A passing smoke run is not a passing baseline run.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Scenario flags

bun run test:load -- \
  --profile baseline \
  --student-flow app-shell \
  --login-mode once-per-vu
Flag Meaning Implication
--profile Selects VUs, stages, duration, and thresholds Different profiles are not directly comparable
--student-flow app-shell or legacy endpoint pattern Measures different browser/API behavior
--login-mode once-per-vu or per-iteration Signed-in capacity vs login pressure

Use once-per-vu for the normal capacity baseline. Use per-iteration only for a login-storm question; do not compare its latency directly with signed-in traffic.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Load runner flags and artifacts

Existing run:  --build-id <id> --download-only
Start only:    --no-wait
No live tail:  --no-watch
Skip checks:   --no-validate   (wrapper debugging only)
Skip outputs:  --no-download / --no-report
Time limit:    --timeout-minutes <minutes>
Help:          --help

AWS target:    --region --project-name --log-group --artifact-bucket
S3 layout:     --results-prefix --output-root
Report labels: --variant --credential-count
Infrastructure: --deploy

The safe recovery path for a finished or interrupted build is usually:

bun run test:load -- \
  --build-id diwa-checkbox-production-k6-load-test:<build-id> \
  --download-only

--no-validate and --deploy change infrastructure behavior; use them only when the runner stack itself is the subject of the change.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Load failures usually identify a missing layer

Symptom First suspicion Check next
No k6 credentials loaded CSV missing or unreadable K6_CREDENTIALS_PATH, upload, artifact contents
Login checks fail immediately Seeded student is absent or mismatched db-auth + db-main, email/password CSV
Access denied or no CodeBuild run Wrong AWS identity, region, or project --region, project permissions, runner stack
5xx/latency rises at high VUs Runtime capacity or downstream saturation CloudWatch, EC2, Aurora, ALB, container restarts
Build finished but no local report Download/report step was skipped --build-id ... --download-only, then inspect S3 artifacts
Baseline comparison disagrees Flow, login mode, profile, or credentials changed Record all scenario flags and the credential set

Stop a run for sustained 5xx, OOM/restarts, EC2 status failure, Aurora saturation, or reported user impact. A failed load run is evidence about the chosen setup, not automatically evidence that the product is slow.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Checkpoint: choose the smallest truthful test

Choose the first test layer for each change:

  1. A pure formatter helper changes.
  2. A new dashboard field must travel from db-main to the browser.
  3. A teacher login and dashboard workflow must still work.
  4. The deployed student read path must be tested at 300 and 1000 virtual users.

For each answer, name the command, one prerequisite, and one result that would change your next step.

DIWA CHECKBOX / MODULE 06 / RUN THE TEST LAYERS

Answer: move outward only when the boundary changes

1. pure helper       → bun run test:unit
2. browser data path → unit + focused E2E/UAT row
3. teacher workflow  → bun run test:e2e -- --role teacher
4. deployed traffic  → bun run test:load -- --profile baseline

Use the smallest truthful test first. Add the next layer when the change crosses that layer's boundary. Keep the command, flags, fixture identity, and artifact run ID with the result.

DIWA CHECKBOX / MODULE 07 / TRACE AND DEBUG ONE FEATURE

Module 07 — Trace and debug one feature

Use the dashboard's Recent Questions request as the worked example. The endpoint is a concrete example of a repeatable boundary-narrowing method.

DIWA CHECKBOX / MODULE 07 / TRACE AND DEBUG ONE FEATURE

Trace from the browser outward

Browser request flow through web app, checkbox-api, API actor, feature package, and database

Start with what the user sees. Then identify:

  1. browser route;
  2. Network request;
  3. web API adapter;
  4. gateway prefix;
  5. API actor route;
  6. authorization middleware;
  7. feature client and method;
  8. database read or write.
DIWA CHECKBOX / MODULE 07 / TRACE AND DEBUG ONE FEATURE

Inspect the browser request

  1. Open browser developer tools.
  2. Select Network.
  3. Reload the page.
  4. Filter for dashboard/encoder.
  5. Record method, path, status, and duration.

Expected successful shape:

GET /api/admin/dashboard/encoder
200 OK

Do not copy cookies, authorization headers, question content, or personal data into shared evidence.

DIWA CHECKBOX / MODULE 07 / TRACE AND DEBUG ONE FEATURE

Reproduce the public API health boundary

curl -i http://localhost:8787/health

Expected result:

HTTP/1.1 200 OK
content-type: application/json
{"status":"ok","service":"checkbox-api"}

Health proves the gateway is reachable. It does not prove the authenticated feature request succeeds.

DIWA CHECKBOX / MODULE 07 / TRACE AND DEBUG ONE FEATURE

Find the source boundary with exact text

rg -n --fixed-strings 'Recent Questions' monorepo
rg -n 'dashboard/encoder' monorepo/apps monorepo/packages

Expected locations include:

feat-admin-app-ui/.../overview.page.tsx
admin-web/.../encoder-dashboard.api.ts
api-admin/.../routes/dashboard.ts

Read the imports and caller chain around each match. A filename match alone is not proof of active wiring.

DIWA CHECKBOX / MODULE 07 / TRACE AND DEBUG ONE FEATURE

Debug by the first failing boundary

Symptom First boundary Next check
Browser will not load Web app/server Terminal output and port
Page loads, list fails API request Network status and request ID
API returns 401 or 403 Auth/session/role Auth URL, cookies, role, middleware
API returns 500 Handler/feature/database API terminal logs and DB connectivity
API returns 200, wrong data Query/scope/seed Feature method, authorization, local seed
Code change does not appear Served bundle/process Port, changed file, compile output

Do not restart every service before identifying which boundary failed.

DIWA CHECKBOX / MODULE 07 / TRACE AND DEBUG ONE FEATURE

Repair the local loop

Use this order:

git status --short
bun run check
bun run check-types
bun test path/to/focused.spec.ts

Then restart only the affected process. If the failure is caused by stale local data, use the documented reset path; if it is caused by source, preserve the first compiler or test error.

Expected recovery result:

The smallest failed command now passes
The affected process restarts
The browser workflow is rechecked
DIWA CHECKBOX / MODULE 07 / TRACE AND DEBUG ONE FEATURE

Checkpoint: explain one failure without guessing

The dashboard loads and the Recent Questions heading is visible, but the list request fails. The API health endpoint returns 200.

What do you check next, in what order, and what does each signal rule in or rule out?

Your explanation should name the first failing boundary and the next command or browser check.

DIWA CHECKBOX / MODULE 07 / TRACE AND DEBUG ONE FEATURE

Answer: health is only one signal

The heading proves the web bundle and route rendered. The health response proves the gateway is alive; it does not prove that the dashboard request is authorized, wired, or returning valid data.

Narrow the failure in this order:

browser Network request and status
  → checkbox-api terminal logs
  → API actor route and authorization middleware
  → feature method and database query

If the request is 401 or 403, inspect the auth/session boundary. If it is 500, inspect the API logs and database connectivity. If it is 200 with wrong data, inspect query scope and local seed state. Restart only the affected process after identifying the failing boundary.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

Bonus — Recommended CodeCommit workflow

This is a future process recommendation. It is not the current deployment behavior.

The target process uses short-lived feature branches, a protected staging integration branch, and a protected main production branch.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

Current versus future behavior

Today Future target
Accepted update to CodeCommit main starts the AWS pipeline. staging starts a separate staging pipeline.
Non-main branches do not deploy by default. Feature PRs merge into staging for shared validation.
Production-named AWS stacks also serve the BSP UAT namespace. Staging and production have separate resources and secrets.
Direct-push protection must be verified. staging and main are protected by approval rules and IAM policy.

Do not tell a new developer that pushing staging deploys anywhere until the future infrastructure exists and has been tested.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

Future source-to-environment flow

Future CodeCommit workflow from short-lived feature branch through staging to main and production

The important identity is the commit SHA. A branch name can move; the tested revision must be recorded before promotion.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

Branch topology: staging is the integration trunk

Git graph showing three short-lived feature branches merging into staging, then staging being promoted into main twice

The graph shows staging being reused: two features merge into it, the first revision is promoted to main, then a third feature joins before the second promotion.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

How to read the repeated staging loop

Read this as the relationship between branches:

  • staging is the shared integration trunk and the source of the UAT environment.
  • feat/* branches are short-lived work branches that merge into staging through a CodeCommit PR. Three features can join the same staging line.
  • main is the protected production release line; each promotion is a second PR from the reviewed staging revision. staging remains available for the next feature after a promotion.

The branch graph explains where code lives. The previous diagram explains what each accepted merge causes.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

Configure CodeCommit for this repository

After cloning with an AWS identity that can access the repository:

bun run aws:codecommit:helper -- --apply-local-git-config
git remote -v
git fetch origin --prune

Expected result shape:

origin  https://git-codecommit.ap-southeast-1.amazonaws.com/v1/repos/diwa-checkbox (fetch)
origin  https://git-codecommit.ap-southeast-1.amazonaws.com/v1/repos/diwa-checkbox (push)

The helper changes this repository's .git/config. If fetch fails, check AWS identity, CodeCommit permission, profile, and the repository-local helper before changing global Git settings.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

Start a feature from the future staging branch

git fetch origin staging
git switch --track -c staging origin/staging
git switch -c feat/<short-description>
git branch --show-current

Expected result:

branch 'staging' set up to track 'origin/staging'.
Switched to a new branch 'feat/<short-description>'
feat/<short-description>

If staging already exists locally, use git switch staging followed by git pull --ff-only origin staging, then create the feature branch. If origin/staging does not exist, this future process has not been provisioned. Stop and use the current branch policy; do not create an environment promise from a missing branch.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

Push a feature branch

After local checks pass:

git status --short --branch
git diff --cached --check
git push -u origin feat/<short-description>
git ls-remote origin refs/heads/feat/<short-description>

Expected result shape:

branch 'feat/<short-description>' set up to track 'origin/feat/<short-description>'
<commit SHA>  refs/heads/feat/<short-description>

If push is rejected, preserve the error. Common causes are expired AWS credentials, missing CodeCommit permission, a remote branch that moved, or a protected destination. Do not force-push a shared branch.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

Create a CodeCommit pull request into staging

aws --region ap-southeast-1 codecommit create-pull-request \
  --title "<short title>" \
  --description "What changed, checks run, and UAT impact" \
  --targets "repositoryName=diwa-checkbox,sourceReference=feat/<short-description>,destinationReference=staging" \
  --query 'pullRequest.pullRequestId' \
  --output text

Expected result:

arn:aws:codecommit:ap-southeast-1:...:pull-request/...

If the command returns AccessDenied, stop and request the CodeCommit pull-request permission. If the target branch is missing, the staging process is not ready.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

Inspect the pull request before approval

aws --region ap-southeast-1 codecommit get-pull-request \
  --pull-request-id <pr-id> \
  --query 'pullRequest.{status:pullRequestStatus,source:pullRequestTargets[0].sourceReference,destination:pullRequestTargets[0].destinationReference,revision:pullRequestTargets[0].sourceCommit}'

Expected result shape:

{
  "status": "OPEN",
  "source": "feat/<short-description>",
  "destination": "staging",
  "revision": "<full commit SHA>"
}

Reviewers should confirm the source SHA, checks, migration compatibility, UAT scope, and rollback concern before approval.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

What staging must prove before production promotion

The staging pipeline and UAT exercise must verify:

[ ] the intended source SHA reached staging
[ ] required checks passed
[ ] migrations completed safely
[ ] public health is green
[ ] the changed browser workflow works
[ ] logs contain no new blocking error
[ ] the release identity and rollback identity are recorded

Passing staging is not permission to push directly to main. It is the input to a second CodeCommit PR.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

Promote the tested revision into main

Create a second PR:

aws --region ap-southeast-1 codecommit create-pull-request \
  --title "Promote staging release" \
  --description "Promotes the tested staging revision to production" \
  --targets "repositoryName=diwa-checkbox,sourceReference=staging,destinationReference=main" \
  --query 'pullRequest.pullRequestId' \
  --output text

After approvals, use the repository's approved merge method. Prefer fast-forward when it preserves the tested SHA:

aws --region ap-southeast-1 codecommit merge-pull-request-by-fast-forward \
  --pull-request-id <promotion-pr-id> \
  --repository-name diwa-checkbox

Expected result includes a merged status and commit identity. If fast-forward is impossible, stop and reconcile history rather than silently cherry-picking.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

Verify promotion identity

git fetch origin main staging
git rev-parse origin/staging
git rev-parse origin/main

Expected result:

<tested staging SHA>
<promoted main SHA>

Record whether these are equal. If they differ, identify the merge commit and confirm which revision the production pipeline will build before continuing.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

Future workflow: required infrastructure

This process cannot be enabled by Git configuration alone. It needs:

  • separate staging database and migration target;
  • staging Secrets Manager paths;
  • staging S3, SQS, DLQ, and email behavior;
  • staging hostname, certificate, ALB, and health checks;
  • CodePipeline branch filters for staging and main;
  • CodeCommit approval rules and IAM direct-push denial;
  • staging data and test-account policy;
  • exact SHA/image promotion and rollback procedures.

Until those exist, the current main-only deployment path remains the source of truth.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

Hotfix and rollback policy

For a production incident:

  1. Branch from the known production revision or follow the approved recovery runbook.
  2. Make the smallest safe fix.
  3. Validate locally.
  4. Submit a CodeCommit PR to the approved release branch.
  5. Promote the fix through staging when the incident allows it.
  6. After the production merge, reconcile the fix back into staging.

Do not reset a shared branch, delete an accepted tag, or deploy a mutable latest image as a rollback.

DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

Checkpoint: explain the promotion path

A feature branch passes its local checks. The future process has staging for shared validation and main for production.

Before continuing, explain:

  1. Why does the feature branch exist?
  2. What must the staging PR prove?
  3. What does the promotion PR to main prove?
  4. Why must the source SHA and image digest be recorded?
  5. What should you do if origin/staging does not exist?
DIWA CHECKBOX / BONUS / CODECOMMIT WORKFLOW

Answer: promote a known revision

The future path is:

feature branch
  → CodeCommit PR to staging
  → staging deploy and UAT evidence
  → promotion PR to main
  → production pipeline

The staging PR proves that the change can integrate and run in the shared environment. The promotion PR proves which reviewed staging revision is being released. The SHA and image digest make the deployed revision identifiable instead of relying on a mutable tag.

If origin/staging does not exist, do not invent the workflow by pushing it. The branch, pipeline, environment, secrets, approval rules, and deployment target must be provisioned together. Until then, follow the current main-only process.

DIWA CHECKBOX / MODULE 08 / UAT, OPERATIONS, AND ACCEPTANCE

Module 08 — UAT, operations, and acceptance

This module is access-gated. Developers without AWS or UAT access should observe the procedures and continue with the evidence model; they should not claim to have executed them.

DIWA CHECKBOX / MODULE 08 / UAT, OPERATIONS, AND ACCEPTANCE

Current UAT release path

For the current repository process, an accepted update to CodeCommit main triggers the AWS-native pipeline:

CodeCommit main
  → EventBridge
  → CodePipeline
  → CodeBuild
  → ECR images
  → EC2 deployment through SSM
  → health and workflow checks

The future staging workflow in the bonus section is not active unless DIWA provisions the separate environment and branch trigger.

DIWA CHECKBOX / MODULE 08 / UAT, OPERATIONS, AND ACCEPTANCE

Find the pipeline execution for one SHA

git rev-parse origin/main

aws --region ap-southeast-1 codepipeline list-pipeline-executions \
  --pipeline-name diwa-checkbox-production-deploy \
  --max-results 10

Expected result contains source revision IDs and an execution status such as InProgress, Succeeded, or Failed.

If no execution matches the accepted SHA, do not select the newest execution. Confirm the source revision, pipeline trigger, and CodeCommit branch.

DIWA CHECKBOX / MODULE 08 / UAT, OPERATIONS, AND ACCEPTANCE

Release identity has three parts

Source identity:  full CodeCommit commit SHA
Image identity:   service image tag and immutable ECR digest
Runtime identity: host/service image actually running

The current pipeline derives a 12-character image tag from the full SHA. A tag is useful for lookup; the digest is the identity to preserve for rollback.

DIWA CHECKBOX / MODULE 08 / UAT, OPERATIONS, AND ACCEPTANCE

Verify an image tag and digest

aws --region ap-southeast-1 ecr describe-images \
  --repository-name diwa-checkbox-admin-web \
  --image-ids imageTag=<12-character-tag> \
  --query 'imageDetails[0].{digest:imageDigest,pushedAt:imagePushedAt}' \
  --output table

Expected result includes one digest and a push time.

If the tag is missing, expired, or resolves to a different digest than the accepted release record, stop. Do not deploy it as a known-good image.

DIWA CHECKBOX / MODULE 08 / UAT, OPERATIONS, AND ACCEPTANCE

Verify public health and the user workflow

bun run aws:smoke-health -- --environment bsp

Then use an approved UAT account to verify the changed workflow in the browser.

Expected evidence:

Health:        all required public surfaces healthy
Workflow:      intended route loads and changed behavior is visible
Revision:      accepted SHA/tag/digest recorded
Residual risk: documented or none

Health is necessary but not sufficient. A green health endpoint does not prove login, authorization, data correctness, or the target workflow.

DIWA CHECKBOX / MODULE 08 / UAT, OPERATIONS, AND ACCEPTANCE

Diagnose an incident by narrowing the boundary

Incident narrowing from user symptom through public health, target, host, service, dependency, and workflow

Use the first failed signal to choose the next boundary. Do not jump directly to the database or infrastructure without evidence.

DIWA CHECKBOX / MODULE 08 / UAT, OPERATIONS, AND ACCEPTANCE

Narrow the failure in this order

Use the sequence:

user impact
→ public health
→ ALB target health
→ EC2/SSM
→ container and logs
→ dependency
→ product workflow

Ask what the next signal will rule in or rule out before running it.

DIWA CHECKBOX / MODULE 08 / UAT, OPERATIONS, AND ACCEPTANCE

Recovery has a stop condition

Before any recovery action, confirm:

[ ] intended AWS account and region
[ ] intended environment
[ ] approved operator and change window
[ ] known-good image digest
[ ] schema compatibility
[ ] rollback access
[ ] exact post-recovery checks

If the maintained helper reconciles more services, runs more migrations, or pulls by mutable tag than the incident requires, do not use it as a narrow recovery command. Record the blocker and keep the exercise tabletop-only.

DIWA CHECKBOX / MODULE 08 / UAT, OPERATIONS, AND ACCEPTANCE

Production rehearsal order

Use the dependency order:

environment and data decision
→ recovery point and rollback
→ certificates and public routes
→ secrets and origins
→ deployment and migrations
→ health and workflow checks
→ monitoring and acceptance

The current production cutover material remains a rehearsal until the required infrastructure, approvals, DNS, secrets, and recovery procedures are proven.

DIWA CHECKBOX / MODULE 08 / UAT, OPERATIONS, AND ACCEPTANCE

What a successful turnover produces

Developer capability
  run → find → change → test → debug → commit → submit

Operational capability
  identify → deploy → verify → narrow → recover → rehearse

Repository result
  clear ownership, reproducible commands, honest blockers,
  and a future CodeCommit promotion process that can be implemented safely

The handbook is successful when a developer can solve the next problem without needing a private explanation of the repository.

DIWA CHECKBOX / APPENDIX A / COMMAND REFERENCE

Appendix A — Command reference

Use this appendix after learning the reason for each command in the modules.

DIWA CHECKBOX / APPENDIX A / COMMAND REFERENCE

A.01 — Local setup

bun run setup:doctor
bun install --frozen-lockfile
bun run dev:bootstrap
bun run setup:doctor

Start the core path in separate terminals:

cd monorepo/apps/checkbox-api && bun run dev
cd monorepo/apps/auth-web && bun run dev
cd monorepo/apps/admin-web && bun run dev

Check:

curl -sS http://localhost:8787/health

Stop/reset:

bun run dev:infra:down
bun run dev:infra:reset
DIWA CHECKBOX / APPENDIX A / COMMAND REFERENCE

A.02 — Daily validation

bun run check
bun run check-types
bun run test:unit
bun run ci

Focused package checks:

cd monorepo/apps/admin-web && bun run check-types
cd monorepo/apps/admin-web && bun run check
cd monorepo/packages/core/feat-admin-app-ui && bun run check-types
cd monorepo/packages/core/feat-admin-app-ui && bun run check

Focused test:

bun test path/to/file.spec.ts
DIWA CHECKBOX / APPENDIX A / COMMAND REFERENCE

A.03 — Database work

cd monorepo/packages/core/db-main
bun run migrate:generate -- --name=<short-description>
bun run migrate:list
bun run migrate:latest

cd ../db-auth
bun run migrate:generate -- --name=<short-description>
bun run migrate:list
bun run migrate:latest

Do not hand-write migration files. Do not run a production migration from a local troubleshooting session.

DIWA CHECKBOX / APPENDIX A / COMMAND REFERENCE

A.04 — CodeCommit access and branch checks

bun run aws:codecommit:helper -- --apply-local-git-config
git remote -v
git fetch origin --prune
git status --short --branch
git branch --show-current
git rev-parse HEAD
git ls-remote origin refs/heads/<branch>

The helper is repository-local. If the remote or identity is wrong, stop before pushing.

DIWA CHECKBOX / APPENDIX A / COMMAND REFERENCE

A.05 — Future CodeCommit PR commands

aws --region ap-southeast-1 codecommit create-pull-request \
  --title "<title>" \
  --description "<summary and checks>" \
  --targets "repositoryName=diwa-checkbox,sourceReference=<source>,destinationReference=staging" \
  --query 'pullRequest.pullRequestId' \
  --output text

aws --region ap-southeast-1 codecommit get-pull-request \
  --pull-request-id <pr-id>

aws --region ap-southeast-1 codecommit merge-pull-request-by-fast-forward \
  --pull-request-id <pr-id> \
  --repository-name diwa-checkbox

These commands describe the future process. Confirm branch protection, approval rules, pipeline triggers, and environment isolation before using them as an operational procedure.

DIWA CHECKBOX / APPENDIX A / COMMAND REFERENCE

A.06 — Current UAT observation

aws --region ap-southeast-1 codepipeline list-pipeline-executions \
  --pipeline-name diwa-checkbox-production-deploy \
  --max-results 10

bun run aws:smoke-health -- --environment bsp

aws --region ap-southeast-1 ssm describe-instance-information
aws --region ap-southeast-1 cloudwatch describe-alarms \
  --state-value ALARM

Use the detailed deployment and recovery runbooks before any state-changing AWS command.

DIWA CHECKBOX / APPENDIX B / REPOSITORY MAP

Appendix B — Repository map

DIWA CHECKBOX / APPENDIX B / REPOSITORY MAP

B.01 — Ownership map

Change Primary path
Admin web route monorepo/apps/admin-web/app/routes.ts
School web route monorepo/apps/school-web/app/routes.ts
Learn web route monorepo/apps/learn-web/app/routes.ts
Auth web route monorepo/apps/auth-web/app/routes.ts
Admin API route monorepo/packages/core/api-admin/src/
School API route monorepo/packages/core/api-school/src/
Learn API route monorepo/packages/core/api-learn/src/
Auth API route monorepo/packages/core/api-auth/src/
Gateway behavior monorepo/apps/checkbox-api/src/
Main DB monorepo/packages/core/db-main/
Auth DB monorepo/packages/core/db-auth/
Feature/domain behavior monorepo/packages/core/feat-*
Shared UI/utilities monorepo/packages/shared/
UAT tests/uat/
AWS deployment deploy/aws/
DIWA CHECKBOX / APPENDIX B / REPOSITORY MAP

B.02 — Source-of-truth reading order

When behavior is unclear, inspect in this order:

  1. public route or visible workflow;
  2. app route and shell;
  3. browser API adapter;
  4. checkbox-api gateway binding;
  5. domain API route and middleware;
  6. feature client and method;
  7. database query/schema/migration;
  8. focused test and UAT coverage;
  9. deployment/runtime wiring if the behavior is environment-specific.

This prevents a schema, helper, or isolated test from being mistaken for active product behavior.

DIWA CHECKBOX / APPENDIX C / TROUBLESHOOTING

Appendix C — Troubleshooting

DIWA CHECKBOX / APPENDIX C / TROUBLESHOOTING

C.01 — Local symptom matrix

Symptom First check Next safe action
Bun version mismatch bun --version Switch to the pinned version.
Docker unavailable docker version Start Docker Desktop.
Port already in use lsof -nP -iTCP: -sTCP:LISTEN Stop the intended stale process.
API health fails API terminal and env Fix API boot before browser work.
Login redirect loop Auth/API origins Compare local URLs in generated env.
Page loads but data fails Network status/request ID Trace the API actor and database boundary.
Type generation fails Affected app check-types Read the first route/type error.
Test fails after seed Local database state Inspect migration/seed status; reset only if safe.
Import cannot resolve Package exports Use the public package surface.
CodeCommit push fails AWS identity/helper/permission Preserve the error; do not force-push.
DIWA CHECKBOX / APPENDIX C / TROUBLESHOOTING

C.02 — Stop conditions

Stop and ask for the correct procedure when:

  • the repository, branch, AWS account, region, or environment is wrong;
  • a command would mutate UAT or production unexpectedly;
  • a required secret or credential would be copied into evidence;
  • a migration is destructive or compatibility is unknown;
  • an image tag cannot be matched to an accepted digest;
  • a branch is protected and the required PR path is unavailable;
  • expected and actual results disagree and the difference is not understood.

Stopping with a precise blocker is better than creating an untraceable success.

DIWA CHECKBOX / APPENDIX D / EVIDENCE AND GLOSSARY

Appendix D — Evidence and glossary

DIWA CHECKBOX / APPENDIX D / EVIDENCE AND GLOSSARY

D.01 — Evidence record

Use this for exercises that need handoff evidence:

Exercise:       _________________________________________________
Environment:    _________________________________________________
Participant:    _________________________________________________
Participation:  [ ] Executed [ ] Paired [ ] Observed [ ] Tabletop [ ] Blocked
Command/action: _________________________________________________
Expected:       _________________________________________________
Actual:         _________________________________________________
Safe output:    _________________________________________________
Blocker:        _________________________________________________
Resolution:     _________________________________________________
Tracking link:  _________________________________________________

Never store passwords, tokens, cookies, complete environment files, private keys, or unnecessary personal data.

DIWA CHECKBOX / APPENDIX D / EVIDENCE AND GLOSSARY

D.02 — Plain-language glossary

Term Meaning
API actor The domain-owned API package for auth, admin, school, or learn behavior.
AWS-managed service A platform service operated through the AWS account, such as EC2, Aurora, S3, SQS, or SES.
DIWA application Repository-owned code, such as web surfaces, checkbox-api, and the notifications worker.
DNS The naming system that maps a hostname to a destination; DNS itself is not an AWS service.
Docker Compose The runtime tool that starts the application containers on the EC2 host; it is not an AWS service.
Gateway checkbox-api, which binds public API prefixes to actors.
UAT User acceptance testing against the approved validation environment.
CodeCommit PR A CodeCommit pull request from one branch to another.
Source SHA The full commit identity used to trace a change.
Image digest The immutable identity of a container image.
Expand/contract migration A schema change released in compatible stages rather than one destructive update.
Tabletop exercise Reasoning through supplied evidence without claiming a live operation.
Runbook The detailed operational procedure that remains authoritative for state-changing work.
DIWA CHECKBOX / APPENDIX D / EVIDENCE AND GLOSSARY
DIWA CHECKBOX / APPENDIX E / TYPESCRIPT PATTERN REFERENCE

Appendix E — TypeScript pattern reference

Use these examples as reading landmarks. Before adding a new pattern, find the nearest active example and follow its public boundary.

DIWA CHECKBOX / APPENDIX E / TYPESCRIPT PATTERN REFERENCE

E.01 — Read the public boundary first

When a TypeScript import or route is unfamiliar, trace it in this order:

// 1. Public package export
import { OverviewPage } from "@packages/core-feat-admin-app-ui/feat-dashboard/pages/overview.page";

// 2. App shell adapts runtime values
const dashboardService: DashboardService = {
  getEncoderDashboard: () => fetchEncoderDashboard({ baseUrl: apiBaseUrl }),
};

// 3. API adapter owns HTTP details
const response = await apiClient<EncoderDashboardResponse>({
  path: `${baseUrl}/dashboard/encoder`,
});

If the import reaches into another package's src/ directory, stop and look for the package's public export instead.

DIWA CHECKBOX / APPENDIX E / TYPESCRIPT PATTERN REFERENCE

E.02 — The smallest truthful feature shape

Use this as a map when a change needs domain behavior, validation, and a database read:

// contract.ts — runtime input + inferred type
export const InputSchema = z.object({ id: z.string().uuid() });
export type Input = z.infer<typeof InputSchema>;

// methods/find-one.ts — one focused behavior
export async function findOne(dbMain: DatabaseMainClient, input: Input) {
  return dbMain
    .selectFrom("questions")
    .select(["id", "created_at"])
    .where("id", "=", input.id)
    .executeTakeFirst();
}

// index.ts — expose the public surface
export { findOne } from "./methods/find-one";

The exact folders vary by domain. The invariant is the boundary: validate input, keep one behavior focused, inject dependencies, and export intentionally.

DIWA CHECKBOX / APPENDIX E / TYPESCRIPT PATTERN REFERENCE

End of handbook

The next step is not to memorize this document. It is to run the smallest exercise you have access to, record what happened, and use the next boundary when something fails.

For current commands, follow the linked repository runbooks. For future staging promotion, treat the bonus section as a target process until DIWA provisions and verifies the required CodeCommit and AWS controls.