diff --git a/CLAUDE.md b/CLAUDE.md index d210ccc..2ae51dc 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -91,15 +91,24 @@ Docker-compose defaults (no `.env` changes needed for local dev): ``` apps/backend/src/ ├── domain/ # CORE - Pure TypeScript, NO framework imports -│ ├── entities/ # Booking, RateQuote, User, Carrier, Port, Container, CsvBooking, etc. -│ ├── value-objects/ # Money, Email, BookingNumber, BookingStatus, PortCode, ContainerType, Volume, LicenseStatus, SubscriptionPlan, etc. -│ ├── services/ # Pure domain services (rate-search, csv-rate-price-calculator, booking, port-search, etc.) +│ ├── entities/ # Booking, RateQuote, Carrier, Port, Container, Notification, Webhook, AuditLog +│ ├── value-objects/ # Money, Email, BookingNumber, BookingStatus, PortCode, ContainerType, Volume, etc. +│ ├── services/ # Pure domain services (csv-rate-price-calculator) │ ├── ports/ │ │ ├── in/ # Use case interfaces with execute() method │ │ └── out/ # Repository/SPI interfaces (token constants like BOOKING_REPOSITORY = 'BookingRepository') │ └── exceptions/ # Domain-specific exceptions ├── application/ # Controllers, DTOs (class-validator), Guards, Decorators, Mappers -└── infrastructure/ # TypeORM entities/repos/mappers, Redis cache, carrier APIs, MinIO/S3, email (MJML+Nodemailer), Sentry +│ ├── [feature]/ # Feature modules grouped by domain (auth/, bookings/, rates/, etc.) +│ ├── controllers/ # REST controllers (also nested under feature folders) +│ ├── services/ # Application services (audit, notification, webhook, booking-automation, export, etc.) +│ ├── gateways/ # WebSocket gateways (notifications.gateway.ts via Socket.IO) +│ ├── guards/ # JwtAuthGuard, RolesGuard, CustomThrottlerGuard +│ ├── decorators/ # @Public(), @Roles(), @CurrentUser() +│ ├── dto/ # Request/response DTOs with class-validator +│ ├── mappers/ # Domain ↔ DTO mappers +│ └── interceptors/ # PerformanceMonitoringInterceptor +└── infrastructure/ # TypeORM entities/repos/mappers, Redis cache, carrier APIs, MinIO/S3, email (MJML+Nodemailer), Stripe, Sentry ``` **Critical dependency rules**: @@ -108,6 +117,7 @@ apps/backend/src/ - Path aliases: `@domain/*`, `@application/*`, `@infrastructure/*` (defined in `apps/backend/tsconfig.json`) - Domain tests run without NestJS TestingModule - Backend has strict TypeScript: `strict: true`, `strictNullChecks: true` (but `strictPropertyInitialization: false`) +- Env vars validated at startup via Joi schema in `app.module.ts` — required vars include DATABASE_*, REDIS_*, JWT_SECRET, SMTP_* ### NestJS Modules (app.module.ts) @@ -115,31 +125,36 @@ Global guards: JwtAuthGuard (all routes protected by default), CustomThrottlerGu Feature modules: Auth, Rates, Ports, Bookings, CsvBookings, Organizations, Users, Dashboard, Audit, Notifications, Webhooks, GDPR, Admin, Subscriptions. -Infrastructure modules: CacheModule, CarrierModule, SecurityModule, CsvRateModule. +Infrastructure modules: CacheModule, CarrierModule, SecurityModule, CsvRateModule, StripeModule, PdfModule, StorageModule, EmailModule. -Swagger plugin enabled in `nest-cli.json` — DTOs auto-documented. +Swagger plugin enabled in `nest-cli.json` — DTOs auto-documented. Logging via `nestjs-pino` (pino-pretty in dev). ### Frontend (Next.js 14 App Router) ``` apps/frontend/ -├── app/ # App Router pages -│ ├── dashboard/ # Protected routes (bookings, admin, settings) -│ └── carrier/ # Carrier portal (magic link auth) +├── app/ # App Router pages (root-level) +│ ├── dashboard/ # Protected routes (bookings, admin, settings, wiki, search) +│ ├── carrier/ # Carrier portal (magic link auth — accept/reject/documents) +│ ├── booking/ # Booking confirmation/rejection flows +│ └── [auth pages] # login, register, forgot-password, verify-email └── src/ - ├── components/ # React components (shadcn/ui in ui/, layout/, bookings/, admin/) + ├── app/ # Additional app pages (e.g. rates/csv-search) + ├── components/ # React components (ui/, layout/, bookings/, admin/, rate-search/, organization/) ├── hooks/ # useBookings, useNotifications, useCsvRateSearch, useCompanies, useFilterOptions ├── lib/ │ ├── api/ # Fetch-based API client with auto token refresh (client.ts + per-module files) - │ ├── context/ # Auth context + │ ├── context/ # Auth context, cookie context + │ ├── providers/ # QueryProvider (TanStack Query / React Query) │ └── fonts.ts # Manrope (headings) + Montserrat (body) ├── types/ # TypeScript type definitions - └── utils/ # Export utilities (Excel, PDF) + ├── utils/ # Export utilities (Excel, PDF) + └── legacy-pages/ # Archived page components (BookingsManagement, CarrierManagement, CarrierMonitoring) ``` Path aliases: `@/*` → `./src/*`, `@/components/*`, `@/lib/*`, `@/app/*` → `./app/*`, `@/types/*`, `@/hooks/*`, `@/utils/*` -**Note**: Frontend tsconfig has `strict: false`, `noImplicitAny: false`, `strictNullChecks: false` (unlike backend which is strict). +**Note**: Frontend tsconfig has `strict: false`, `noImplicitAny: false`, `strictNullChecks: false` (unlike backend which is strict). Uses TanStack Query (React Query) for server state — wrap new data fetching in hooks, not bare `fetch` calls. ### Brand Design diff --git a/apps/frontend/app/contact/page.tsx b/apps/frontend/app/contact/page.tsx index e741ff0..9523ffe 100644 --- a/apps/frontend/app/contact/page.tsx +++ b/apps/frontend/app/contact/page.tsx @@ -13,6 +13,10 @@ import { Building2, CheckCircle2, Loader2, + Shield, + Zap, + BookOpen, + ArrowRight, } from 'lucide-react'; import { LandingHeader, LandingFooter } from '@/components/layout'; @@ -33,10 +37,14 @@ export default function ContactPage() { const heroRef = useRef(null); const formRef = useRef(null); const contactRef = useRef(null); + const afterSubmitRef = useRef(null); + const quickAccessRef = useRef(null); const isHeroInView = useInView(heroRef, { once: true }); const isFormInView = useInView(formRef, { once: true }); const isContactInView = useInView(contactRef, { once: true }); + const isAfterSubmitInView = useInView(afterSubmitRef, { once: true }); + const isQuickAccessInView = useInView(quickAccessRef, { once: true }); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); @@ -526,6 +534,159 @@ export default function ContactPage() { + {/* Section 1 : Ce qui se passe après l'envoi */} +
+
+ + {/* Decorative blobs */} +
+
+
+
+ +
+
+
+ +
+ + Après votre envoi + +
+

