@AGENTS.md

# CLAUDE.md — Next.js Web Application Context

## Project Overview
* Shipping cost comparison websites instantly aggregate and evaluate rates across multiple couriers, allows customers to find the most afforadable or fastest option by simply entering the packaging's weight, dimensions, pickup and delivery locations.
* This is an upgrade version of an existing website https://parcel2courier.com
* Build a fully responsive, lightweight, SEO-friendly website, prioritizes lightning-fast loadtimes and performance.
* Opimize for Search and AI Readiness


## Build and Development Commands
```bash
pnpm dev          # start dev server
pnpm build        # production build
pnpm lint         # ESLint via next lint
npx prisma generate   # regenerate Prisma client after schema changes
npx prisma migrate dev --name <name>  # create and apply a migration
```
## Environment Variables

Copy `.env.example` to `.env.local`. Required variables:

| Variable | Purpose |
|---|---|
| `DATABASE_URL` | MariaDB connection string (Prisma) |
| `API_SERVICE_URL` | Base URL of the external REST API |
| `API_SERVICE_USERNAME` | HTTP Basic auth username for the API |
| `API_SERVICE_PASSWORD` | HTTP Basic auth password for the API |
| `ITEMS_PER_PAGE` | Pagination page size |
| `ORDER_PREFIX` | String prefix prepended to order numbers in the UI |
| `AUTH_SECRET` | NextAuth secret |
| `POSTGRES_URL` | Postgres connection (used by NextAuth for user lookup) |


### Two data sources

The app reads from two completely separate backends:

1. **MariaDB via Prisma** â€” only the `users` table (authentication). The generated client lives in `generated/prisma/`. After any schema change run `npx prisma generate`.

2. **External REST API** (`API_SERVICE_URL`) â€” all business data (accounts, orders, shipments, statements, etc.). Every request uses HTTP Basic auth built from `API_SERVICE_USERNAME`/`API_SERVICE_PASSWORD`. Two fetch helpers in `src/app/lib/data.tsx` cover most cases: `fetchRecords(resource)`, `fetchRecordList(resource, query, page)`, and `fetchRecordById(resource, id, param)`. Section-specific fetches (e.g. accounts) live in `src/app/dashboard/<section>/lib/data.tsx`.

### Authentication

NextAuth v5 with a Credentials provider. Session strategy is JWT (1-day expiry). `src/proxy.ts` (Next.js 16 replacement for `middleware.ts`) protects all `/dashboard/**` routes via `authConfig` and enforces IP allowlist; redirects unauthenticated requests to `/login`. `auth()` is called directly in server components and layouts to get the session.

### Route and file conventions

