Imported from zihadm654/atcampus-dev (
AGENTS.md). Install upstream withnpx skills add zihadm654/atcampus-dev. Copyright stays with the author.
AGENTS.md - Agentic Coding Guidelines
Concise rules for building accessible, fast, delightful UIs. Use MUST/SHOULD/NEVER to guide decisions.
Commands
Development
pnpm dev # Start Next.js dev server
pnpm build # Production build
pnpm start # Start production server
pnpm email # Start email dev server (React Email)
Database
pnpm prisma:push # Push schema to database
pnpm prisma:migrate # Run migrations
pnpm prisma:generate # Generate Prisma client
Linting & Type Checking
pnpm lint # Run ESLint on all files
npx eslint <file> # Lint specific file
npx tsc --noEmit # TypeScript type check
Testing
pnpm test:polar # Run Polar integration tests
There is no Vitest/Jest test framework configured. Tests are run via scripts/test-polar.ts.
Code Style Guidelines
General
- TypeScript with strict mode enabled
- Use ES modules (
.ts,.tsxfiles) - Use
pnpmas package manager - Follow Next.js 16 conventions (App Router)
Imports
- Use absolute imports with
@/prefix (configured in tsconfig.json) - Order imports: external libs → internal libs → components → types
- Use explicit type imports:
import { type Foo } from "bar" - Group imports with blank lines between groups
// Good
import { useState } from "react";
import { useRouter } from "next/navigation";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import type { User } from "@/types/user";
Naming Conventions
- Files: kebab-case for utilities (
utils.ts), PascalCase for components (Button.tsx) - Components: PascalCase (e.g.,
AppSidebar) - Functions: camelCase (e.g.,
formatDate) - Constants: UPPER_SNAKE_CASE for config values, camelCase for others
- Types/Interfaces: PascalCase (e.g.,
UserProfile)
Types
- Enable strict TypeScript (
strict: truein tsconfig.json) - Prefer interfaces over types for object shapes
- Use explicit return types for utility functions
- Never use
any- useunknownif type is truly unknown
// Good
interface User {
id: string;
name: string;
email: string;
}
export function formatUser(user: User): string {
return `${user.name} (${user.email})`;
}
Error Handling
- Use try/catch with async/await
- Throw descriptive errors with context
- Handle errors at route/API boundary with proper HTTP status codes
- Use error boundaries for React component errors
// Good
async function getUser(id: string): Promise<User> {
const user = await db.user.findUnique({ where: { id } });
if (!user) {
throw new Error(`User with id ${id} not found`);
}
return user;
}
React/Next.js Patterns
- Use Server Components by default in App Router
- Mark client components with
"use client"directive at top - Use
use clientsparingly - only when needed (hooks, browser APIs, interactivity) - Use React Server Actions for mutations
- Fetch data in Server Components
- Use
nuqsfor URL state management
UI Components
- Use Radix UI primitives via
@radix-ui/react-*packages - Style with Tailwind CSS + cva (class-variance-authority)
- Use
cn()utility for conditional class merging - Follow shadcn/ui patterns for component structure
Database/Prisma
- Use Prisma ORM with PostgreSQL
- Define schema in
prisma/schema.prisma - Generate client after schema changes:
pnpm prisma:generate
Formatting
- No Prettier config - uses ESLint defaults
- Use ESLint for code formatting issues
- 2-space indentation in TypeScript/TSX
- Use double quotes in TypeScript
Security
- Never commit secrets - use
.envand.env.example - Validate all user input with Zod
- Use proper authentication/authorization checks
- Sanitize user-generated content before rendering
Interactions
- Keyboard
- MUST: Full keyboard support per WAI-ARIA APG
- MUST: Visible focus rings (
:focus-visible; group with:focus-within) - MUST: Manage focus (trap, move, and return) per APG patterns
- Targets & input
- MUST: Hit target ≥24px (mobile ≥44px) If visual <24px, expand hit area
- MUST: Mobile
<input>font-size ≥16px or set:<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover" /> - NEVER: Disable browser zoom
- MUST:
touch-action: manipulationto prevent double-tap zoom; set-webkit-tap-highlight-colorto match design
- Inputs & forms (behavior)
- MUST: Hydration-safe inputs (no lost focus/value)
- NEVER: Block paste in
<input>/<textarea> - MUST: Loading buttons show spinner and keep original label
- MUST: Enter submits focused text input In
<textarea>, ⌘/Ctrl+Enter submits; Enter adds newline - MUST: Keep submit enabled until request starts; then disable, show spinner, use idempotency key
- MUST: Don't block typing; accept free text and validate after
- MUST: Allow submitting incomplete forms to surface validation
- MUST: Errors inline next to fields; on submit, focus first error
- MUST:
autocomplete+ meaningfulname; correcttypeandinputmode - SHOULD: Disable spellcheck for emails/codes/usernames
- SHOULD: Placeholders end with ellipsis and show example pattern (eg,
+1 (123) 456-7890,sk-012345…) - MUST: Warn on unsaved changes before navigation
- MUST: Compatible with password managers & 2FA; allow pasting one-time codes
- MUST: Trim values to handle text expansion trailing spaces
- MUST: No dead zones on checkboxes/radios; label+control share one generous hit target
- State & navigation
- MUST: URL reflects state (deep-link filters/tabs/pagination/expanded panels) Prefer libs like nuqs
- MUST: Back/Forward restores scroll
- MUST: Links are links—use
<a>/<Link>for navigation (support Cmd/Ctrl/middle-click)
- Feedback
- SHOULD: Optimistic UI; reconcile on response; on failure show error and rollback or offer Undo
- MUST: Confirm destructive actions or provide Undo window
- MUST: Use polite
aria-livefor toasts/inline validation - SHOULD: Ellipsis (
…) for options that open follow-ups (eg, "Rename…") and loading states (eg, "Loading…", "Saving…", "Generating…")
- Touch/drag/scroll
- MUST: Design forgiving interactions (generous targets, clear affordances; avoid finickiness)
- MUST: Delay first tooltip in a group; subsequent peers no delay
- MUST: Intentional
overscroll-behavior: containin modals/drawers - MUST: During drag, disable text selection and set
inerton dragged element/containers - MUST: No "dead-looking" interactive zones—if it looks clickable, it is
- Autofocus
- SHOULD: Autofocus on desktop when there's a single primary input; rarely on mobile (to avoid layout shift)
Animation
- MUST: Honor
prefers-reduced-motion(provide reduced variant) - SHOULD: Prefer CSS > Web Animations API > JS libraries
- MUST: Animate compositor-friendly props (
transform,opacity); avoid layout/repaint props (top/left/width/height) - SHOULD: Animate only to clarify cause/effect or add deliberate delight
- SHOULD: Choose easing to match the change (size/distance/trigger)
- MUST: Animations are interruptible and input-driven (avoid autoplay)
- MUST: Correct
transform-origin(motion starts where it "physically" should)
Layout
- SHOULD: Optical alignment; adjust by ±1px when perception beats geometry
- MUST: Deliberate alignment to grid/baseline/edges/optical centers—no accidental placement
- SHOULD: Balance icon/text lockups (stroke/weight/size/spacing/color)
- MUST: Verify mobile, laptop, ultra-wide (simulate ultra-wide at 50% zoom)
- MUST: Respect safe areas (use env(safe-area-inset-*))
- MUST: Avoid unwanted scrollbars; fix overflows
Content & Accessibility
- SHOULD: Inline help first; tooltips last resort
- MUST: Skeletons mirror final content to avoid layout shift
- MUST:
<title>matches current context - MUST: No dead ends; always offer next step/recovery
- MUST: Design empty/sparse/dense/error states
- SHOULD: Curly quotes (" "); avoid widows/orphans
- MUST: Tabular numbers for comparisons (
font-variant-numeric: tabular-numsor a mono like Geist Mono) - MUST: Redundant status cues (not color-only); icons have text labels
- MUST: Don't ship the schema—visuals may omit labels but accessible names still exist
- MUST: Use the ellipsis character
…(not ``) - MUST:
scroll-margin-topon headings for anchored links; include a "Skip to content" link; hierarchical<h1–h6> - MUST: Resilient to user-generated content (short/avg/very long)
- MUST: Locale-aware dates/times/numbers/currency
- MUST: Accurate names (
aria-label), decorative elementsaria-hidden, verify in the Accessibility Tree - MUST: Icon-only buttons have descriptive
aria-label - MUST: Prefer native semantics (
button,a,label,table) before ARIA - SHOULD: Right-clicking the nav logo surfaces brand assets
- MUST: Use non-breaking spaces to glue terms:
10 MB,⌘ + K,Vercel SDK
Performance
- SHOULD: Test iOS Low Power Mode and macOS Safari
- MUST: Measure reliably (disable extensions that skew runtime)
- MUST: Track and minimize re-renders (React DevTools/React Scan)
- MUST: Profile with CPU/network throttling
- MUST: Batch layout reads/writes; avoid unnecessary reflows/repaints
- MUST: Mutations (
POST/PATCH/DELETE) target <500 ms - SHOULD: Prefer uncontrolled inputs; make controlled loops cheap (keystroke cost)
- MUST: Virtualize large lists (eg,
virtua) - MUST: Preload only above-the-fold images; lazy-load the rest
- MUST: Prevent CLS from images (explicit dimensions or reserved space)
Design
- SHOULD: Layered shadows (ambient + direct)
- SHOULD: Crisp edges via semi-transparent borders + shadows
- SHOULD: Nested radii: child ≤ parent; concentric
- SHOULD: Hue consistency: tint borders/shadows/text toward bg hue
- MUST: Accessible charts (color-blind-friendly palettes)
- MUST: Meet contrast—prefer APCA over WCAG 2
- MUST: Increase contrast on
:hover/:active/:focus - SHOULD: Match browser UI to bg
- SHOULD: Avoid gradient banding (use masks when needed)
Ultracite Code Standards
This project uses Ultracite, a zero-config preset that enforces strict code quality standards through automated formatting and linting.
Quick Reference
- Format code:
pnpm dlx ultracite fix - Check for issues:
pnpm dlx ultracite check - Diagnose setup:
pnpm dlx ultracite doctor
Biome (the underlying engine) provides robust linting and formatting. Most issues are automatically fixable.
Core Principles
Write code that is accessible, performant, type-safe, and maintainable. Focus on clarity and explicit intent over brevity.
Type Safety & Explicitness
- Use explicit types for function parameters and return values when they enhance clarity
- Prefer
unknownoveranywhen the type is genuinely unknown - Use const assertions (
as const) for immutable values and literal types - Leverage TypeScript's type narrowing instead of type assertions
- Use meaningful variable names instead of magic numbers - extract constants with descriptive names
Modern JavaScript/TypeScript
- Use arrow functions for callbacks and short functions
- Prefer
for...ofloops over.forEach()and indexedforloops - Use optional chaining (
?.) and nullish coalescing (??) for safer property access - Prefer template literals over string concatenation
- Use destructuring for object and array assignments
- Use
constby default,letonly when reassignment is needed, nevervar
Async & Promises
- Always
awaitpromises in async functions - don't forget to use the return value - Use
async/awaitsyntax instead of promise chains for better readability - Handle errors appropriately in async code with try-catch blocks
- Don't use async functions as Promise executors
React & JSX
- Use function components over class components
- Call hooks at the top level only, never conditionally
- Specify all dependencies in hook dependency arrays correctly
- Use the
keyprop for elements in iterables (prefer unique IDs over array indices) - Nest children between opening and closing tags instead of passing as props
- Don't define components inside other components
- Use semantic HTML and ARIA attributes for accessibility:
- Provide meaningful alt text for images
- Use proper heading hierarchy
- Add labels for form inputs
- Include keyboard event handlers alongside mouse events
- Use semantic elements (
<button>,<nav>, etc.) instead of divs with roles
Error Handling & Debugging
- Remove
console.log,debugger, andalertstatements from production code - Throw
Errorobjects with descriptive messages, not strings or other values - Use
try-catchblocks meaningfully - don't catch errors just to rethrow them - Prefer early returns over nested conditionals for error cases
Code Organization
- Keep functions focused and under reasonable cognitive complexity limits
- Extract complex conditions into well-named boolean variables
- Use early returns to reduce nesting
- Prefer simple conditionals over nested ternary operators
- Group related code together and separate concerns
Security
- Add
rel="noopener"when usingtarget="_blank"on links - Avoid
dangerouslySetInnerHTMLunless absolutely necessary - Don't use
eval()or assign directly todocument.cookie - Validate and sanitize user input
Performance
- Avoid spread syntax in accumulators within loops
- Use top-level regex literals instead of creating them in loops
- Prefer specific imports over namespace imports
- Avoid barrel files (index files that re-export everything)
- Use proper image components (e.g., Next.js
<Image>) over<img>tags
Framework-Specific Guidance
Next.js:
- Use Next.js
<Image>component for images - Use
next/heador App Router metadata API for head elements - Use Server Components for async data fetching instead of async Client Components
React 19+:
- Use ref as a prop instead of
React.forwardRef
Solid/Svelte/Vue/Qwik:
- Use
classandforattributes (notclassNameorhtmlFor)
Testing
- Write assertions inside
it()ortest()blocks - Avoid done callbacks in async tests - use async/await instead
- Don't use
.onlyor.skipin committed code - Keep test suites reasonably flat - avoid excessive
describenesting
When Biome Can't Help
Biome's linter will catch most issues automatically. Focus your attention on:
- Business logic correctness - Biome can't validate your algorithms
- Meaningful naming - Use descriptive names for functions, variables, and types
- Architecture decisions - Component structure, data flow, and API design
- Edge cases - Handle boundary conditions and error states
- User experience - Accessibility, performance, and usability considerations
- Documentation - Add comments for complex logic, but prefer self-documenting code
Most formatting and common issues are automatically fixed by Biome. Run pnpm dlx ultracite fix before committing to ensure compliance.
