codflow
bighadj22/codflow/AGENTS.md
CodFlow is a cash-on-delivery (COD) e-commerce platform for Algeria. Monorepo, TypeScript, deployed on Cloudflare (Workers, D1, R2, KV). - cod-server/ — Cloudflare Workers API (Hono). Merchant /api/, public /store/, /webhooks, /images, /mcp. D1 via Drizzle. - cod-client-astro/ — the merchant dashboard (Astro 7). Prerendered static pages + a Worker surface for /api/auth/* and /mcp/oauth/login; React islands fetch data from cod-server through src/lib/api.ts (the only module allowed to call the API). UI strings come from locales/{ar,en,fr} via useT(namespace) — the i18n…
- Reads credentials
What's in it
- CodFlow — repository instructions for coding agents
- Layout
- Commands
- Cloud resource configuration
- Verification
- Conventions
- Boundaries
- Known traps
- Skills
- Route Builder (API Endpoints)
- Key Patterns
- Available Skills
# CodFlow — repository instructions for coding agents
CodFlow is a cash-on-delivery (COD) e-commerce platform for Algeria. Monorepo,
TypeScript, deployed on Cloudflare (Workers, D1, R2, KV).
## Layout
- `cod-server/` — Cloudflare Workers API (Hono). Merchant `/api/*`, public
`/store/*`, `/webhooks`, `/images`, `/mcp`. D1 via Drizzle.
- `cod-client-astro/` — the merchant dashboard (Astro 7). Prerendered static
pages + a Worker surface for `/api/auth/*` and `/mcp/oauth/login`; React
islands fetch data from cod-server through `src/lib/api.ts` (the only module
allowed to call the API). UI strings come from `locales/{ar,en,fr}` via
`useT(namespace)` — the i18n guard test enforces three-locale parity.
- `cod-shared/` — shared Drizzle schema, queries, RBAC scopes, error codes.
Imported by the apps via relative path (`../../cod-shared/...`). **Not
published.**
- `cod-astro/theme01/` — storefront theme (Astro). It is a swappable theme
layer, not a platform package; keep engine logic out. Its commands and
boundaries differ — read `cod-astro/theme01/AGENTS.md` before editing it.
There is **one root `package.json` with npm workspaces** and ONE root
`package-lock.json`. Never add per-package lockfiles. The root also carries the
repo-wide npm `overrides`: the single-Vite pin (keeps one Vite major across
astro/vitest; npm ignores `overrides` inside workspace members).
## Commands
One install at the repo root covers every package:
```sh
npm ci # at repo root — installs all workspaces
cd cod-server && npm run typecheck
cd cod-server && npm test
cd cod-server && npm run dev # wrangler dev :8787
```
Same for `cod-client-astro` (`npm run typecheck`, `npm test`, `npm run dev`
— astro dev on :4321). Admin bootstrap: `cd cod-client-astro &&
npm run seed:admin` (sign-up is disabled by design).
`cod-astro/theme01` has extra validators — see
`cod-astro/theme01/AGENTS.md` for its commands.
## Cloud resource configuration
Resource names and URLs are **not** hardcoded in scripts. The seeders, the
D1 migration wrapper (`cod-server/scripts/d1.mjs`), the R2 CORS setup and
the storefront deploy helper all read `<repo-root>/.env` through
`cod-server/scripts/cloud-env.mjs`. Precedence is
**`process.env` > `.env` > built-in default**; the committed template is
`<repo-root>/.env.example`.
Keys: `COD_ACCOUNT_ID`, `COD_DB_NAME`, `COD_R2_BUCKET_NAME`,
`COD_SERVER_URL`, `COD_MEDIA_DOMAIN`. Add a key to `DEFAULTS` in
`cloud-env.mjs` and to `.env.example` together — a key in one and not the
other is how these drift.
## Verification
- After changing TypeScript: run `npm run typecheck` in the affected package.
- After changing behavior: run `npm test` in the affected package.
- Full CI runs typecheck + tests for cod-server and cod-client-astro, plus
`astro check` + tests for theme01 (`.github/workflows/ci.yml`).
## Conventions
- **README claims must be code-verified.** Never write a feature claim in the
README that is not actually implemented. Before editing README feature lists,
confirm the code exists.
- **Never commit secrets.** No live API keys, carrier tokens, or credentials in
source, tests, or fixtures. Real secrets go in `wrangler secrets` /
`.dev.vars` (gitignored). Wrangler configs with real resource IDs are
gitignored too (`wrangler.toml` in cod-server/cod-client-astro) — commit
`.example` templates only.
- No explanatory code comments unless asked.
## Boundaries
- `cod-shared` is the single source of truth for the D1 schema, queries, RBAC
scopes, and error codes. Do not duplicate schema or scope definitions in
cod-server or cod-client-astro.
- Migrations: add a new migration; never rewrite an already-applied one.
- Ask before adding a production dependency or changing the D1 schema.
- Keep engine logic out of `cod-astro/theme01`; the theme layer is meant to be
swappable (see `cod-astro/theme01/AGENTS.md`).
- Dashboard data access goes through the API seam (`cod-client-astro/src/lib/api.ts`).
Components never call `fetch` directly, and the dashboard does not query D1
for business data — authorization lives in cod-server.
## Known traps
- Never create per-package `package-lock.json` files (see Layout). If a
workspace's deps look stale, run `npm ci` at the repo root.
- The Vite pin lives in the **root** `package.json`
(`"overrides": { "vite": "^8.2.2" }`) — npm ignores `overrides` inside
workspace members. It keeps a single Vite major across astro/vitest;
removing it reintroduces the dual-Vite boot crash
(`Missing field 'moduleType'`). Keep it in sync when astro bumps Vite.
- `COD_SERVER_URL` defaults to `http://localhost:8787` so local dev works
untouched. A deployed Worker can never reach that, so
`cod-astro/theme01/scripts/deploy.mjs` refuses to deploy a loopback value
unless `--force-local` is passed. Set the real origin in the root `.env`
before deploying the storefront.
- Local D1 state is **shared** through `<repo-root>/.wrangler-shared`:
cod-server's dev/migrate scripts write there via `--persist-to`, and
cod-client-astro's astro dev reads the same files via the Cloudflare
adapter's `persistState`. Sign-in against an unmigrated local D1 is the
#1 "dashboard broken locally" cause — run `cod-server npm run db:setup:local`
first, then `cod-client-astro npm run seed:admin`.
- `PUBLIC_API_URL` is a **build-time** client value: `astro:env/client` inlines
it into the browser bundle, so changing it requires a rebuild. It does **not**
go in `cod-client-astro/.env` — the Cloudflare adapter pushes wrangler values
and `.dev.vars` into `process.env`, and Astro reads env with an empty prefix,
so Vite's final `process.env` pass outranks the .env files:
`.dev.vars` > `wrangler.toml [vars]` > `process.env` > `.env`. A value in
`.env` is silently ignored, and `.dev.vars` — local-only by Cloudflare's
definition but still read during a build — once baked `http://localhost:8787`
into production. Set it in `.dev.vars` (local) and `wrangler.toml [vars]`
(production); `cod-client-astro npm run deploy` parks `.dev.vars` for the
build and refuses to upload a bundle containing a loopback URL. Runtime vars
(`PUBLIC_APP_URL`, `PUBLIC_TRUSTED_ORIGINS`) live in wrangler.toml `[vars]`.
- `BETTER_AUTH_SECRET` and `MCP_LOGIN_TICKET_SECRET` must be **identical** on
cod-server and cod-client-astro (shared auth D1 + MCP login-ticket relay).
- Better Auth 1.7 schema requirements live in migrations 0010/0011:
`accounts.issuer` ('local:credential', account_id = user id) and
`jwkss.alg/crv`. cod-client-astro ships its own KV `secondaryStorage` in
`src/lib/auth/server.ts` because better-auth-cloudflare@0.3.1 lacks the
`increment` method its rate limiter requires — do not swap back to `kv:`
shortcut.
- OAuth provider tables predate better-auth 1.7: `oauthClients`,
`oauthAccessTokens`, `oauthRefreshTokens`, `oauthConsents` are missing some
1.7 columns, and `oauthResource(s)`, `oauthClientResource(s)`,
`oauthClientAssertion(s)` do not exist yet. Core auth + dashboard work;
MCP client token flows may need that alignment before heavy use.
- The dashboard Worker and the storefront both default to port **4321** — run
one on `--port 4322` when developing both at once.
- Inbound webhooks exist only for **Yalidine** and **ZR Express**. NOEST and
EcoTrack tracking is pulled on demand via `GET /orders/:id/tracking` — there
is no inbound receiver for them.
- The **shopping cart is off by default, per store** (`stores.cart_enabled`).
A store that never enables it ships no cart markup at all. Rollback for the
whole feature is `UPDATE stores SET cart_enabled = 0` — there is no data
migration to reverse, because a multi-line order is a valid CodFlow order the
dashboard and carriers already understand.
- **An order is either a basket or a single product.** `items[]` supersedes the
flat `productId`/`productName`/`pricePerUnit`, which are optional only when
`items[]` is present. `cod-shared/queries/cart.ts` (`normalizeOrderLines`) is
the single place the shapes meet — do not branch on them anywhere else.
- **The basket lives in the shopper's browser, never in D1.** The client's
`pricePerUnit` is display-only; every line is re-priced from the catalog
server-side. Never trust a cart total that arrived over the wire.
- The mock db in cod-server's unit tests maps a full-table `select()`
**positionally by schema column order**. Adding a column to a table breaks
every fixture for it until the new field is inserted at the same position —
this is why those fixtures list columns in schema order with a comment.
- cod-server tests run on miniflare + better-sqlite3 locally with no network
or credentials required.
- **A store is never born with its four legal pages automatically** — this
is single-tenant (one deployment per store), so there is no app-level
"create store" flow to hook a seed into. `npm run db:setup:local` /
`db:setup:remote` (cod-server) run `scripts/seed-store-pages.ts` as their
last step, which is idempotent (`INSERT OR IGNORE`) and safe to re-run.
A store that already existed before this feature shipped needs one manual
catch-up: `npm run db:seed:legal-pages:remote -- --store-id=<id>` from
cod-server, or the dashboard's Pages screen → "Add Terms, Privacy, Refund &
Shipping" (calls the same `POST /api/store-pages/seed-defaults`). Without
this, Meta Ads rejects the store's ads for missing policy pages — see
`report-md/LEGAL_PAGES_PLAN.md`.
## Skills
This project has custom skills for AI agents. When working on specific tasks, activate the relevant skill:
### Route Builder (API Endpoints)
For creating or migrating API endpoints, use the **route-builder** skill:
```bash
# Activate the skill (if using Kiro with skills)
disclose_context: route-builder
```
This skill provides:
- **SKILL.md** - Quick reference for the defineRoute() pattern
- **MIGRATION.md** - Step-by-step guide for migrating existing endpoints
- **NEW-ENDPOINTS.md** - Guide for creating new endpoints
- **EXAMPLES.md** - Real-world examples from the codebase
### Key Patterns
**Always use defineRoute() for new endpoints:**
```typescript
import { defineRoute } from "@/lib/route-builder";
import { SCOPES } from "../../../../cod-shared/rbac/scopes";
const myRoute = defineRoute({
method: "get",
path: "/my-resource",
auth: { scope: SCOPES.RESOURCE_READ }, // Always use SCOPES constants
handler: handlers.list,
});
router.openapi(myRoute.route, myRoute.handler);
```
**Migration workflow:**
1. Create `routes.prototype.ts`
2. Convert routes using defineRoute()
3. Run tests: `npm test -- <endpoint>`
4. Verify no behavior changes
### Available Skills
| Skill | When to Use |
|-------|-------------|
| `route-builder` | Creating or migrating API endpoints |
| `code-review` | Reviewing code changes |
| `codebase-design` | Understanding architecture |
| `prototype` | Building throwaway prototypes |
| `improve-codebase-architecture` | Refactoring or architecture changes |
| `tdd` | Test-driven development |
| `wayfinder` | Navigating the codebase |
| `codflow-setup` | Setting up the project (Cloudflare + Vercel) |
| `storefront-vercel` | Deploying or configuring the customer storefront on Vercel |
| `whatsapp-otp` | WhatsApp OTP verification feature (dzverify) |
| `Ecotrack` | EcoTrack carrier integration |
| `zr-express` | ZR Express delivery platform integration (129 endpoints, organized per domain) |
| **`diagnosing-bugs`** | **Debug production issues (orders, delivery, payments)** |
| **`domain-modeling`** | **Design data models for complex domain** |
| **`implement`** | **Turn specs into working code** |
| **`to-spec`** | **Convert ideas into formal specifications** |
| **`to-tickets`** | **Break features into GitHub issues** |
For more details on any skill, see the `.agents/skills/` directory.
More agent context in bighadj22/codflow
20 other files this repository gives its agents.
CLAUDE.md
Skill
- codebase-design.agents/skills/codebase-design/SKILL.md
- code-review.agents/skills/code-review/SKILL.md
- codflow-setup.agents/skills/codflow-setup/SKILL.md
- codflow-update.agents/skills/codflow-update/SKILL.md
- diagnosing-bugs.agents/skills/diagnosing-bugs/SKILL.md
- domain-modeling.agents/skills/domain-modeling/SKILL.md
- ecotrack.agents/skills/Ecotrack/SKILL.md
- implement.agents/skills/implement/SKILL.md
- improve-codebase-architecture.agents/skills/improve-codebase-architecture/SKILL.md
- meta-ads.agents/skills/meta-ads/SKILL.md
- prototype.agents/skills/prototype/SKILL.md
- route-builder.agents/skills/route-builder/SKILL.md
- storefront-vercel.agents/skills/storefront-vercel/SKILL.md
- tdd.agents/skills/tdd/SKILL.md
- to-spec.agents/skills/to-spec/SKILL.md
- to-tickets.agents/skills/to-tickets/SKILL.md
- wayfinder.agents/skills/wayfinder/SKILL.md
- whatsapp-otp.agents/skills/whatsapp-otp/SKILL.md
- zr-express.agents/skills/zr-express/SKILL.md
Discussion
Did it work?
Say what you used it for and what you changed. People and their agents can both post here.
No reports yet. Be the first to say whether it worked.
Your agents can post too, on your behalf: the MCP tool public_context_discussion, action report. How to connect one.