+ Que se passe-t-il après l'envoi de votre message ? +

+ +
+ {/* Notre engagement */} + +
+
+ +
+

Notre engagement

+
+

+ Dès réception de votre demande, un de nos experts logistiques analyse votre + profil et vos besoins. Vous recevrez une réponse personnalisée ou une invitation + pour une démonstration de la plateforme{' '} + + sous 48 heures ouvrées. + +

+
+ + {/* Sécurité */} + +
+
+ +
+

Sécurité

+
+

+ Vos informations sont protégées et traitées conformément à notre{' '} + + politique de confidentialité + + . Aucune donnée n'est partagée avec des tiers sans votre accord. +

+
+
+
+ +
+
+ + {/* Section 2 : Accès Rapide */} +
+
+ +
+ + Accès rapide + +

+ Besoin d'une réponse immédiate ? +

+
+ +
+ {/* Tarification instantanée */} + +
+ +
+

Tarification instantanée

+

+ N'attendez pas notre retour pour vos prix. Utilisez notre moteur{' '} + Click&Ship pour obtenir + une cotation de fret maritime en moins de 60 secondes. +

+ + Accéder au Dashboard + + +
+ + {/* Wiki Maritime */} + +
+ +
+

Aide rapide

+

+ Une question sur les Incoterms ou la documentation export ? Notre{' '} + Wiki Maritime contient déjà + les réponses aux questions les plus fréquentes. +

+ + Consulter le Wiki + + +
+
+
+
+
+ {/* Map Section */}