# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Development Commands - **Development server**: `npm run dev` - Starts Next.js development server on http://localhost:3000 - **Build**: `npm run build` - Creates production build - **Production server**: `npm run start` - Starts production server (requires build first) - **Lint**: `npm run lint` - Runs Next.js ESLint checks **Note**: No test framework is currently configured in this project. ## High-Level Architecture This is a Next.js 15 application built with React 19 that creates an interactive map visualization with a custom WebGL timeline component. ### Core Architecture Components **Map System**: - Uses MapLibre GL JS for interactive mapping - `app/map-context.tsx` provides global map state management via React Context - `components/map-component.tsx` handles map rendering and initialization - Default map center: Singapore (103.851959, 1.290270) at zoom level 11 - Custom map style from MapTiler API **Timeline Visualization**: - `app/timeline.tsx` is a complex WebGL-powered timeline component using custom shaders - Uses vesica piscis (lens-shaped) geometry rendered via WebGL2 - Custom GLSL shaders in `app/glsl/timeline/` for vertex and fragment processing - Supports interactive features: dragging, zooming, panning, custom time markers - Dual-canvas architecture: WebGL canvas for vesica shapes, 2D canvas overlay for UI elements **UI Framework**: - Tailwind CSS with Radix UI components - Theme system with dark/light mode support via `components/theme-provider.tsx` - shadcn/ui component library in `components/ui/` - Sidebar layout using `components/ui/sidebar.tsx` **Admin System**: - Comprehensive admin interface in `app/admin/` with dashboard, analytics, user management, and content editor - Admin pages include dynamic configuration system and navigation components - Uses both Apollo Client and GraphQL Request for data fetching **Data Layer**: - GraphQL API integration using Apollo Client and GraphQL Request - Backend communication via `/api/bff` endpoint (configured in `lib/gr-client.ts`) - Page-based content management with block-based architecture - Authentication support with JWT tokens ### Key Technical Details **WebGL Timeline**: - Renders vesica piscis shapes as timeline markers - Supports high-DPI displays with proper pixel ratio handling - Interactive controls for zoom (mouse wheel), pan (drag), and custom time selection - Real-time shader uniform updates for responsive interactions **State Management**: - Map state centralized in `MapProvider` context - Timeline uses internal React state with refs for performance-critical interactions - Custom hooks in `hooks/` for map location, zoom, timeline, and mobile detection **Styling**: - Tailwind CSS v4 with PostCSS - Custom animations via `tw-animate-css` - Component styling via `class-variance-authority` and `clsx` **Build Configuration**: - Next.js 15 with App Router - Custom webpack config for GLSL file loading via `raw-loader` (see `next.config.ts`) - TypeScript with strict mode enabled - Absolute imports using `@/*` path mapping **GraphQL Integration**: - Uses both Apollo Client (`@apollo/client`) and GraphQL Request (`graphql-request`) for different use cases - Page content fetching via `lib/fetchers.ts` with support for authentication - Block-based content architecture supporting TextBlock, ChartBlock, SettingsBlock, and HeroBlock types - Environment variables: `GRAPHQL_BACKEND_URL` and `NEXTAUTH_URL` ### File Structure Notes - `app/` - Next.js App Router pages and components - `app/admin/` - Complete admin interface with dashboard, analytics, users, and content editor - `app/glsl/timeline/` - Custom GLSL shaders for WebGL timeline rendering - `components/` - Reusable React components - `components/ui/` - shadcn/ui component library - `hooks/` - Custom React hooks for map, timeline, and mobile detection - `lib/` - Utility functions including GraphQL clients and data fetchers - `types/` - TypeScript type definitions - `public/` - Static assets The application combines modern web mapping with custom WebGL visualization to create an interactive timeline-driven map interface, complemented by a full-featured admin system for content management. These examples should be used as guidance when configuring Sentry functionality within a project. # Exception Catching Use `Sentry.captureException(error)` to capture an exception and log the error in Sentry. Use this in try catch blocks or areas where exceptions are expected # Tracing Examples Spans should be created for meaningful actions within an applications like button clicks, API calls, and function calls Use the `Sentry.startSpan` function to create a span Child spans can exist within a parent span ## Custom Span instrumentation in component actions The `name` and `op` properties should be meaninful for the activities in the call. Attach attributes based on relevant information and metrics from the request ```javascript function TestComponent() { const handleTestButtonClick = () => { // Create a transaction/span to measure performance Sentry.startSpan( { op: "ui.click", name: "Test Button Click", }, (span) => { const value = "some config"; const metric = "some metric"; // Metrics can be added to the span span.setAttribute("config", value); span.setAttribute("metric", metric); doSomething(); }, ); }; return ( ); } ``` ## Custom span instrumentation in API calls The `name` and `op` properties should be meaninful for the activities in the call. Attach attributes based on relevant information and metrics from the request ```javascript async function fetchUserData(userId) { return Sentry.startSpan( { op: "http.client", name: `GET /api/users/${userId}`, }, async () => { const response = await fetch(`/api/users/${userId}`); const data = await response.json(); return data; }, ); } ``` # Logs Where logs are used, ensure Sentry is imported using `import * as Sentry from "@sentry/nextjs"` Enable logging in Sentry using `Sentry.init({ _experiments: { enableLogs: true } })` Reference the logger using `const { logger } = Sentry` Sentry offers a consoleLoggingIntegration that can be used to log specific console error types automatically without instrumenting the individual logger calls ## Configuration In NextJS the client side Sentry initialization is in `instrumentation-client.ts`, the server initialization is in `sentry.edge.config.ts` and the edge initialization is in `sentry.server.config.ts` Initialization does not need to be repeated in other files, it only needs to happen the files mentioned above. You should use `import * as Sentry from "@sentry/nextjs"` to reference Sentry functionality ### Baseline ```javascript import * as Sentry from "@sentry/nextjs"; Sentry.init({ dsn: "https://109bcfcc2d1cdd643e0af61409016900@o4505647824109568.ingest.us.sentry.io/4509868655181824", _experiments: { enableLogs: true, }, }); ``` ### Logger Integration ```javascript Sentry.init({ dsn: "https://109bcfcc2d1cdd643e0af61409016900@o4505647824109568.ingest.us.sentry.io/4509868655181824", integrations: [ // send console.log, console.warn, and console.error calls as logs to Sentry Sentry.consoleLoggingIntegration({ levels: ["log", "warn", "error"] }), ], }); ``` ## Logger Examples `logger.fmt` is a template literal function that should be used to bring variables into the structured logs. ```javascript logger.trace("Starting database connection", { database: "users" }); logger.debug(logger.fmt`Cache miss for user: ${userId}`); logger.info("Updated profile", { profileId: 345 }); logger.warn("Rate limit reached for endpoint", { endpoint: "/api/results/", isEnterprise: false, }); logger.error("Failed to process payment", { orderId: "order_123", amount: 99.99, }); logger.fatal("Database connection pool exhausted", { database: "users", activeConnections: 100, }); ```