pelagia-portal/App/CLAUDE.md
2026-05-18 23:18:58 +05:30

89 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Commands
```bash
# Development
pnpm dev # Next.js + Turbopack at localhost:3000
pnpm lint # ESLint
pnpm type-check # tsc --noEmit
# Tests
pnpm test # Unit tests (Vitest, jsdom)
pnpm test:watch # Unit tests in watch mode
pnpm test:integration # Integration tests (Vitest, node + real DB)
pnpm test:e2e # E2E tests (Playwright, headless)
pnpm test:e2e:ui # E2E tests with interactive UI
pnpm test:all # All test suites
# Run a single test file
pnpm test -- tests/unit/po-line-items-editor.test.tsx
pnpm test:integration -- tests/integration/create-po.test.ts
# Database
pnpm db:migrate # Create + apply migration (dev)
pnpm db:migrate:deploy # Apply migrations (CI/prod)
pnpm db:seed # Populate sample data
pnpm db:studio # Prisma GUI at localhost:5555
pnpm db:reset # Drop + recreate + seed (dev)
```
## Architecture
### Overview
Internal purchase order management system for a maritime company. Full-stack Next.js 15 App Router app with Prisma + PostgreSQL, NextAuth v5 credentials auth, and Tailwind CSS v4.
**Key design decisions:**
- Server Components for all data-fetching pages; Client Components only where interactivity is needed
- Server Actions for all mutations (form submissions, approvals, etc.)
- Prisma `Decimal` fields **cannot** be passed directly to Client Components — convert with `Number()` in the Server Component before passing as props (see `po-detail.tsx``lineItemsForEditor` pattern)
- File storage toggles automatically: Cloudflare R2 in production, `.dev-uploads/` directory in development
- Email toggles automatically: Resend in production, console log in development
### PO Lifecycle (State Machine)
`lib/po-state-machine.ts` enforces all status transitions. The canonical flow:
```
DRAFT → SUBMITTED → MGR_REVIEW → MGR_APPROVED → SENT_FOR_PAYMENT → PAID_DELIVERED → CLOSED
↓↑
EDITS_REQUESTED / REJECTED / VENDOR_ID_PENDING
```
Every status change is validated against the state machine and recorded as a `POAction` row (audit trail).
### Role-Based Permissions
`lib/permissions.ts` defines `hasPermission(role, permission)` and `requirePermission(role, permission)`. Roles: `TECHNICAL`, `MANNING`, `ACCOUNTS`, `MANAGER`, `SUPERUSER`, `AUDITOR`, `ADMIN`.
**Pattern:** Server Actions call `requirePermission()` at the top before any DB write.
### Key Directories
- `app/(portal)/` — All authenticated pages (portal layout with sidebar)
- `app/api/po/[id]/export/` — PDF and XLSX export endpoint
- `lib/validations/po.ts` — Zod schemas for PO forms; exports `TC_FIXED_LINE` and `TC_DEFAULTS`
- `lib/po-state-machine.ts` — All valid status transitions with required roles
- `lib/notifier.ts` — Email dispatch (Resend in prod, console in dev)
- `lib/storage.ts` — File upload/download (R2 in prod, local in dev)
- `components/po/` — PO-specific components (line items editor, status badge, etc.)
- `tests/integration/helpers.ts``makeSession()`, `makePoForm()`, `fd()` for integration test setup
### GST Calculation
`totalAmount = sum(quantity × unitPrice × (1 + gstRate))` for each line item. The `gstRate` is stored as a decimal on `POLineItem` (e.g., `0.18` = 18%). This applies in Server Actions when computing `totalPrice` per line and the PO `totalAmount`.
### Environment Variables
```
NEXTAUTH_SECRET # Required always
NEXTAUTH_URL # Required always (e.g., http://localhost:3000)
DATABASE_URL # PostgreSQL connection string
# Optional in dev (defaults to local storage + console email):
R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET_NAME, R2_PUBLIC_URL
RESEND_API_KEY, EMAIL_FROM, EMAIL_FROM_NAME
```