Code Standards

Doc Status: Good | ✓ Clear summary | ✓ Easy to read | ✓ Matches code | ✓ Good structure | ✓ Professional look | ✓ Visual components

File Naming

TypeConventionExample
Pageskebab-case.tsxuser-profile.tsx
Componentskebab-case.tsxbutton-primary.tsx
Hooksuse-kebab-case.tsuse-user-profile.ts
Utilskebab-case.tsformat-date.ts
Types/Interfaceskebab-case.types.tsuser.types.ts
Testskebab-case.test.tsuser-service.test.ts
Exception: Convex source modules use camelCase.ts (e.g. students.ts) — the Convex runtime rejects hyphens in module paths.

Import Conventions

Path Aliases

{
  "compilerOptions": {
    "paths": {
      "~/*": ["./src/*"],
      "@wds/ui": ["../../packages/ui/src"],
      "@packages/backend/*": ["../../packages/backend/*"]
    }
  }
}

Tilde for Project Imports

// ✅ GOOD — tilde path alias
import { Button } from '~/components/ui/button';
import { cn } from '~/lib/cn';

// ❌ BAD — relative path
import { Button } from '../../../components/ui/button';
Same-directory relative imports are allowed.

No Barrel Files

Never use index.ts barrel files. Import directly from the specific file.
// ❌ BAD — barrel file
import { UserService, UserRepository } from '~/domain/user';

// ✅ GOOD — direct import
import { UserService } from '~/application/user/user.service';
Exception: packages/backend/convex/_generated/api is auto-generated by Convex — importing api from it is the standard pattern.

TypeScript Rules

No any Type

Never use any — it bypasses TypeScript’s type checking.
// ❌ BAD
const items: any[] = [];
const data: any = fetchSomething();

// ✅ GOOD — use unknown + type guard or Zod
const items: unknown[] = [];
const data = DataSchema.parse(rawData);

No Type Assertions (as)

Never use as type assertions — they bypass type checking.
// ❌ BAD
const user = data as User;

// ✅ GOOD — Zod or type guard
const user = UserSchema.parse(data);

Boolean Naming

PrefixUse forExample
isCurrent stateisLoading, isActive
hasPossession / containmenthasPermission
canCapabilitycanDelete
shouldDecision / conditionshouldRefetch

Explicit Naming

// ❌ BANNED
function handle(x) {}
const data = await api.users.list();
const res = response;

// ✅ REQUIRED
function sendWelcomeEmail(userId: string) {}
const userList = await api.users.list();
const httpResponse = response;

No console.log

Use consola for structured logging:
import { consola } from 'consola';

// ❌ BAD
console.log('User created:', user);

// ✅ GOOD
consola.success('User created', { userId: user.id });
LevelUse
debugDevelopment noise
infoNotable events
successSuccessful operations
warnRecoverable issues
errorErrors that need attention

ESLint Rules (Summary)

{
  "no-explicit-any": "error",
  "@typescript-eslint/consistent-type-definitions": ["error", "interface"],
  "react-hooks/exhaustive-deps": "error",
  "no-console": ["warn", { "allow": ["warn", "error", "info"] }],
  "prefer-const": "error",
  "no-var": "error"
}

Prettier Config

{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 100
}

Git Commit Format

Conventional Commits — required for all commits:
feat: add user enrollment form
fix: correct attendance calculation
docs: update deployment guide
refactor: split student service into separate modules