| name | code-standards |
| description | Enforces TypeScript and React code standards for this project — English identifiers, 60-line limit, verb-based naming, control flow, and type organization. Use when writing, reviewing, or refactoring any TypeScript or React code. |
Code Standards
These conventions apply to all TypeScript and React code in this project. For setup, commands, ports, dependencies, and folder layout, see AGENTS.md. For React-specific rules, see react. For testing, see test.
Language
All code — identifiers, comments, commit messages, and user-facing copy in code — must be written in English.
const nomeDoJogador = "Pedro";
const playerName = "Pedro";
UI copy shown to end users may stay in Portuguese when required by product/design; implementation code stays in English.
Function and component size
Methods, functions, and components must not exceed 60 lines (including blank lines). Extract helpers, hooks, or sub-components when logic grows.
export function ExperienceTimelineBody() {
}
export function ExperienceCardBody() {
const carousel = useHighlightCarousel(EXPERIENCE_SLIDES);
return (
<InsightCard>
<InsightHeader title="Experience" icon={BriefcaseIcon} cardId="experience" onViewAll={onViewAll} />
<InsightSlide slide={carousel.slide} />
<InsightNav title="Experience" index={carousel.index} total={carousel.total} onGoTo={carousel.goTo} onPrevious={carousel.showPrevious} onNext={carousel.showNext} />
</InsightCard>
);
}
Parameter count
Avoid passing more than 3 parameters. Prefer an options object or a typed config when you need more data.
function createOrder(planId: string, email: string, players: Player[], method: string) {}
interface CreateOrderInput {
planId: PlanId;
email: string;
players: Player[];
paymentMethod: PaymentMethod;
}
function createOrder(input: CreateOrderInput) {}
Control flow
Do not nest if/else blocks. Avoid switch statements. Prefer early returns, guard clauses, lookup maps, or small extracted functions.
function getStatusLabel(status: OrderStatus) {
if (status === "pending") {
if (paymentConfirmed) {
return "Processing";
} else {
return "Awaiting payment";
}
} else {
return "Complete";
}
}
function getStatusLabel(status: OrderStatus) {
switch (status) {
case "pending":
return "Pending";
case "paid":
return "Paid";
default:
return "Unknown";
}
}
function getStatusLabel(status: OrderStatus, paymentConfirmed: boolean) {
if (status === "complete") return "Complete";
if (status === "pending" && paymentConfirmed) return "Processing";
if (status === "pending") return "Awaiting payment";
return "Paid";
}
const STATUS_LABELS: Record<OrderStatus, string> = {
pending: "Pending",
paid: "Paid",
complete: "Complete",
};
Naming functions and methods
Function and method names must start with a verb that describes the action.
function player(data: PlayerData) {}
function validation(email: string) {}
function buildPlayerPayload(data: PlayerData) {}
function validateEmail(email: string) {}
function fetchRemotePlans() {}
function renderCheckoutSummary() {}
React components use PascalCase nouns (e.g. StepResumo, OrderStatusView); hooks use the use prefix with a verb phrase (e.g. useOrderWizard, usePaymentForm).
Naming variables
Variable names must be clear and objective. Prefer full words over abbreviations. Name by purpose, not by type alone.
const d = new Date();
const arr = players.filter((p) => p.ok);
const temp = response.data;
const createdAt = new Date();
const completePlayers = players.filter(isPlayerComplete);
const order = response.data;
Booleans should read as questions: isValid, hasPhotos, canSubmit. Collections use plural nouns: players, plans. Avoid vague names like data, info, item, or handleStuff.
Type file organization
Each type must live in its own file when it is exported and reused outside a single module. Keep related types together only when they always belong to the same domain and change together. See AGENTS.md for folder placement.
One type per file (required)
Create a dedicated file in src/types/ when the type is:
| Case | File example | Type example |
|---|
| Shared across folders | src/types/order.ts | OrderDraft, OrderStatus |
| A domain entity or DTO | src/types/player.ts | PlayerData |
| An API contract | src/types/api.ts | RemotePlan, ApiErrorBody |
| Context or store state | src/types/order-wizard.ts | OrderWizardState |
| Used by both client and server | src/types/payment.ts | PaymentMethod |
export interface OrderDraft {}
export interface RemotePlan {}
export interface ClubOption {}
export interface OrderDraft {}
export type OrderStatus = "pending" | "paid" | "complete";
export interface RemotePlan {}
export type PlanId = "experimento" | "mais-escolhido" | "colecionador";
Name files after the domain, not a single type name: order.ts, not OrderDraft.ts.
Same file allowed
Keep types in the same file when they are:
| Case | Location | Example |
|---|
| Props for a single component | Same file as the component, or a sibling ComponentName.types.ts | ButtonProps in Button.tsx |
| A type alias tightly coupled to one function | Next to that function | CreateOrderInput in orders.service.ts |
| Union members of the same concept | One domain file in src/types/ | PlanId, Plan, StickerType in plan.ts |
| Inferred from a Zod schema | Same file as the schema in src/schemas/ | PagamentoStepValues from pagamento.schema.ts |
| Private to one module, never exported | Bottom of the module that uses it | `type SortDirection = "asc" |
interface ButtonProps {
variant?: "primary" | "secondary";
href?: string;
}
export function Button({ variant = "primary", href }: ButtonProps) {}
export type PlanId = "experimento" | "mais-escolhido" | "colecionador";
export type StickerType = "normal" | "brilhosa";
export interface Plan {
id: PlanId;
stickerType: StickerType;
price: number;
}
When to split into a new file
Extract a type into its own file in src/types/ when any of these is true:
- The type is imported from more than one folder (
components/, services/, app/, etc.).
- The host file would exceed 60 lines mainly because of type definitions.
- The type represents a separate domain concept (do not mix
Order and Plan types).
- The type is part of the public API of a service or route handler.
export interface OrderDraft {}
export async function createOrder(input: OrderDraft) {}
export interface OrderDraft {}
import type { OrderDraft } from "@/types/order";
export async function createOrder(input: OrderDraft) {}
File naming
| Kind | Pattern | Example |
|---|
| Shared domain types | src/types/<domain>.ts | order.ts, payment.ts |
| Component-only props | <Component>.types.ts or inline | Button.types.ts |
| Zod schemas + inferred types | src/schemas/<feature>.schema.ts | jogador.schema.ts |
Do not create a separate file for every single type or interface alias. Create a separate file per domain; split further only when reuse or file size requires it.
Quick checklist
Before opening a PR, confirm: