diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 764b35112..000000000 --- a/AGENTS.md +++ /dev/null @@ -1,97 +0,0 @@ -# AGENTS.md - -This file provides guidance for AI coding agents working in this repository. - -## Project overview - -Umami is a privacy-focused web analytics platform built with Next.js 15, React 19, and TypeScript. - -- Primary database: PostgreSQL -- Optional analytics backend: ClickHouse -- Optional cache/session backend: Redis - -## Development rules - -- Assume a dev server is already running on port `3001`. -- Do **not** start another dev server. -- Use `pnpm` (not `npm` or `yarn`). -- Avoid destructive shell commands unless explicitly requested. -- Ask before running `git commit` or `git push`. - -## Common commands - -```bash -# Development -pnpm dev -pnpm build -pnpm start - -# Database -pnpm build-db -pnpm update-db -pnpm check-db -pnpm seed-data - -# Code quality -pnpm lint -pnpm format -pnpm check -pnpm test - -# Build specific parts -pnpm build-tracker -pnpm build-geo -``` - -## Architecture - -- `src/app/`: Next.js App Router routes and API endpoints -- `src/components/`: UI components and hooks -- `src/lib/`: shared utilities and infrastructure helpers -- `src/queries/`: data access layer (Prisma + raw SQL) -- `src/store/`: Zustand stores -- `src/tracker/`: standalone client tracking script -- `prisma/`: schema and migrations - -## Key implementation patterns - -### API request validation - -Use Zod + `parseRequest` in API handlers: - -```ts -const schema = z.object({ /* fields */ }); -const { body, error } = await parseRequest(request, schema); -if (error) return error(); -``` - -### Authentication - -- JWT via `Authorization: Bearer ` -- Share token via `x-umami-share-token` -- Role model: `admin`, `manager`, `user` - -### Client data fetching - -- React Query defaults: `staleTime` 60s, no retry, no refetch on window focus - -### Styling - -- CSS Modules with CSS variables and theme support - -## Environment variables - -Common env vars: - -- `DATABASE_URL` -- `APP_SECRET` -- `CLICKHOUSE_URL` -- `REDIS_URL` -- `BASE_PATH` -- `DEBUG` - -## Runtime requirements - -- Node.js 18.18+ -- PostgreSQL 12.14+ -- `pnpm` diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 89b043559..000000000 --- a/CLAUDE.md +++ /dev/null @@ -1,100 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Project Overview - -Umami is a privacy-focused web analytics platform built with Next.js 15, React 19, and TypeScript. It serves as an alternative to Google Analytics, storing data in PostgreSQL (primary) with optional ClickHouse for time-series analytics. - -## Development - -Assume a dev server is always running on port 3001. Do not start the dev server. - -## Common Commands - -```bash -# Development -npm run dev # Start dev server on port 3001 with Turbopack -npm run build # Full production build (includes db setup, tracker, geo data) -npm run start # Start production server - -# Database -npm run build-db # Generate Prisma client -npm run update-db # Run Prisma migrations -npm run check-db # Verify database connection -npm run seed-data # Seed test data - -# Code Quality -npm run lint # Lint with Biome -npm run format # Format with Biome -npm run check # Format and lint with Biome -npm run test # Run Jest tests - -# Building specific parts -npm run build-tracker # Build client-side tracking script (Rollup) -npm run build-geo # Build geolocation database -``` - -## Architecture - -### Directory Structure -- `src/app/` - Next.js App Router (routes and API endpoints) - - `(main)/` - Authenticated app routes (dashboard, websites, teams, boards, etc.) - - `(collect)/` - Data collection routes - - `api/` - REST API endpoints -- `src/components/` - React components (charts, forms, common UI, hooks) -- `src/lib/` - Core utilities (auth, crypto, date, prisma helpers, redis) -- `src/queries/` - Data access layer (Prisma queries and raw SQL) -- `src/store/` - Zustand state stores (app, dashboard, websites, cache) -- `src/tracker/` - Client-side tracking script (lightweight IIFE) -- `prisma/` - Database schema and migrations - -### Key Patterns - -**API Request Handling** - All API endpoints use Zod validation with `parseRequest`: -```typescript -const schema = z.object({ /* fields */ }); -const { body, error } = await parseRequest(request, schema); -if (error) return error(); -``` - -**Authentication** - JWT tokens via Bearer header, share tokens via `x-umami-share-token` header for public dashboards. Role-based access: admin, manager, user. - -**Data Fetching** - React Query with 60s stale time, no retry, no refetch on window focus. - -**State Management** - Zustand for client state, localStorage for user preferences. - -**Styling** - CSS Modules with CSS variables for theming (light/dark mode). - -### Database - -- **ORM**: Prisma 7.x with PostgreSQL adapter -- **Schema**: `prisma/schema.prisma` - 14 models (User, Team, Website, Session, WebsiteEvent, EventData, etc.) -- **Query helpers**: `src/lib/prisma.ts` has dynamic SQL generation functions (`getDateSQL`, `mapFilter`, `getSearchSQL`) -- **Raw SQL**: Complex analytics queries use `{{param}}` template placeholders for safe binding - -### Tracker Script - -The tracking script in `src/tracker/index.js` is a standalone IIFE (~3-4KB) built with Rollup. It sends events to `/api/send`. Alternative script names can be configured via `TRACKER_SCRIPT_NAME` env var. - -## Environment Variables - -Key variables in `.env`: -``` -DATABASE_URL # PostgreSQL connection string (required) -APP_SECRET # Encryption/signing secret -CLICKHOUSE_URL # Optional ClickHouse for analytics -REDIS_URL # Optional Redis for caching/sessions -BASE_PATH # App base path (e.g., /analytics) -DEBUG # Debug namespaces (e.g., umami:*) -``` - -## Requirements - -- Node.js 18.18+ -- PostgreSQL 12.14+ -- pnpm (package manager) - -## Git Workflow - -Always ask for confirmation before running `git commit` or `git push`. diff --git a/src/app/(main)/boards/[boardId]/BoardControls.tsx b/src/app/(main)/boards/[boardId]/BoardControls.tsx index 4e4185bbb..a9c2be3a5 100644 --- a/src/app/(main)/boards/[boardId]/BoardControls.tsx +++ b/src/app/(main)/boards/[boardId]/BoardControls.tsx @@ -4,7 +4,16 @@ import { useBoard } from '@/components/hooks'; export function BoardControls() { const { board } = useBoard(); - const websiteId = board?.parameters?.websiteId; + const boardWebsiteId = board?.parameters?.websiteId; + const componentWebsiteIds = board?.parameters?.rows + ?.flatMap(row => row.columns) + .map(column => column.component?.websiteId) + .filter(Boolean); + const fallbackWebsiteId = + componentWebsiteIds && new Set(componentWebsiteIds).size === 1 + ? componentWebsiteIds[0] + : undefined; + const websiteId = boardWebsiteId || fallbackWebsiteId; if (!websiteId) { return null;