```
src/app/
  layout.tsx                        — root layout; renders TopNav, Footer
  page.tsx                          — homepage with ShippingCalculator widget
  globals.css                       — global styles
  styles/
    modal-content.css               — modal-scoped styles

  (auth)/
    login/
      page.tsx
      components/login-form.tsx
      lib/actions.ts                — login server action

  (public-marketing)/
    (freight-options)/              — service info pages (air, road, pallet, etc.)
      <service-name>/page.tsx
    (help)/                         — help/info pages (FAQ, T&C, packaging, etc.)
      <help-topic>/page.tsx
    (online-services)/
      quote/
        layout.tsx                  — quote wizard layout
        page.tsx                    — quote intro / results page
        step-1/page.tsx … step-5/page.tsx
        payment-result/
          page.tsx                  — post-payment landing page
          payment-result-client.tsx — client component handling eWay result
        components/                 — all quote-specific UI and forms
          quote-row.tsx
          quote-stepper.tsx
          quote-tabs.tsx
          quote-params-saver.tsx
          stepper-header.tsx
          step-3-form.tsx
          step-4-form.tsx
          voucher-form.tsx
          warranty-options.tsx
          warranty-important-info.tsx
          tnt-heavy-declaration.tsx
          sms-cost-saver.tsx
          shipment-summary.tsx
          order-summary-section.tsx
          payment-section.tsx
      cubic-volume-calculator/page.tsx
      our-api/page.tsx
      re-print-shipping-labels/page.tsx
      shipment-tracking/page.tsx
      shopping-cart-integrations/page.tsx
    accounts/
      business/page.tsx
      personal/page.tsx
    order/
      [orderId]/
        page.tsx                    — order confirmation page (post-payment)
        booking-form.tsx            — pickup booking client form

  dashboard/
    layout.tsx                      — calls auth(), renders SideNav
    page.tsx                        — dashboard home
    account/
      page.tsx
      config/tabs.ts                — Tab[] for account sub-pages
    orders/
      page.tsx
      [id]/
        collection-delivery/page.tsx
        insurance/page.tsx
        parcel-info/page.tsx
        payment-info/page.tsx
        pick-up/page.tsx
      config/tabs.ts                — Tab[] for order detail tabs
    components/
      ui/                           — dashboard-specific UI primitives

  api/
    auth/[...nextauth]/route.ts     — NextAuth handler
    courier-quote/route.ts          — parallel per-courier quote fetch (Server Actions are queued; see External API call rule)

  components/                       — shared public-facing components
    navbar/
      topnav.tsx                    — React top navigation
    forms/
      address-fieldset.tsx
      parcel-desc-fieldset.tsx
    form-elements/
      toggle-switch.tsx
    ui/                             — Shadcn primitives (Button, DropdownMenu, Breadcrumbs, Pagination, Skeletons, flash-message)
    shipping/                       — shipping-flow card components
      booking-form.tsx              — collection booking form (shared by public order page and dashboard order page)
      collection-card.tsx
      courier-service-card.tsx
      custom-declarations-card.tsx
      delivery-card.tsx
      export-details-card.tsx
      parcel-description-card.tsx
      parcels-card.tsx
      service-details-card.tsx
      shipping-calculator.tsx
    hero.tsx  footer.tsx  features.tsx  cta.tsx  container.tsx  courier-logos.tsx

  config/
    navigation.ts                   — navigations[] tree consumed by TopNav
    datepicker.ts                   — customTheme for Flowbite Datepicker
    modal.ts                        — customModalTheme for Flowbite Modal

  lib/
    data.ts                         — fetchRecords / fetchRecordList / fetchRecordById
    definitions.ts                  — TypeScript types for API shapes
    shipping-utils.ts               — quote/shipping calculation helpers
    utils.tsx                       — general utilities (decodeHtml, formatDeliveryDate, …)
    catalogue.ts                    — static service/courier catalogue data
    constants.ts                    — shared constants
    order-payload.ts                — builds the order payload sent to the API
    api/
      services.ts                   — server actions for /api/* endpoints (eWay, quotes, orders, bookings, contacts, addresses, members)
      parcel.ts                     — server actions for /parcel/* endpoints (contacts, addresses, members, payments)
```

### External API call rule

All calls to `API_SERVICE_URL` must be server actions placed in the correct file based on the URL prefix:

| Endpoint prefix | File |
|---|---|
| `/api/*` | `src/app/lib/api/services.ts` |
| `/parcel/*` | `src/app/lib/api/parcel.ts` |

Never call the external API from a client component via `fetch('/api/...')`, with one exception: **Server Actions are queued and execute sequentially in this Next.js version** (see `node_modules/next/dist/docs/01-app/02-guides/backend-for-frontend.md`, "Server Actions" caveat), so they cannot be used for genuinely concurrent client-side data fetching. Where a client component needs to fire multiple independent requests in parallel (e.g. `src/app/api/courier-quote/route.ts`, used by `live-quote-results.tsx` to fetch quotes from N couriers at once), add a dedicated Route Handler instead and call it with plain `fetch`. Otherwise `api/auth/[...nextauth]` remains the only Next.js API route.


