diff --git a/.claude/agents/code-standards-enforcer.md b/.claude/agents/code-standards-enforcer.md new file mode 100644 index 0000000000..e1191ee8c0 --- /dev/null +++ b/.claude/agents/code-standards-enforcer.md @@ -0,0 +1,150 @@ +--- +name: code-standards-enforcer +description: "Audits recently written or modified code against CLAUDE.md rules, patterns-in-transition, and checklist files. Covers CDP-specific patterns: pg-promise over Sequelize, functional services over classes, single-tenant via DEFAULT_TENANT_ID, Auth0 auth, Zod + validateOrThrow for public endpoints, query performance, and Temporal workflow rules. Invoked in background by review-pr." +model: inherit +color: red +memory: none +--- + +# Code Standards Enforcer + +You are an elite code standards enforcement specialist. Your singular mission is to audit recently written or modified code against the project's CLAUDE.md guidelines, rule files, and checklist files, catching violations before they enter the codebase. + +## Your Primary Directive + +Read and internalize every rule, convention, pattern, and guideline described in CLAUDE.md. These are law. When CLAUDE.md references other documents (rule files in `.claude/rules/`, checklist files under `.claude/skills/review-pr/references/`), read and enforce those too. + +## Enforcement Process + +### Step 1: Load All Reference Documents + +- Read the project's `CLAUDE.md` thoroughly +- Read the user's global CLAUDE.md at `~/.claude/CLAUDE.md` if it exists +- Glob `.claude/rules/*.md` and read every rule file +- Read all checklists under `.claude/skills/review-pr/references/` +- Build a mental checklist of every enforceable rule + +### Step 2: Identify Recently Changed Code + +- Use `git status` or `git diff` to identify changed files +- Categorize changes: backend (`backend/`), frontend (`frontend/`), services (`services/apps/*`, `services/libs/*`), migrations, SQL + +### Step 3: Systematic Audit + +For each changed file, check against ALL applicable rules. The patterns-in-transition from CLAUDE.md are the highest priority: + +#### Patterns in Transition (enforce on ALL new code) + +- [ ] **No new Sequelize usage** — all new DB code uses `queryExecutor` from `@crowd/data-access-layer`. Legacy Sequelize in `backend/src/database/repositories/` and `backend/src/services/` is exempt. +- [ ] **No new class-based services or repositories** — plain functions only +- [ ] **No new multi-tenant logic** — use `DEFAULT_TENANT_ID` from `@crowd/common` +- [ ] **New public endpoints use Zod + `validateOrThrow`** from `@crowd/common` +- [ ] **Auth0 patterns** — no new legacy JWT patterns +- [ ] **No `any` types** in new code + +#### Backend Rules + +- [ ] New DAL functions checked against existing equivalents (blast-radius risk) +- [ ] Parameterized queries only — no string interpolation with user input +- [ ] `$N` placeholder count matches bind values array length +- [ ] No secrets hardcoded — env vars only +- [ ] Query performance: indexes considered for WHERE clauses on large tables + +#### Services Rules (Temporal/Kafka/Redis workers) + +- [ ] Temporal workflows are deterministic — no I/O, no `Math.random()`, no `Date.now()` inside workflow code +- [ ] Kafka/Redis calls are in Activities only, not Workflows +- [ ] Activities are idempotent where possible +- [ ] Logger from `@crowd/logging` — no `console.log` + +#### Frontend Rules + +- [ ] ` +``` + +**Fix:** +```vue + +``` + +--- + +## 2. TanStack Vue Query for server state (SHOULD FIX) + +Use `useQuery` / `useMutation` from TanStack Vue Query for data fetching. Do not use raw `axios` directly in `onMounted` for data that should be cached. + +**Violation:** +```ts +const data = ref(null) +onMounted(async () => { + data.value = await axios.get('/api/members') +}) +``` + +**Fix:** +```ts +import { useQuery } from '@tanstack/vue-query' +const { data } = useQuery({ + queryKey: ['members'], + queryFn: () => axios.get('/api/members').then(r => r.data), +}) +``` + +--- + +## 3. Pinia for shared client state (SHOULD FIX) + +Use Pinia stores for shared client-side state. Do not pass deeply nested props for state that should be in a store. + +--- + +## 4. TypeScript — no `any` (SHOULD FIX) + +Avoid `any`. Use proper types, `unknown` with narrowing, or generics. + +--- + +## 5. Tailwind CSS conventions (SHOULD FIX) + +- **Prefer `gap-*` over `space-y-*`** for vertical stacking +- No hard-coded hex color values in templates — use Tailwind color tokens + +--- + +## 6. Reactive refs over non-reactive values (SHOULD FIX) + +State that should trigger re-renders must use `ref()` or `computed()`. + +**Violation:** +```ts +let isLoading = false // won't trigger re-render +``` + +**Fix:** +```ts +const isLoading = ref(false) +``` + +--- + +## 7. Element Plus usage patterns (NIT) + +The project uses Element Plus (`el-*`). Follow existing component usage patterns — check how similar components are used elsewhere before introducing a new pattern. diff --git a/.claude/skills/review-pr/references/services-checklist.md b/.claude/skills/review-pr/references/services-checklist.md new file mode 100644 index 0000000000..570719b064 --- /dev/null +++ b/.claude/skills/review-pr/references/services-checklist.md @@ -0,0 +1,51 @@ +# Services Review Checklist + +Review standards for microservices under `services/apps/` and shared libraries under `services/libs/`. + +--- + +## Temporal Worker patterns (`services/apps/*/`) + +### 1. Workflows must be deterministic (CRITICAL) + +Temporal workflows must be fully deterministic. No direct I/O, no `Math.random()`, no `Date.now()`, no non-deterministic APIs inside workflow code. Move all I/O into Activities. + +### 2. Activities should be idempotent (SHOULD FIX) + +Temporal may retry activities on failure. Activities should be safe to run multiple times without unintended side effects. + +### 3. No direct Kafka/Redis calls inside Temporal workflows (CRITICAL) + +Kafka producers and Redis clients must only be called from Activities, not from Workflow code. + +--- + +## Shared Libraries (`services/libs/*/`) + +### 4. New DAL functions — check for existing equivalents first (SHOULD FIX) + +Before adding a new function to `services/libs/data-access-layer/src/`, verify no equivalent exists. + +### 5. `queryExecutor` from `@crowd/data-access-layer` (CRITICAL) + +All new database queries must use `queryExecutor`. Do not add Sequelize or raw `pg` queries to service libraries. + +### 6. Query performance awareness (SHOULD FIX) + +Flag queries that clearly scan large tables without an appropriate WHERE clause using an indexed column. + +### 7. Bunyan logger usage (SHOULD FIX) + +Use the logger from `@crowd/logging`, not `console.log/error/warn`. + +### 8. New class-based code (SHOULD FIX) + +New service/worker code should use plain functions, not class-based patterns. Classes are legacy. + +--- + +## Known false positives — do NOT flag + +- Existing class-based workers that have not been refactored — only flag **new** classes +- `queryExecutor` usage in `services/libs/data-access-layer/` — correct pattern +- `DEFAULT_TENANT_ID` from `@crowd/common` — correct pattern diff --git a/.claude/skills/review-pr/references/sql-checklist.md b/.claude/skills/review-pr/references/sql-checklist.md new file mode 100644 index 0000000000..892a524743 --- /dev/null +++ b/.claude/skills/review-pr/references/sql-checklist.md @@ -0,0 +1,75 @@ +# SQL & Migration Review Checklist + +Review standards for database queries in `services/libs/data-access-layer/` and migrations in `backend/src/database/migrations/`. + +--- + +## Flyway Migrations + +### 1. Migrations are append-only (CRITICAL) + +Never modify an existing migration file that has been applied. Create a new migration to alter or fix a previous one. + +**Violation:** Editing `V1234__create_members_table.sql` after it has been applied. + +**Fix:** Create `V1235__alter_members_add_column.sql` with the corrective change. + +--- + +### 2. Migration filename format (SHOULD FIX) + +Migration files must follow: `V{epoch}__{description}.sql` and `U{epoch}__{description}.sql` (undo). The version must be unique and greater than all existing versions. + +--- + +### 3. Migrations must be safe for production (CRITICAL) + +Avoid: +- `DROP TABLE` without verifying data is no longer needed +- `ALTER TABLE ... NOT NULL` without a default or two-step migration (add nullable first, backfill, then add constraint) +- Renaming columns without updating all code references first +- Large table operations without considering lock impact + +--- + +## Data Access Layer Queries + +### 4. Parameterized queries only — no string interpolation (CRITICAL) + +All queries must use parameterized placeholders (`$1`, `$2`, etc.). Never interpolate user input directly into SQL. + +**Violation:** +```ts +await queryExecutor.query(`SELECT * FROM members WHERE email = '${email}'`) +``` + +**Fix:** +```ts +await queryExecutor.query('SELECT * FROM members WHERE email = $1', [email]) +``` + +--- + +### 5. Placeholder count matches bind values (CRITICAL) + +Every `$N` placeholder must have a corresponding value in the binds array, in correct order. Mismatch causes runtime errors. + +--- + +### 6. Index awareness (SHOULD FIX) + +Before writing a query, verify the table has an index on the WHERE clause columns. Flag queries that will cause full table scans on large tables (`members`, `activities`, `organizations`). + +Common indexed columns: `id`, `tenantId`, `platform`, `sourceId`, `memberId`, `organizationId`, `timestamp`, `deletedAt`. + +--- + +### 7. Blast radius check for modified DAL functions (SHOULD FIX) + +If a shared DAL function in `services/libs/data-access-layer/src/` is modified, check all callers. Use `grep -r "functionName" services/ backend/` to find them. + +--- + +### 8. Soft-delete awareness (SHOULD FIX) + +Many tables use `deletedAt` for soft deletes. Queries that don't filter on `deletedAt IS NULL` may return deleted records. Verify the intended behavior. diff --git a/AGENTS.md b/AGENTS.md new file mode 120000 index 0000000000..681311eb9c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1 @@ +CLAUDE.md \ No newline at end of file diff --git a/docs/adr/README.md b/docs/adr/README.md new file mode 100644 index 0000000000..6e2c3ae031 --- /dev/null +++ b/docs/adr/README.md @@ -0,0 +1,20 @@ +# Architecture Decision Records + +Architecture Decision Records (ADRs) capture significant technical decisions made in this project, including context, alternatives considered, and consequences. + +Use the `/adr` skill in Claude Code to record new ADRs or query past decisions. + +## Index + +| ADR | Title | Status | Date | +| --- | ----- | ------ | ---- | +| _none yet_ | | | | + +## Why ADRs? + +The codebase is in active transition across several axes (see `CLAUDE.md`). ADRs provide a durable record of: +- Why old patterns are being replaced (e.g. Sequelize → pg-promise) +- What alternatives were considered before choosing the current approach +- What trade-offs were accepted + +New contributors can understand constraints without needing to ask — the reasoning is in the ADRs. diff --git a/docs/adr/template.md b/docs/adr/template.md new file mode 100644 index 0000000000..f21d8c134e --- /dev/null +++ b/docs/adr/template.md @@ -0,0 +1,36 @@ +# ADR-NNNN: [Decision Title] + +**Date**: YYYY-MM-DD +**Status**: proposed | accepted | deprecated | superseded by ADR-NNNN +**Deciders**: [who was involved] + +## Context + +[2–5 sentences describing the situation, constraints, and forces at play. What problem prompted this decision?] + +## Decision + +[1–3 sentences stating the change clearly and unambiguously. "We decided to..."] + +## Alternatives Considered + +### Alternative 1: [Name] +- **Pros**: [benefits] +- **Cons**: [drawbacks] +- **Why not**: [specific rejection reason] + +### Alternative 2: [Name] +- **Pros**: [benefits] +- **Cons**: [drawbacks] +- **Why not**: [specific rejection reason] + +## Consequences + +### Positive +- [benefit 1] + +### Negative +- [trade-off 1] + +### Risks +- [risk and how it's mitigated]