8.0 KiB
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.tsxprovides global map state management via React Contextcomponents/map-component.tsxhandles 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.tsxis 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/bffendpoint (configured inlib/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
MapProvidercontext - 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-authorityandclsx
Build Configuration:
- Next.js 15 with App Router
- Custom webpack config for GLSL file loading via
raw-loader(seenext.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.tswith support for authentication - Block-based content architecture supporting TextBlock, ChartBlock, SettingsBlock, and HeroBlock types
- Environment variables:
GRAPHQL_BACKEND_URLandNEXTAUTH_URL
File Structure Notes
app/- Next.js App Router pages and componentsapp/admin/- Complete admin interface with dashboard, analytics, users, and content editorapp/glsl/timeline/- Custom GLSL shaders for WebGL timeline rendering
components/- Reusable React componentscomponents/ui/- shadcn/ui component library
hooks/- Custom React hooks for map, timeline, and mobile detectionlib/- Utility functions including GraphQL clients and data fetcherstypes/- TypeScript type definitionspublic/- 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
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 (
<button type="button" onClick={handleTestButtonClick}>
Test Sentry
</button>
);
}
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
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
import * as Sentry from "@sentry/nextjs";
Sentry.init({
dsn: "https://109bcfcc2d1cdd643e0af61409016900@o4505647824109568.ingest.us.sentry.io/4509868655181824",
_experiments: {
enableLogs: true,
},
});
Logger Integration
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.
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,
});