# Pelagia Portal An internal purchase order management system for a maritime vessel-operations company. Digitises the full PO lifecycle — from crew requisition through manager approval, vendor validation, accounts payment, and receipt confirmation — replacing ad-hoc email chains and spreadsheets with a single auditable workflow. ## Tech Stack | Layer | Technology | |---|---| | Framework | Next.js 15 (App Router) | | Language | TypeScript 5 (strict) | | Database | PostgreSQL 16 via Prisma 5 | | Auth | NextAuth.js v5 (credentials) | | Styling | Tailwind CSS v4 + shadcn/ui | | File Storage | Cloudflare R2 (production) / local filesystem (development) | | Email | Resend (production) / console log (development) | --- ## Prerequisites | Tool | Required Version | |---|---| | Node.js | >= 20.11.0 LTS | | pnpm | >= 9.0.0 | | PostgreSQL | >= 16 (local or Docker) | Install pnpm if you don't have it: ```bash npm install -g pnpm ``` --- ## Development Setup In development mode the app requires **only a database and auth secret** — Cloudflare R2 and Resend are not needed. File uploads are saved to `.dev-uploads/` on your local machine, and emails are printed to the terminal instead of being sent. ### 1. Install dependencies ```bash pnpm install ``` ### 2. Configure environment Copy the example file and fill in the two required values: ```bash cp .env.example .env.local ``` Minimum `.env.local` for development: ```env NEXTAUTH_SECRET= NEXTAUTH_URL=http://localhost:3000 DATABASE_URL="postgresql://postgres:postgres@localhost:5432/pelagia_portal" ``` The R2 and Resend variables are not needed in development and can be left as placeholders. ### 3. Set up the database Create the database (if it doesn't exist yet), run migrations, and seed sample data: ```bash pnpm db:migrate # runs prisma migrate dev pnpm db:seed # seeds vessels, accounts, vendors, and demo users ``` To inspect the database with a GUI: ```bash pnpm db:studio # opens Prisma Studio at http://localhost:5555 ``` ### 4. Start the dev server ```bash pnpm dev ``` The app will be available at [http://localhost:3000](http://localhost:3000). **Email behaviour in dev:** all notification emails are logged to the terminal in place of actual delivery. Look for lines starting with `📧 [DEV EMAIL]`. **File upload behaviour in dev:** uploaded files are written to `.dev-uploads/` at the project root. This directory is git-ignored. --- ## Serving in Production Production requires all environment variables to be set, including Cloudflare R2 credentials and a Resend API key. ### 1. Configure environment Set the following variables in your hosting platform (Vercel, etc.) or in `.env.local` for a self-hosted deploy: ```env # Auth NEXTAUTH_SECRET= NEXTAUTH_URL=https://your-domain.com # Database DATABASE_URL=postgresql://:@:/ # Cloudflare R2 R2_ACCOUNT_ID= R2_ACCESS_KEY_ID= R2_SECRET_ACCESS_KEY= R2_BUCKET_NAME=pelagia-portal R2_PUBLIC_URL=https://..r2.cloudflarestorage.com # Email RESEND_API_KEY=re_ EMAIL_FROM=noreply@yourdomain.com EMAIL_FROM_NAME="Pelagia Portal" ``` ### 2. Run database migrations ```bash pnpm db:migrate:deploy # runs prisma migrate deploy (safe for production) ``` ### 3. Build and start ```bash pnpm build pnpm start ``` The app listens on port 3000 by default. Point your reverse proxy (nginx, Caddy, etc.) or hosting platform to that port. --- ## Database Management | Command | Purpose | |---|---| | `pnpm db:migrate` | Create and run a new migration (dev only) | | `pnpm db:migrate:deploy` | Apply pending migrations without prompting (CI/production) | | `pnpm db:push` | Push schema changes without a migration file (prototyping only) | | `pnpm db:seed` | Seed sample data | | `pnpm db:studio` | Open Prisma Studio GUI | | `pnpm db:reset` | Drop and recreate the database, then re-seed (dev only) | --- ## Testing ```bash pnpm test # unit + integration tests (Vitest) pnpm test:watch # watch mode pnpm test:e2e # end-to-end tests (Playwright) pnpm test:e2e:ui # Playwright with interactive UI ``` --- ## Other Scripts ```bash pnpm lint # ESLint pnpm type-check # tsc --noEmit pnpm email:preview # live-preview email templates at http://localhost:3001 ``` --- ## Project Structure ``` pelagia-portal/ ├── app/ # Next.js App Router pages and API routes │ ├── (auth)/ # Login │ ├── (portal)/ # Authenticated shell (sidebar + header) │ │ ├── dashboard/ │ │ ├── po/ # PO creation, detail, edit │ │ ├── approvals/ # Manager approval queue │ │ ├── payments/ # Accounts payment queue │ │ ├── history/ # Audit trail │ │ └── admin/ # User, vessel, account, vendor management │ └── api/ │ ├── auth/ # NextAuth endpoints │ ├── files/sign/ # Generate presigned upload URL (production) │ ├── files/dev/ # Local file upload/download handler (dev only) │ └── reports/export/ # CSV / PDF export ├── components/ # Shared UI components (shadcn/ui + custom) ├── lib/ # Business logic │ ├── po-state-machine.ts # All PO state transitions enforced here │ ├── permissions.ts # Role → allowed-action map │ ├── notifier.ts # Email dispatch (Resend in prod, console in dev) │ ├── storage.ts # File storage (R2 in prod, local in dev) │ └── validations/ # Zod schemas ├── emails/ # React Email templates ├── prisma/ # Schema and migrations └── tests/ # Vitest unit/integration + Playwright E2E ``` --- ## Roles | Role | Description | |---|---| | Technical | Deck/engine crew — create and submit POs, confirm receipt | | Manning | Crew-management staff — same as Technical | | Manager | Review, approve, reject, request edits | | Accounts | Process payment for approved POs | | SuperUser | Combined Technical + Manning + Manager authority | | Auditor | Read-only access to all records and reports | | Admin | Manage users, vessels, accounts, and vendors | User accounts are provisioned by an Admin; there is no self-registration.