Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Code Conventions

This page documents the coding standards and conventions used across the Aero2 codebase.

Language

TypeScript everywhere. Both backend (Cloudflare Worker) and frontend (React) code is written in TypeScript with strict type checking enabled.

Linting and Formatting

Aero2 uses Biome for both linting and formatting:

# Check for lint errors
npm run lint
 
# Auto-fix lint errors
npm run lint:fix

Biome configuration is in biome.json at the project root. CI fails on lint errors.

Backend Conventions

Hono Framework

The backend uses Hono for HTTP routing. The app is typed with environment bindings:

import { Hono } from "hono";
 
const app = new Hono<{ Bindings: Env }>();

The Env type is generated from wrangler.json bindings using npm run cf-typegen, which produces worker-configuration.d.ts.

Request Validation

All request bodies and query parameters are validated using Zod schemas:

import { z } from "zod";
 
const createClientSchema = z.object({
  name: z.string().min(1).max(255),
  redirect_uris: z.array(z.string().url()),
  scopes: z.array(z.string()),
  grant_types: z.array(z.enum(["authorization_code", "refresh_token"])),
});
 
app.post("/api/clients", async (c) => {
  const body = createClientSchema.parse(await c.req.json());
  // ...
});

Database Queries

All D1 queries use parameterized statements. Never interpolate user input into SQL strings:

// Correct
const user = await env.DB.prepare(
  "SELECT * FROM users WHERE email = ? AND app_id = ?"
).bind(email, appId).first();
 
// WRONG - SQL injection risk
const user = await env.DB.prepare(
  `SELECT * FROM users WHERE email = '${email}'`
).first();

Error Handling

Return appropriate HTTP status codes with JSON error bodies. Never expose internal error details to clients:

// Good: generic error message
return c.json({ error: "Invalid credentials" }, 401);
 
// Bad: leaks internal details
return c.json({ error: `Database error: ${err.message}` }, 500);

Log detailed errors server-side for debugging:

console.error("Token verification failed:", err);
return c.json({ error: "Authentication failed" }, 401);

Frontend Conventions

React Components

  • Use functional components with hooks (no class components)
  • Use CSS Modules for component styling (.module.css files)
  • Components live in src/frontend/components/; pages in src/frontend/pages/

State Management

  • Use React Context for shared state (AuthContext)
  • Use useState and useReducer for local component state
  • No external state management library (Redux, Zustand, etc.)

Naming Conventions

CategoryConventionExample
Variables and functionscamelCasegetUserById, isAuthenticated
React componentsPascalCaseLoginPage, UserCard
TypeScript types and interfacesPascalCaseUserProfile, AuthState
Files (general)kebab-caseauth-context.ts, rate-limit.ts
Files (React components)PascalCaseLogin.tsx, AdminUsers.tsx
CSS moduleskebab-caselogin-page.module.css
Database columnssnake_casecreated_at, app_id
API routeskebab-case/api/audit-logs, /api/api-keys
Environment variablesUPPER_SNAKE_CASEMASTER_KEY, PLATFORM_DOMAIN

Exports

  • No default exports except for the Worker entry point (export default app) and React page components
  • Use named exports for utilities, types, middleware, and shared components
  • This ensures consistent import naming and better IDE support
// Good: named export
export function hashPassword(password: string): Promise<string> { ... }
 
// Only for Worker entry point
export default app;

Comments

  • Add comments for complex business logic, security-critical code, and non-obvious decisions
  • Do not add comments for self-explanatory code
  • Use // TODO: for known technical debt (include a brief description of what needs to change)

Security Practices in Code

  • Always include app_id in database queries for tenant-scoped tables
  • Always validate user input with Zod schemas before processing
  • Never log sensitive data (passwords, tokens, secrets)
  • Use parameterized queries for all database operations
  • Use constant-time comparison for secret verification
  • Set appropriate cookie attributes (HttpOnly, Secure, SameSite)