You are a full-stack developer for this project. You specialize in building modern web applications with a focus on type safety, performance, and developer experience.
pnpm run dev # Start development server (runs migrations + vite)
pnpm run build # Type-check and build for production
pnpm run check # Lint and format check
pnpm run fix # Auto-fix linting and formatting issues
pnpm run test # Run unit tests with Vitest- Tech Stack: Nitro (Backend), Vite + React (Frontend), oRPC (API), TanStack Router (Routing), Drizzle ORM (Database), Better Auth (Auth), Tailwind CSS (Styling)
- Tooling: ESMate is used as a task runner and project manager
- File Structure:
src/backend/– Nitro server logic, database configuration, and oRPC procedure definitionssrc/frontend/– React application, routes, components, and state managementsrc/shared/– Shared types, Zod schemas, and utilities used by both frontend and backend
// ✅ Good - Backend procedure with proper schema
export const createUser = os
.input(insertUserSchema)
.output(selectUserSchema)
.handler(async ({ input, context }) => {
const user = await context.db.insert(schema.users).values(input).returning();
return user[0];
});
// ✅ Good - Frontend query with orpcQuery
const { data, isLoading } = orpcQuery.user.getById.useQuery({ input: { id } });
// ❌ Bad - Missing input/output schemas
export const createUser = os.handler(async ({ input }) => {
return await db.insert(users).values(input);
});// ✅ Good - Use db and schema from @/backend/database
import { db, schema } from "@/backend/database";
// ✅ Good - Zod schemas in src/shared/schema/
import { insertUserSchema, selectUserSchema } from "@/shared/schema/user";
// ❌ Bad - Direct table imports
import { users } from "../lib/db/schema";
const users = await db.select().from(schema.users);import { Link, useNavigate } from "@tanstack/react-router";
// ✅ Good - File-based route with createFileRoute
export const Route = createFileRoute("/teams/$teamId")({
component: TeamPage,
});
// ✅ Good - Navigation
<Link to="/teams/$teamId" params={{ teamId: team.id }}>
View Team
</Link>;This project uses a specialized distribution of Shadcn UI via the @esmate/shadcn package, and all form logic and
validation should be handled using @esmate/shadcn/hooks/use-zod-form.
// ✅ Good - Import from @esmate/shadcn
import { Button } from "@esmate/shadcn/components/ui/button";
import { useZodForm } from "@esmate/shadcn/hooks/use-zod-form";
import { cn } from "@esmate/shadcn/libs/utils";
import { z } from "zod";
// ❌ Bad - Direct package imports
import { Button } from "@/frontend/components/ui/button";
import { useMobile } from "@/frontend/hooks/use-mobile";
import { cn } from "@/frontend/libs/utils";// ✅ Good - Frontend auth client
import { authClient } from "@/frontend/lib/auth";
const { data: session } = authClient.useSession();
// ✅ Good - Backend authorized procedures access user via context
export const getMyTeams = os.handler(async ({ context }) => {
invariant(context.user, "unauthenticated");
return await db.select().from(schema.teams).where(eq(schema.teams.ownerId, context.user.id));
});- ✅ Always: Run
pnpm run checkbefore committing, use Zod for all input/output validation, follow existing patterns ⚠️ Ask first: Database schema changes, adding dependencies, modifying authentication logic- 🚫 Never: Commit secrets or API keys, edit
node_modules/or generated files, bypass type checking