Skip to main content

System Overview

ICL Cotizaciones is a freight quotation management SaaS application built with Next.js 16 App Router, React 19, and SQLite. The system enables freight forwarders to manage client quotes for maritime and air freight (FCL/LCL), commercial agreements, pricing catalogs, and analytics dashboards.
The application uses a monolithic architecture with server-side rendering, API routes, and an embedded SQLite database with WAL mode for concurrent access.

Tech Stack

Frontend

TechnologyVersionPurpose
React19.2.4UI rendering and client components
Next.js16.1.6Full-stack framework with App Router
Tailwind CSS4.1.18Utility-first styling
Radix UIVariousHeadless accessible components (Dialog, Select, Dropdown, etc.)
Recharts3.7.0Dashboard charts and data visualization
Lucide React0.564.0Icon library
TanStack Table8.21.3Data table management

Backend

TechnologyVersionPurpose
Node.jsServer runtime
Next.js API Routes16.1.6RESTful API endpoints
iron-session8.0.4Encrypted HTTP-only session cookies
bcryptjs3.0.3Password hashing

Database

TechnologyVersionPurpose
SQLiteEmbedded relational database
better-sqlite312.6.2Native SQLite binding for Node.js
Drizzle ORM0.45.1Type-safe ORM and query builder
drizzle-kit0.31.9Schema migration tool
The application uses better-sqlite3 which requires native compilation. Ensure you configure serverExternalPackages: ["better-sqlite3"] in next.config.ts.

Development Tools

  • TypeScript 5.9.3
  • ESLint 9.39.2 with Next.js config
  • tsx 4.21.0 for running TypeScript scripts
  • Turbopack for fast development builds

C4 Model Diagrams

Level 1: System Context

Shows the system as a black box and its relationships with actors and external systems.

Actors

ActorRolesCapabilities
AdministratorDIRECTOR, GERENTE, ADMINISTRACIONFull CRUD on all quotations, master data management, global dashboard, user management
Commercial / OperationsCOMERCIAL, OPERACIONESCRUD on own quotations, read-only access to catalogs (clients, origins, routes, agreements, pricing)

External Systems

SystemPurposeIntegration Type
Google Fonts CDNProvides Work Sans font for UICDN HTTP — loaded in browser from root layout
The system has no external integrations for email, cloud storage, payments, or third-party authentication providers.

Level 2: Container

Shows the containers (processes/stores) that compose the system.

Container Details

Browser App

  • Technology: React 19, Next.js Client Components ("use client")
  • Responsibilities: UI rendering, form state management, filters, modals, API route fetching
  • Notes: Does not access the database directly. All mutations go through API Routes.

Next.js Server

  • Technology: Node.js, Next.js 16 App Router
  • Responsibilities:
    • Serve Server Components (layouts, pages with redirect)
    • Expose RESTful API Routes (/api/**)
    • Read/write encrypted session via iron-session
    • Apply authentication guards (layout redirect) and authorization (isAdmin in API)
  • Configuration: serverExternalPackages: ["better-sqlite3"] in next.config.ts

SQLite Database

  • Technology: better-sqlite3 (native binding), drizzle-orm
  • Location: {cwd}/data/icl.db
  • Pragmas: journal_mode = WAL, foreign_keys = ON
  • Tables: 8 business tables (see Database Schema)

User Session

  • Technology: iron-session v8
  • Transport: HTTP-only cookie (icl-session)
  • Flags: httpOnly: true, sameSite: lax, secure: false (localhost)
  • Payload: { userId, email, full_name, role, isLoggedIn }
Production deployment requires:
  • Moving the session encryption key from hardcoded value to environment variable
  • Setting secure: true for HTTPS connections

Database Tables Summary

TablePurposeKey Relationships
usersUser accounts with roles
clientsClient companies (FFWW, Final, Both types)user_id → users.id
locationsOrigins and routes unified by location_type
quotationsFreight quotations (core entity)client_id → clients.id, origin_id → locations.id, via_id → locations.id, user_id → users.id
commercial_agreementsCommercial terms per clientclient_id → clients.id, user_id → users.id
pricing_netosUnified FCL + LCL net rates by route and period
port_ratesBase rates per port of loading
Calculated fields in quotations: profit = (freight_sale - freight_net) + (origin_costs_sale - origin_costs_net), plus month, year, week derived from date on the server.

Project Structure

src/
├── app/                          # Next.js App Router
│   ├── layout.tsx               # Root layout (HTML, Work Sans font)
│   ├── page.tsx                 # Redirect logic based on session
│   ├── login/                   # Login page
│   ├── (dashboard)/             # Protected route group
│   │   ├── layout.tsx          # Auth guard + Header + Sidebar
│   │   ├── cotizaciones/       # Quotations pages
│   │   ├── dashboard/          # Analytics dashboards
│   │   └── maestros/           # Master data pages
│   └── api/                     # API Routes
│       ├── auth/               # Authentication endpoints
│       ├── cotizaciones/       # Quotations CRUD
│       ├── clientes/           # Clients CRUD
│       ├── usuarios/           # Users CRUD
│       └── ...
├── components/                  # React components
│   ├── ui/                     # Reusable UI components
│   └── ...
├── db/
│   ├── schema.ts               # Drizzle schema definitions
│   ├── db.ts                   # Database connection
│   └── seed.ts                 # Seed data script
└── lib/
    ├── session.ts              # iron-session configuration
    └── utils.ts                # Utility functions (isAdmin, etc.)

Key Design Decisions

SQLite provides:
  • Zero-configuration embedded database
  • Single-file deployment simplicity
  • Excellent performance for single-server deployments
  • ACID compliance with WAL mode
  • Suitable for low-to-medium concurrent users
Trade-off: Not suitable for multi-server horizontal scaling without read replicas.
iron-session offers:
  • Encrypted session data stored in HTTP-only cookies
  • No need for Redis or session store
  • Automatic CSRF protection with sameSite: lax
  • Stateless session management
  • Simpler than OAuth for internal applications
App Router provides:
  • Server Components for reduced JavaScript bundle size
  • Simplified data fetching with async/await
  • Layout-based authentication guards
  • Co-located API routes with frontend code
  • Automatic code splitting and optimization
Drizzle offers:
  • Type-safe schema definitions with TypeScript
  • Lightweight runtime (no runtime schema validation overhead)
  • SQL-like query builder
  • Excellent SQLite support
  • Migration tooling with drizzle-kit

Next Steps

Database Schema

Explore the complete database schema with ERD diagrams

Authentication

Learn about iron-session, roles, and authorization guards

Routing

Understand the Next.js App Router structure and API routes

API Reference

Browse the complete API documentation

Build docs developers (and LLMs) love