## Technology Stack & Constraints
* **Framework:** Next.js (App Router format only)
* **Language:** TypeScript configured in `strict: true` mode
* **Styling:** Tailwind CSS using global classes or Tailwind utility variants
* **Components:** Default to React Server Components (RSC) for data fetching
* **State Management:** Prioritize URL states or native React Hooks; avoid external global stores


## Core Architectural Rules
* **Imports:** Group sequentially: 1) React, 2) Third-party libraries, 3) Absolute paths using the `@/*` alias
* **Routing Structure:** All routing maps strictly inside the `/app` folder directory
* **Client Directives:** Append the `"use client"` directive only when adding interactive listeners or state Hooks
* **Naming Conventions:** Use PascalCase format for React components and camelCase format for functions


### Styling conventions

- **Theme**: Tailwind `darkMode: ["class"]` + `next-themes` with `attribute="class"`. The `ThemeToggle` is rendered in `SideNav`.
- **CSS variables**: Shadcn-style HSL variables in `src/style/globals.css`. Always use semantic tokens (`text-foreground`, `bg-background`, `text-muted-foreground`, `border-border`) rather than hardcoded Tailwind color classes on anything that must work in both themes.
- **Form inputs**: standard class is `block w-full rounded-md bg-gray-100 dark:bg-muted disabled:opacity-70 px-3 py-1.5 text-base text-foreground outline-1 -outline-offset-1 outline-gray-300 dark:outline-gray-600 placeholder:text-muted-foreground focus:outline-2 focus:-outline-offset-2 focus:outline-indigo-600 sm:text-sm/6`.
- **Form labels**: always `text-foreground` (never `text-white`).
- **Table cells**: always `text-foreground`.
- **Flowbite Datepicker**: always pass `theme={customTheme}` from `config/datepicker.tsx` to match the input style above.
- **Flowbite React** is configured via `withFlowbiteReact` in `next.config.mjs`.
- **External form submission (native POST to third-party URL)**: use a dedicated `submitting` boolean state, separate from the `submitted` flag used for inline validation. Set `submitting = true` only after validation passes and the form is about to POST. The submit button must be `disabled={submitting}` and swap its label/icon to a `<Loader2 className="animate-spin" />` + "Processing…" while `submitting` is true. Add `disabled:cursor-not-allowed` to the button class. This prevents duplicate submissions and gives visible feedback during the external redirect (e.g. eWay Transparent Redirect).
- **Modal footer buttons**: always wrap in `<div className="flex w-full justify-end gap-3">` so buttons align to the bottom-right. Never place buttons directly inside `<ModalFooter>` without this wrapper.
- **Inline content links** (links embedded within prose/body text): always use `text-indigo-600 hover:text-indigo-800 hover:underline transition-colors`. Never use `text-red-500`, `text-red-600`, or bare anchor tags without a class. In HTML strings (e.g. declaration text in `constants.ts` rendered via `html-react-parser`), use the equivalent `class="text-indigo-600 hover:text-indigo-800 hover:underline transition-colors"`.

### Navigation

`src/app/config/navigation.ts` exports `navigations` â€” the topnav tree consumed by `TopNav`.  Account sub-tabs are driven by the `tabs` array in `src/app/dashboard/account/config/tabs.ts`.

### UI primitives

Shared primitives live in two places:

- `src/app/components/ui/` â€” Shadcn components (Button, DropdownMenu, Popover, Breadcrumbs, Pagination, Skeletons, flash-message).
- `src/app/dashboard/components/ui/` â€” project-specific components (OrderStatus badge, CourierSelection dropdown, OrderStatusSelection dropdown).

# External Dependency Standards

* Analyze this template structure located in `../web_templates/astroship/`. 
* Analyze p2c-dashboard for authentication and pattern `../p2c-dashboard/`.
* Build a Shipping cost comparison websites using this style template. Modify the homepage hero section with a shipping cost calculator form. Update the top navigation based on the public-marketing pages.
* You may grab the public page content from the existing parcel2courier.com website.

## Common Gotchas & Fixes
* Never import server actions or database logic inside standalone client files.
* Always ensure page configurations export metadata objects correctly from layout structures.