Initial commit: Port Nimara CRM (Layers 0-4)
Full CRM rebuild with Next.js 15, TypeScript, Tailwind, Drizzle ORM, PostgreSQL, Redis, BullMQ, MinIO, and Socket.io. Includes 461 source files covering clients, berths, interests/pipeline, documents/EOI, expenses/invoices, email, notifications, dashboard, admin, and client portal. CI/CD via Gitea Actions with Docker builds. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
158
14-TECHNICAL-DECISIONS.md
Normal file
158
14-TECHNICAL-DECISIONS.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# 14 — Technical Decisions (Locked)
|
||||
|
||||
> **Status:** All decisions locked as of 2026-03-12. This document is the single source of truth for every dependency, library, and tooling choice in the Port Nimara CRM V1 rebuild.
|
||||
|
||||
---
|
||||
|
||||
## 1. Framework & Runtime
|
||||
|
||||
| Decision | Choice | Notes |
|
||||
| --------------- | ---------------------------- | ----------------------------------------------------------- |
|
||||
| Framework | **Next.js 15** (App Router) | React 19, standalone output mode, `next start` behind nginx |
|
||||
| Language | **TypeScript** (strict mode) | `strict: true` in tsconfig, no `any` escape hatches |
|
||||
| Runtime | **Node.js 20 LTS** | Docker base image: `node:20-alpine` |
|
||||
| Package manager | **pnpm** | Faster installs, strict dependency resolution |
|
||||
|
||||
## 2. UI Layer
|
||||
|
||||
| Decision | Choice | Notes |
|
||||
| ---------------------- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Styling | **Tailwind CSS 4** + Port Nimara design tokens | Custom theme from brand guidelines. Full token system in `15-DESIGN-TOKENS.md` |
|
||||
| Typography | **Inter** (UI), **Georgia** (formal docs), **JetBrains Mono** (data) | Inter via Google Fonts. Brand fonts (Bill Corporate, Adobe Garamond) reserved for marketing materials — CRM uses approved in-house alternatives per brand guide p.14 |
|
||||
| Component library | **shadcn/ui** | Copy-paste components (not npm package). Built on Radix UI primitives + Tailwind. ~50 components. Run `npx shadcn@latest add <component>` to scaffold into `components/ui/`. Fully customizable — we own the source. |
|
||||
| Icons | **Lucide React** | Tree-shakeable, consistent stroke style, bundled with shadcn/ui |
|
||||
| Data tables | **TanStack Table** via shadcn DataTable | Server-side pagination, sorting, filtering. Column definitions per entity. |
|
||||
| Forms | **React Hook Form + Zod** via shadcn Form | Zod schemas shared between client validation and API endpoint validation |
|
||||
| Toasts / notifications | **Sonner** via shadcn Toast | Stacked toasts, auto-dismiss, action buttons |
|
||||
| Command palette | **shadcn Command** (⌘K) | cmdk under the hood. Global search, quick navigation, actions. |
|
||||
| Rich text editor | **TipTap** | Headless, ProseMirror-based, extension architecture. React integration via `@tiptap/react`. Used in 3 contexts (see Section 8). Pre-built shadcn integration available ("Minimal Tiptap"). |
|
||||
| Charts | **Recharts** | For dashboard widgets and report visualizations |
|
||||
| Date handling | **date-fns** | Lightweight, tree-shakeable. No moment.js. |
|
||||
|
||||
### 2.1 TipTap Configuration (3 contexts)
|
||||
|
||||
1. **Email composer** — Full toolbar: bold, italic, underline, lists, links, images. Merge field insertion via custom extension (or repurposed `@tiptap/extension-mention`). HTML output for email body.
|
||||
2. **Document template editor** — Same as email composer plus: table support (`@tiptap/extension-table`), page break hints, merge field tokens rendered as styled inline chips.
|
||||
3. **Notes fields** — Lightweight config: bold, italic, lists, links only. No toolbar — slash commands or floating menu. Markdown-like shortcuts enabled.
|
||||
|
||||
### 2.2 shadcn/ui Components Expected in Use
|
||||
|
||||
Core set (installed during Layer 0):
|
||||
`Button`, `Input`, `Label`, `Select`, `Textarea`, `Checkbox`, `RadioGroup`, `Switch`, `Dialog`, `Sheet`, `DropdownMenu`, `Command`, `Tabs`, `Table`, `Card`, `Badge`, `Avatar`, `Tooltip`, `Popover`, `Calendar`, `DatePicker`, `Form`, `Toast` (Sonner), `Skeleton`, `Separator`, `ScrollArea`, `AlertDialog`, `Accordion`, `Breadcrumb`, `NavigationMenu`, `Pagination`, `Progress`, `Slider`
|
||||
|
||||
## 3. Data Layer
|
||||
|
||||
| Decision | Choice | Notes |
|
||||
| ---------- | ----------------- | ------------------------------------------------------------------------- |
|
||||
| Database | **PostgreSQL 16** | Docker container, named volume, same Compose stack |
|
||||
| ORM | **Drizzle ORM** | Type-safe, SQL-like syntax, push-based migrations. Schema in `db/schema/` |
|
||||
| Validation | **Zod** | Shared schemas: API validation + form validation + Drizzle type inference |
|
||||
| Caching | **Redis 7** | Session store, BullMQ backing store, rate limiting, Socket.io adapter |
|
||||
|
||||
## 4. Authentication & Authorization
|
||||
|
||||
| Decision | Choice | Notes |
|
||||
| ---------------- | --------------------------------------------------- | ----------------------------------------------------- |
|
||||
| Auth library | **Better Auth** | Session-based auth with RBAC. No Keycloak dependency. |
|
||||
| Session store | **Redis** | `better-auth/plugins/redis` for session persistence |
|
||||
| Password hashing | **Argon2** (via Better Auth defaults) | |
|
||||
| RBAC | 4 roles: `super_admin`, `admin`, `manager`, `agent` | Permissions defined per-role in `lib/permissions.ts` |
|
||||
|
||||
## 5. Real-time & Background Jobs
|
||||
|
||||
| Decision | Choice | Notes |
|
||||
| ------------- | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| WebSocket | **Socket.io** | Real-time notifications, live updates, presence. Redis adapter for scaling. |
|
||||
| Job queue | **BullMQ** | Redis-backed. Recurring jobs (calendar sync, email sync, backups), event-driven jobs (EOI generation, webhook processing). Dashboard at `/admin/queues`. |
|
||||
| Job dashboard | **bull-board** | Embedded in admin panel for queue monitoring |
|
||||
|
||||
## 6. File Storage & Documents
|
||||
|
||||
| Decision | Choice | Notes |
|
||||
| -------------- | -------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
||||
| Object storage | **MinIO** (existing self-hosted instance, older version) | S3-compatible. Credentials in env vars. SSE-S3 encryption at rest. DB-backed file metadata in `files` table. |
|
||||
| E-signatures | **Documenso** (self-hosted) | Webhooks primary (instant). BullMQ fallback poll every 6 hours (rare safety net). |
|
||||
| PDF generation | **@pdfme** | Template-based PDF generation. Branded layouts with port logo/colors. |
|
||||
| Receipt OCR | **OpenAI Vision API** | Via standalone PWA at `/scan`. Offline queueing with IndexedDB. |
|
||||
|
||||
## 7. Email
|
||||
|
||||
| Decision | Choice | Notes |
|
||||
| ---------------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
||||
| SMTP relay | **Poste.io** (self-hosted) | Per-user encrypted SMTP credentials stored in DB |
|
||||
| Sending | **Nodemailer** | Direct SMTP send via user's configured account |
|
||||
| IMAP sync | **imapflow** | Background job syncs threads, metadata in PostgreSQL, raw emails in MinIO |
|
||||
| System email templates | **MJML** | Compiled to HTML at build time. Templates for: password set/reset, EOI notifications, follow-up reminders, invoices |
|
||||
|
||||
## 8. External APIs
|
||||
|
||||
| Decision | Choice | Notes |
|
||||
| ---------------- | --------------------- | ---------------------------------------------------------------------------------- |
|
||||
| Google Calendar | **googleapis** | OAuth2 flow, 3 sync triggers (30min poll, on-login, on-navigation if stale > 5min) |
|
||||
| Currency rates | **Frankfurter API** | Free, no API key, ECB rates. Cached daily. |
|
||||
| AI (receipt OCR) | **OpenAI Vision API** | Only AI dependency. Scoped to receipt scanning. |
|
||||
|
||||
## 9. Testing
|
||||
|
||||
| Decision | Choice | Notes |
|
||||
| ------------------ | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Unit / integration | **Vitest** | Modern Jest replacement. Same `describe/it/expect` API. Natively supports TypeScript/ESM. Built on Vite — significantly faster. Next.js officially recommends it. |
|
||||
| E2E | **Playwright** | Real browser automation. V1 scope: 5–6 critical workflow tests only. |
|
||||
| Component tests | **Skipped for V1** | Vitest covers logic; Playwright covers critical flows. Component-level tests deferred. |
|
||||
|
||||
### 9.1 Vitest Coverage Targets (V1)
|
||||
|
||||
- All business rule functions in `lib/business-rules/`
|
||||
- All Zod validation schemas
|
||||
- API endpoint handlers (happy path + key error cases)
|
||||
- Utility functions (date formatting, currency conversion, permission checks)
|
||||
- Service layer functions (EOI generation, invoice calculation, email sending)
|
||||
|
||||
### 9.2 Playwright E2E Tests (V1)
|
||||
|
||||
5–6 critical workflows:
|
||||
|
||||
1. Login → dashboard loads → navigate to clients
|
||||
2. Create client → link interest → generate EOI → verify PDF
|
||||
3. Create expense → upload receipt → verify in expense list
|
||||
4. Email compose → send → verify in thread
|
||||
5. Admin: create user → assign role → verify permissions
|
||||
6. Berth management: create berth → assign client → verify status transitions
|
||||
|
||||
## 10. DevOps & Infrastructure
|
||||
|
||||
| Decision | Choice | Notes |
|
||||
| ---------------- | ------------------- | ----------------------------------------------------------------------- |
|
||||
| Containerization | **Docker Compose** | Services: `crm-app`, `postgres`, `redis`, `minio`, `documenso`, `nginx` |
|
||||
| Reverse proxy | **nginx** | TLS termination, rate limiting, static asset caching |
|
||||
| CI/CD | **GitHub Actions** | Lint → type-check → Vitest → build → deploy |
|
||||
| Backups | **pg_dump → MinIO** | Nightly at 02:00, encrypted, 30-day retention |
|
||||
|
||||
## 11. Server-side State & API
|
||||
|
||||
| Decision | Choice | Notes |
|
||||
| ------------ | --------------------- | --------------------------------------------------------------------------- |
|
||||
| API style | **REST** | Consistent pattern for CRM frontend, website berth map, future integrations |
|
||||
| Server state | **TanStack Query** | Client-side caching, automatic revalidation, optimistic updates |
|
||||
| Client state | **Zustand** | Minimal UI state (sidebar collapse, active port, theme) |
|
||||
| API docs | **OpenAPI / Swagger** | Auto-generated from Zod schemas. Available at `/api/docs` in dev. |
|
||||
|
||||
---
|
||||
|
||||
## Decision Log
|
||||
|
||||
| Date | Decision | Rationale |
|
||||
| ---------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------- |
|
||||
| 2026-02-xx | Next.js 15 over Nuxt 3 / SvelteKit | Largest AI training corpus, best Claude Code fluency |
|
||||
| 2026-02-xx | REST over tRPC | One API pattern for all consumers, no dual-paradigm |
|
||||
| 2026-02-xx | PostgreSQL + Drizzle over NocoDB | Relational integrity, type-safe ORM, proper migrations |
|
||||
| 2026-02-xx | Better Auth over Keycloak | Simpler, no external service, built-in RBAC |
|
||||
| 2026-02-xx | Keep MinIO | Working infrastructure, S3-compatible, no migration needed |
|
||||
| 2026-03-12 | shadcn/ui confirmed | Copy-paste ownership, Radix primitives, Claude Code fluent |
|
||||
| 2026-03-12 | TipTap for rich text | Headless ProseMirror, extension architecture, shadcn integration exists |
|
||||
| 2026-03-12 | Vitest + Playwright | Vitest for unit/integration (fast, TS-native), Playwright for 5-6 critical E2E |
|
||||
| 2026-03-12 | Skip component tests V1 | Logic covered by Vitest, flows covered by Playwright |
|
||||
| 2026-03-12 | MinIO stays (older version) | Self-hosted instance works, no migration overhead |
|
||||
| 2026-03-12 | Port Nimara design tokens from brand guide | Full token system in `15-DESIGN-TOKENS.md`, replaces generic "Maritime tokens" |
|
||||
| 2026-03-12 | Inter as CRM UI font | Brand guide approves Arial for in-house; Inter is the modern web equivalent, shadcn default |
|
||||
| 2026-03-12 | Georgia for formal generated docs | Brand guide secondary font (Adobe Garamond) is commercial; Georgia is the approved in-house serif |
|
||||
Reference in New Issue
Block a user