Next.js 16 app (App Router) with React 19, TypeScript 7, Tailwind CSS 4, HeroUI, and Tremor.
API requests are proxied to an external backend via Next.js rewrites (next.config.js).
| Task | Command |
|---|---|
| Dev | pnpm dev |
| Build | pnpm build — runs next build --turbopack |
| Lint | pnpm lint — runs eslint --fix |
| Typecheck | pnpm typecheck — runs tsc --noEmit |
| Format | pnpm format — runs Prettier on all source files |
Package manager: pnpm only (v10). Do not use npm or yarn.
No test framework is configured. There are no test scripts, test dependencies, or test files. Do not attempt to run or create tests unless explicitly asked.
Always run pnpm lint after making changes to verify code passes lint rules.
- Dual install via npm aliases.
typescriptis aliased to@typescript/typescript6@^6.0.2and is consumed by@typescript-eslint/*(which still requires TS 6's API).@typescript/nativeis aliased totypescript@^7.0.2and is consumed bytsc/pnpm typecheck. As a resultnpx tscruns TS 7 (native) andnpx tsc6runs TS 6. Do not consolidate these into a single install. - VS Code: install the
TypeScriptTeam.native-previewextension to enable the TS 7 language server. Toggle via the "Enable/Disable TypeScript 7 Language Server" commands from the palette. - Strict mode enabled (
strict: true) - Target: ES2022, module resolution: bundler
- Path alias:
@/*maps to project root — use@/lib/...,@/components/..., etc. - No
noEmitrestrictions for type-checking; types are project-referenced via Next.js - On memory-constrained CI runners, pass
--checkers 2totscto reduce memory usage.
- Double quotes (no single quotes)
- 2-space indentation, no tabs
- 80 character line width
- Trailing commas: es5
- Semicolons: always
- Arrow function parens: always
- End of line: LF
These rules are warn and will be flagged. Follow them to avoid lint failures.
Imports must be grouped with a blank line between each group, in this order:
typeimportsbuiltin(Node built-ins)object(TypeScript/TSlib)external(npm packages)internal(@/*aliased paths)parent(../)sibling(./)index(./index)
The ~/** pattern is grouped after external.
Example:
import type { ReactNode } from "react";
import fs from "fs";
import { Button } from "@heroui/react";
import { apiClient } from "@/lib/api/client";
import { siteConfig } from "@/config/site";
import { helper } from "../utils";
import { localHelper } from "./helper";Props must be ordered:
reservedFirst—keyandrefcome firstshorthandFirst— shorthand props (e.g.,disabled,loading) before value props- Alphabetical — remaining props sorted A–Z
callbacksLast— callback/event handler props (onClick,onChange, etc.) come last
Example:
<Button key="btn" disabled loading variant="primary" onClick={handleClick}>
Save
</Button>- Blank line before every
returnstatement - Blank line between different statement types (e.g., after
constblock before anif) - No extra blank line between same-type statements (multiple
constdeclarations)
All unused imports are flagged. Remove any import you don't actually use.
Variables prefixed with _ are allowed to be unused (e.g., _event, _index).
Components without children must be self-closing: <MyComponent /> not <MyComponent></MyComponent>.
console.log / console.warn / etc. are warn. Do not add console statements.
app/ — Next.js App Router pages and layouts
components/ — Reusable React components
primitives.ts — Tailwind Variants (tv) style definitions
config/
site.ts — Site-wide config (typed via typeof pattern)
api-origin.js — API origin resolution (server vs client)
constants/
endpoints.ts — API endpoint constants
hooks/ — Custom React hooks
lib/
api/
client.ts — ApiClient class + ApiError class (singleton: apiClient)
hooks.ts — SWR data-fetching hooks
types/ — TypeScript type definitions
index.ts — Barrel export
enums/ — Enum definitions (faction, item-quality, etc.)
components/ — Component-specific types
data/ — Data/input types
validation/ — Validation schemas
styles/
globals.css — Tailwind layers + custom utility classes
tokens.css — CSS custom properties for theming
- App Router defaults to Server Components
- Add
"use client"directive only when the component needs state, effects, event handlers, or browser APIs - Data fetching in server components uses
ApiClientdirectly; client components use SWR hooks fromlib/api/hooks.ts
- Server-side: use
apiClient.get<T>(endpoint, params)from@/lib/api/client - Client-side: use SWR hooks from
@/lib/api/hooks.tswithdefaultConfig - API endpoints are defined as constants in
@/constants/endpoints
- Tailwind CSS 3 with Tailwind Variants (
tv) for component variants - CSS custom properties in
styles/tokens.cssfor theming (--bg,--text,--primary,--accent, etc.) - Custom utility classes in
globals.css(.card-surface,.btn,.chip) - HeroUI components with Tremor for data visualization
- Types live in
lib/types/with barrel exports viaindex.ts - Use
export typefor type-only exports - Enum-like constants use
as constwith derived types - Config pattern:
type X = typeof x(seeconfig/site.ts)
- API errors use the
ApiErrorclass from@/lib/api/client - Validation uses Yup schemas (
yuppackage) with@hookform/resolvers - Forms use
react-hook-formfor state management
| Purpose | Package |
|---|---|
| UI Framework | HeroUI (@heroui/*) |
| Charts | Tremor (@tremor/react) |
| Data Fetching | SWR |
| Forms | react-hook-form + Yup |
| Styling | Tailwind CSS + tailwind-variants |
| Date Formatting | dayjs |
| Animation | framer-motion |
| Markdown Rendering | react-markdown |
| Theme Switching | next-themes |
Use conventional commits:
git commit -m "type(scope): description"Types: feat, fix, refactor, docs, style, test, chore
Rules:
- Commit only staged changes
- Split logical changes into separate commits - each commit should represent one logical change that could be reverted independently
- Never mix refactoring, formatting, or cleanup changes with new features or bug fixes in the same commit
- Order commits logically so each builds on the previous one
- Use short lowercased commit message, with no description body