This is a modern React + TypeScript application built with:
- Runtime: Bun
- Framework: React 19 + TypeScript
- Bundler: Vite
- Routing: TanStack Router (file-based)
- Data Fetching: TanStack Query + Axios
- Styling: Tailwind CSS v4 + shadcn/ui
- Linting: oxlint + Prettier
- Git Hooks: Husky + lint-staged
bun install # Install dependencies
bun run dev # Start dev server (localhost:3000)
bun run build # Build for production (includes type checking)
bun run preview # Preview production buildbun run lint # Run oxlint linter
bun run lint:fix # Auto-fix lint issues
bun run format # Format code with Prettier
bun run check # Check Prettier formatting- Pre-commit: Runs
lint-staged(prettier + oxlint --fix) - All staged files are automatically formatted and linted
- Strict mode enabled: All type checks enforced
- No unused locals/parameters: Code must be clean
- ES2022 target: Modern JavaScript features available
- JSX transform: React 19+ JSX transform enabled
// ✅ Correct order and style
import React from "react"
import { Link, createFileRoute } from "@tanstack/react-router"
import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils"
import { api } from "@/lib/axios"
// ✅ Use path aliases
import Component from "@/components/Component"
import utils from "@/lib/utils"// ✅ Function component with TypeScript
interface ComponentProps {
title: string
variant?: "default" | "secondary"
children?: React.ReactNode
}
function Component({ title, variant = "default", children }: ComponentProps) {
return (
<div
className={cn(
"base-styles",
variant === "secondary" && "secondary-styles"
)}
>
<h1>{title}</h1>
{children}
</div>
)
}
export { Component }// ✅ Use cn() utility for conditional classes
import { cn } from "@/lib/utils"
function Button({ variant, className, ...props }) {
return (
<button
className={cn(
"base-button-styles",
variant === "primary" && "bg-blue-500",
variant === "secondary" && "bg-gray-500",
className
)}
{...props}
/>
)
}- Routes in
src/routes/automatically generate routes - Root layout:
src/routes/__root.tsx - Use
<Outlet />for nested route content - Use
<Link />from@tanstack/react-routerfor navigation
import { Link } from "@tanstack/react-router"
// ✅ Navigation
<Link to="/about">About</Link>
<Link to="/posts/$postId" params={{ postId: "123" }}>Post 123</Link>// ✅ TanStack Query for API calls
import { useQuery } from "@tanstack/react-query"
function PostsList() {
const { data, error, isLoading } = useQuery({
queryKey: ["posts"],
queryFn: () => api.get("/posts").then((res) => res.data),
})
if (isLoading) return <div>Loading...</div>
if (error) return <div>Error: {error.message}</div>
return <div>{/* render posts */}</div>
}# Install new components
bunx shadcn@latest add <component-name>- Components use
class-variance-authorityfor variants - All components forward refs properly
- Use Radix UI primitives when needed
- Follow existing component patterns in
src/components/ui/
- No semicolons
- Double quotes (not single)
- 2 spaces for indentation
- Trailing commas: ES5 compatible
- Print width: 80 characters
- Minimal configuration - relies on TypeScript strict mode
- Auto-fixes most issues on commit
- Run
bun run lint:fixmanually for batch fixes
{
"@/*": "./src/*",
"@/components/*": "./src/components/*",
"@/lib/*": "./src/lib/*"
}- Create components in appropriate directories
- Add routes in
src/routes/for new pages - Use TanStack Query for data fetching
- Follow existing TypeScript patterns
- Run
bun run lint:fixbefore committing
- Use Tailwind classes directly in components
- For complex logic, use the
cn()utility - Avoid inline styles except for dynamic values
- Follow shadcn/ui patterns for component variants
- Base path:
/app/(configured in vite.config.ts) - Type checking: Built into build command (fails on type errors)
- Generated files:
src/routeTree.gen.ts(auto-generated, don't edit)
- Use
.env.exampleas template - Never commit
.envfile - Environment variables are available via
import.meta.env
- TanStack Router DevTools enabled in development
- TanStack Query DevTools integrated
- React DevTools available via browser extension
// ✅ Use error boundaries and proper error states
function Component() {
const { data, error } = useQuery({...})
if (error) {
return <div>Error: {error.message}</div>
}
return <div>{/* content */}</div>
}// ✅ Show loading states during data fetch
function Component() {
const { data, isLoading } = useQuery({...})
if (isLoading) {
return <div>Loading...</div>
}
return <div>{/* content */}</div>
}- Use React's built-in form handling
- Validate with Zod schemas when needed
- Connect to TanStack Query for mutations
- Components:
PascalCase.tsx(e.g.,UserProfile.tsx) - Utilities:
camelCase.ts(e.g.,formatDate.ts) - Routes:
kebab-case.tsx(e.g.,user-profile.tsx) - Hooks:
useCamelCase.ts(e.g.,useAuth.ts) - Types:
camelCase.types.ts(e.g.,user.types.ts)
- Page-specific components: When building homepage or any page with subcomponents (e.g.,
homepage-table,homepage-card), organize them insrc/components/[page-name]/subfolder - Consistent naming: Use kebab-case for component folders, PascalCase for component files
- Variable casing: Maintain consistent casing across variables and file names
// ✅ Always use zod schemas for mutations and payloads
import { z } from "zod"
const loginSchema = z.object({
email: z.string().email(),
password: z.string().min(6),
})
// ✅ Always use zod.safeParse for validation
const result = loginSchema.safeParse(data)
if (!result.success) {
// Handle validation errors
}- Centralized endpoints: All API endpoints must be defined in
src/lib/api-endpoints.ts - Usage pattern:
axiosInstance.get(apiEndpoints.LOGIN)instead of hardcoded URLs - Consistent naming: Use UPPER_CASE constants for endpoint names
// api-endpoints.ts example
export const apiEndpoints = {
LOGIN: "/auth/login",
REGISTER: "/auth/register",
USERS: "/users",
} as const- All API calls: Must use TanStack Query (useQuery for GET, useMutation for POST/PUT/DELETE)
- Loading states: Always utilize
isLoading,isFetching,isErrorstates - UI feedback: Show appropriate loading indicators, error states, and success messages
// ✅ Proper Query usage
const { data, isLoading, isFetching, isError, error } = useQuery({
queryKey: ['users'],
queryFn: () => api.get(apiEndpoints.USERS)
})
// ✅ Proper Mutation usage
const mutation = useMutation({
mutationFn: (data) => api.post(apiEndpoints.LOGIN, data),
onSuccess: () => // handle success
})- Field-level errors: Display validation errors directly below the corresponding form field
- Consistent positioning: Use fixed positioning or proper spacing to ensure errors are clearly visible
// ✅ Error placement pattern
<div className="space-y-4">
<div>
<Input name="email" />
{errors.email && (
<p className="text-sm text-destructive mt-1">{errors.email}</p>
)}
</div>
</div>This is the most important rule - this app is designed for mobile phones.
- Mobile responsiveness takes priority above all else
- 100% mobile-first approach: Design for mobile first, then scale up
- Touch-friendly: Ensure buttons, links, and interactive elements have adequate touch targets (minimum 44px)
- Responsive testing: Always test on mobile viewports during development
- Performance: Optimize for mobile data speeds and device constraints
- Layouts: Use mobile-appropriate layouts (single column, collapsible navigation, etc.)
- Gestures: Consider touch gestures and mobile interaction patterns
This guide should help any agentic coding agent work effectively with this codebase. When in doubt, follow existing patterns and maintain consistency with the established conventions.