- Add SKIP_ENV_VALIDATION to bypass Zod env check during next build - Bundle custom server.ts with esbuild so production uses Socket.io - Create worker entry point (src/worker.ts) with all BullMQ workers - Add esbuild build scripts for server and worker bundles - Fix Dockerfile.worker to include its own build stage - Fix pre-commit hook to work without global pnpm - Add CLAUDE.md with project conventions and quick reference Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3.9 KiB
3.9 KiB
Port Nimara CRM
Multi-tenant CRM for marina/port management. Built with Next.js 15 App Router (standalone output), React 19, TypeScript (strict), Tailwind CSS 3, and Drizzle ORM on PostgreSQL.
Quick reference
pnpm dev # Start dev server
pnpm build # Production build
pnpm lint # ESLint
pnpm format # Prettier
pnpm db:generate # Generate Drizzle migrations
pnpm db:push # Push schema to DB
pnpm db:studio # Drizzle Studio GUI
pnpm db:seed # Seed database (tsx src/lib/db/seed.ts)
Tech stack
- Framework: Next.js 15.1 App Router,
output: 'standalone',experimental.typedRoutes - Auth: better-auth (session cookie:
pn-crm.session_token) - Database: PostgreSQL via
postgresdriver + Drizzle ORM - Queue: BullMQ + Redis (ioredis)
- Storage: MinIO (S3-compatible)
- Realtime: Socket.IO with Redis adapter
- UI: Radix UI primitives, shadcn/ui components (
src/components/ui/), Lucide icons, CVA + tailwind-merge + clsx - Forms: react-hook-form + zod resolvers
- Tables: TanStack Table
- State: Zustand stores (
src/stores/), TanStack React Query - PDF: pdfme
- Email: nodemailer + imapflow + mailparser
- AI: OpenAI SDK (optional)
- Testing: Vitest (unit), Playwright (e2e)
- Logging: pino + pino-pretty
Project structure
src/
app/
(auth)/ # Login/auth pages
(dashboard)/ # Main app - route: /[portSlug]/...
(portal)/ # Client portal
api/ # API routes
components/
ui/ # shadcn/ui base components
layout/ # Shell, sidebar, header
[domain]/ # Domain components (clients, invoices, berths, etc.)
shared/ # Cross-domain shared components
hooks/ # React hooks (use-auth, use-permissions, use-socket, etc.)
lib/
api/ # API client utilities
auth/ # better-auth config
db/
schema/ # Drizzle schema (one file per domain)
migrations/ # Generated Drizzle migrations
env.ts # Zod env validation (SKIP_ENV_VALIDATION=1 bypasses)
services/ # Business logic services
validators/ # Zod schemas for API input validation
utils/ # Shared utilities
middleware.ts # Auth middleware (cookie check, redirects)
providers/ # React context providers
stores/ # Zustand stores
types/ # Shared TypeScript types
Conventions
- TypeScript: Strict mode with
noUncheckedIndexedAccess. Noany(ESLint error). - Formatting: Prettier - single quotes, semicolons, trailing commas, 2-space indent, 100 char line width.
- Lint: ESLint flat config extending
next/core-web-vitals,next/typescript,prettier. Unused vars prefixed with_are allowed. - Imports: Use
@/*path alias (maps tosrc/*). - Components: shadcn/ui pattern - base components in
src/components/ui/, domain components insrc/components/[domain]/. - DB schema: One file per domain in
src/lib/db/schema/, re-exported fromindex.ts. Relations inrelations.ts. - Routes: Multi-tenant via
[portSlug]dynamic segment. Typed routes enabled. - Pre-commit: Husky + lint-staged runs ESLint fix + Prettier on staged
.ts/.tsxfiles.
Environment
Copy .env.example to .env for local dev. See src/lib/env.ts for the full schema. Set SKIP_ENV_VALIDATION=1 to bypass validation (used in Docker build).
Docker
Dockerfile- Production multi-stage build (deps -> build -> runner)Dockerfile.dev- Dev with bind-mounted sourceDockerfile.worker- BullMQ worker processdocker-compose.yml/docker-compose.dev.yml/docker-compose.prod.yml
Architecture docs
Numbered spec files in repo root (01-CONSOLIDATED-SYSTEM-SPEC.md through 15-DESIGN-TOKENS.md) contain detailed architecture decisions, feature specs, DB schema docs, API catalog, and implementation sequence.