This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
RC Tracker is a project management and time tracking application. It manages clients, projects, deliverables, tasks, and development hours tracking.
- Framework: Next.js 16 (App Router, Turbopack default)
- Runtime: Node.js 20.9+ (pinned in
.nvmrc) - Database: PostgreSQL on Neon, accessed via Prisma 5
- Authentication: Auth.js v5 (
next-auth@5) with a Credentials provider and 6-digit OTP, JWT sessions - Email: Resend + React Email (
@react-email/components) - UI: Radix UI primitives + shadcn/ui, Tailwind CSS
- Forms: React Hook Form + Zod
- State: Jotai
- Editor: Tiptap / Novel
- Lint: ESLint 9 flat config (
eslint.config.mjs)
pnpm run dev # Next dev (Turbopack)
pnpm run build # Production build
pnpm run start # Production server on port 8050
pnpm run lint # ESLint
pnpm run seed # Seed the database
pnpm exec prisma migrate dev --name <name> # Create + apply migration on dev
pnpm exec prisma migrate deploy # Apply pending migrations (prod)
pnpm exec prisma generate # Regenerate Prisma clientHierarchical data model:
- Client → many Projects
- Project → many Deliverables
- Deliverable → many Tasks
- Task → many Developments (time entries)
- User has a
role(admin/client/user) and an optionalclientIdlinking to a Client - OtpToken stores 6-digit codes per user with
expiresAtandusedAt
There is no Account / Session / VerificationToken table — sessions are JWT, not DB-backed.
- Public:
/login(2-step OTP form),/unauthorized,/legal/* - Admin Panel (
/admin/*): CRUD for clients, projects, deliverables, tasks, developments, users — gated byrole === "admin"insrc/app/admin/layout.tsx - Client Portal (
/[slug]/*): per-client views (projects, billing, pendings) —slugmatchesClient.slug - API Routes: only
/api/auth/[...nextauth](Auth.js handlers)
- Auth helper:
auth()from@/lib/authreturns the current session in server components / actions.signIn,signOut, andhandlersare also exported from there. - Service Layer (
src/services/*): Prisma access.auth-services.tsowns OTP gen/verify;email-services.tsowns Resend. - Server Actions: Form submissions and mutations live in
*-actions.tsfiles next to the page; they call services andrevalidatePath. - Data Tables: Reusable TanStack Table components with filtering / sorting / pagination.
- Forms: React Hook Form + Zod schemas. Always seed
defaultValueswith empty strings / numbers —defaultValues: {}causes React 19 uncontrolled→controlled warnings.
src/app/(auth)/login/login-form.tsxis a 2-step client form (email → 6 digits) using<InputOTP>from shadcn.- Server actions in
src/app/(auth)/login/actions.ts:checkEmailAction,sendOtpAction,verifyOtpAction. - In development,
sendOtpEmail(insrc/services/email-services.ts) logs the OTP to the console instead of sending mail. In production it goes through Resend. - The verify action calls
signIn("credentials", { email, otp, redirect: false }); the Credentials provider insrc/lib/auth.tsre-validates the OTP and populates the JWT.
Required:
DATABASE_URL— Neon pooled connection string (used at runtime).DIRECT_DATABASE_URL— Neon direct connection string (used by Prisma for migrations / shadow DB; same URL asDATABASE_URLminus the-poolerhost suffix).RESEND_API_KEY— Resend API key.EMAIL_FROM— sender (e.g.RCTracker <rctracker@raphauy.dev>).NEXTAUTH_SECRET(orAUTH_SECRET) — JWT signing secret. Auth.js v5 reads either name.NEXTAUTH_URL(orAUTH_URL) — app base URL. Same alias rule.
Legacy SMTP env vars (EMAIL_SERVER, EMAIL_PORT, EMAIL_USER, EMAIL_PASSWORD) are no longer read and can be removed from Vercel.
@/*maps to./src/*
Neon's pooler can break prisma migrate dev's shadow database step. The fix is directUrl = env("DIRECT_DATABASE_URL") in schema.prisma (already configured).
Workflow when changing the schema:
- Edit
prisma/schema.prisma. pnpm exec prisma migrate dev --name <change>— generates the SQL file underprisma/migrations/and applies it to the dev Neon branch.- Smoke-test in dev.
- After deploying to Vercel,
prisma migrate deployruns on the main Neon branch via the postinstall / deploy step.