CLAUDE.md · diff

git:20260703.16dd696 to git:20260921.5319a3e

2 added, 358 removed. Audit A to A.

- # CLAUDE.md
-
- This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
-
- ## Project Overview
-
- **PromptMinder** is a professional AI prompt management platform built with Next.js 16 and React 19. It enables users to create, version, organize, and share AI prompts with support for team collaboration.
-
- **Key Features:**
- - Prompt version management with diff comparison
- - Team-based multi-tenancy with role-based permissions
- - Public prompt sharing and community contributions
- - AI-powered prompt optimization
- - Real-time prompt testing with various AI models
- - Bilingual support (Chinese and English)
-
- **Core Stack:**
- - Next.js 16 (App Router)
- - React 19 (functional components with hooks)
- - Clerk for authentication
- - Neon PostgreSQL + Drizzle ORM for database
- - Radix UI for accessible primitives
- - Tailwind CSS for styling
- - Lucide React for icons
- - Framer Motion for animations
- - No TypeScript - uses JavaScript with jsconfig.json for path mapping
-
- ## Commands
-
- Use **pnpm** for all package management:
-
- ### Development
- - `pnpm dev` - Start development server (http://localhost:3000)
- - `pnpm build` - Build for production
- - `pnpm start` - Start production server
- - `pnpm lint` - Run ESLint (must pass after changes)
-
- ### Testing
- - `pnpm test` - Run all tests
- - `pnpm test:watch` - Run tests in watch mode
- - `pnpm test:coverage` - Run tests with coverage report
- - `pnpm test:ci` - Run tests in CI mode
- - `pnpm test __tests__/path/to/test.test.js` - Run specific test file
- - `pnpm test --testNamePattern="test description"` - Run tests matching pattern
-
- ### Analysis & Performance
- - `pnpm analyze` - Build with bundle analyzer
-
- ## Project Structure
-
- ```
- prompt-manager/
- ├── app/ # Next.js App Router pages
- │ ├── api/ # API routes (REST endpoints)
- │ ├── prompts/ # Prompt management pages
- │ ├── tags/ # Tag management pages
- │ ├── teams/ # Team management pages
- │ ├── admin/ # Admin dashboard pages
- │ ├── public/ # Public prompt gallery
- │ ├── share/ # Shared prompt pages
- │ ├── sign-in/ # Authentication pages
- │ ├── sign-up/ # Registration pages
- │ ├── layout.js # Root layout with metadata
- │ ├── page.js # Landing page
- │ ├── providers.jsx # Context providers wrapper
- │ └── globals.css # Global styles with Tailwind
- ├── components/ # React components
- │ ├── ui/ # Reusable UI components (Button, Card, Dialog, etc.)
- │ ├── prompt/ # Prompt-related components
- │ ├── team/ # Team-related components
- │ ├── landing/ # Landing page sections
- │ ├── layout/ # Layout components (Navbar, Footer)
- │ ├── admin/ # Admin dashboard components
- │ ├── playground/ # Prompt testing components
- │ └── common/ # Shared utility components
- ├── hooks/ # Custom React hooks
- │ ├── use-prompts.js # Prompt data fetching
- │ ├── use-prompt-detail.js
- │ └── use-toast.js # Toast notifications
- ├── lib/ # Utility functions and configurations
- │ ├── api-client.js # Centralized API client
- │ ├── api-error.js # Error handling utilities
- │ ├── auth.js # Authentication helpers
- │ ├── constants.js # Application constants
- │ ├── utils.js # Utility functions (cn, etc.)
- │ ├── team-service.js # Team business logic
- │ ├── team-request.js # Team context resolution
- │ ├── team-storage.js # Team localStorage utilities
- │ └── prompts.js # Prompt utilities
- ├── contexts/ # React Context providers
- │ ├── LanguageContext.js # Internationalization
- │ └── team-context.js # Team state management
- ├── messages/ # Internationalization files
- │ ├── zh.json # Chinese translations
- │ └── en.json # English translations
- ├── sql/ # Database migration scripts
- │ ├── teams.sql # Team tables
- │ ├── prompts.sql # Prompt tables
- │ ├── tags.sql # Tag tables
- │ ├── projects.sql # Project tables
- │ ├── contributions.sql # Contribution system
- │ └── backfill_team_data.sql
- ├── __tests__/ # Test files (mirrors source structure)
- ├── __mocks__/ # Jest mocks
- │ └── lucide-react.js # Icon mocks for testing
- ├── public/ # Static assets
- ├── jest.config.js # Jest configuration
- ├── jest.setup.js # Jest setup and mocks
- ├── tailwind.config.js # Tailwind CSS configuration
- ├── next.config.js # Next.js configuration
- └── jsconfig.json # JavaScript path mapping
- ```
-
- ## Code Style Guidelines
-
- ### Imports
- - Use absolute imports with `@/` alias: `@/components/...`, `@/lib/...`, `@/hooks/...`, `@/contexts/...`
- - External libraries first, then internal modules
- - Named imports from libraries: `import { useState } from 'react'`
- - Example: `import { apiClient, ApiError } from '@/lib/api-client'`
-
- ### File Types
- - `.jsx` - React components (use 'use client' directive when needed)
- - `.js` - Utility functions, hooks, API clients, and tests
- - No TypeScript - uses JavaScript with jsconfig.json for path mapping
-
- ### Formatting
- - 2 space indentation
- - Semicolons required
- - Mixed quotes: single quotes in JS, double quotes in JSX attributes
- - Use `cn()` utility from `@/lib/utils` for className merging (combines clsx and tailwind-merge)
-
- ### Naming Conventions
- - Components: PascalCase (PromptCard, Button, TestCaseList)
- - Functions: camelCase (fetchPrompts, handleCopy, validateInput)
- - Constants: UPPER_SNAKE_CASE (PERSONAL_TEAM_ID, DEFAULTS, UI_CONFIG)
- - Hooks: use prefix (usePrompts, useToast, useLanguage)
- - Files: kebab-case (prompt-card.jsx, button.jsx, api-client.js)
- - Test files: *.test.js pattern (Button.test.js, api-client.test.js)
-
- ### React Patterns
- - Use functional components with hooks over class components
- - Add `'use client';` at top of client components
- - Memoize expensive operations with useMemo and useCallback
- - Use React.memo with custom comparison functions for components
- - Destructure props in function signature: `function PromptCard({ prompt, onUpdate }) { ... }`
- - Always export components at bottom: `export { Button, buttonVariants }`
-
- ### Error Handling
- - Use ApiError class from `@/lib/api-client` for API errors
- - Wrap async operations in try-catch
- - Show user feedback with useToast hook: `toast({ title: '...', variant: 'destructive' })`
- - Log errors: `console.error('Error fetching prompts:', error)`
-
- ## Testing
-
- - Jest with React Testing Library
- - Test files in `__tests__/` directory, mirroring source structure
- - Use descriptive Chinese test descriptions: `it('应该正确渲染基本按钮', () => ...)`
- - Setup: `global.fetch = jest.fn()` and `fetch.mockClear()` in beforeEach
- - Prefer modern assertions: `expect(element).toBeInTheDocument()` over toBeTruthy()
- - Group related tests in describe blocks
- - Coverage threshold: 70% for branches, functions, lines, statements
-
- ### Mock Setup
- Key mocks are configured in `jest.setup.js`:
- - Next.js router and navigation
- - Clerk authentication
- - OpenAI API
- - Framer Motion
- - React Hot Toast
- - Lucide React icons (also in `__mocks__/lucide-react.js`)
-
- ## Multi-Tenant Team Architecture
-
- This is a multi-tenant application where all data belongs to a team. Understanding the team system is critical.
-
- ### Team Model
-
- **Personal vs. Team Workspaces:**
- - Every user has an auto-generated "personal team" (`is_personal: true`)
- - Users can create up to 2 additional non-personal teams
- - Personal teams cannot have members (owner only)
- - Non-personal teams support invitations and role-based permissions
-
- **Team Roles:**
- - `owner` - Full control, can transfer ownership
- - `admin` - Can manage members and update team settings
- - `member` - Can access team resources but not manage
-
- **Membership Statuses:**
- - `active` - Full member access
- - `pending` - Invited but not yet accepted
- - `left`, `removed`, `blocked` - Inactive states
-
- ### Team Context Flow
-
- **Client-side:**
- 1. `TeamContext` (contexts/team-context.js) manages active team selection
- 2. Active team ID stored in localStorage via `TEAM_STORAGE_KEY`
- 3. `null` team ID represents personal workspace
- 4. `ApiClient` reads from localStorage and sends `X-Team-Id` header
-
- **Server-side (API routes):**
- 1. Extract team ID from `X-Team-Id` header or `?teamId=` query param via `extractTeamId()`
- 2. Call `resolveTeamContext()` to get db client, teamService, and membership
- 3. Use `teamService.requireMembership()` to authorize access
- 4. Pass `teamId` to database queries
-
- **Example API route pattern:**
- ```javascript
- export async function GET(request) {
- const userId = await requireUserId()
- const { teamId, teamService } = await resolveTeamContext(request, userId, {
- requireMembership: true,
- allowMissingTeam: false
- })
-
- // Query data with team_id filter
- const data = await db
- .select()
- .from(prompts)
- .where(eq(prompts.team_id, teamId))
-
- return NextResponse.json({ prompts: data })
- }
- ```
-
- **For operations that work across personal and team contexts:**
- ```javascript
- const { teamId, teamService } = await resolveTeamContext(request, userId, {
- requireMembership: false,
- allowMissingTeam: true
- })
-
- const data = teamId
- ? await db.select().from(prompts).where(eq(prompts.team_id, teamId))
- : await db.select().from(prompts).where(isNull(prompts.team_id))
- ```
-
- ### Key Team Files
-
- - `lib/team-service.js` - Business logic for team operations (invite, accept, leave, transfer ownership)
- - `lib/team-request.js` - Server-side team context resolution from headers/params
- - `lib/team-storage.js` - Constants and utilities for localStorage team persistence
- - `contexts/team-context.js` - Client-side team state management
- - `components/team/TeamSwitcher.jsx` - UI for switching between teams
-
- ## API & Data Layer
-
- ### API Routes (app/api/**)
-
- **Standard pattern:**
- 1. Get userId via `requireUserId()`
- 2. Resolve team context via `resolveTeamContext()`
- 3. Validate membership if needed
- 4. Perform database queries
- 5. Handle errors with `handleApiError()`
-
- **Team-aware queries:**
- - All data tables should have a `team_id` column (nullable for personal items)
- - Always filter by `team_id` in WHERE clauses
- - For personal workspace items, use `isNull(prompts.team_id)` with Drizzle ORM
-
- ### Client Components
-
- **Use centralized API client:**
- ```javascript
- import { apiClient } from '@/lib/api-client'
-
- // Get prompts for active team
- const data = await apiClient.getPrompts({ tag: 'chatbot' })
-
- // Create prompt in specific team
- const newPrompt = await apiClient.createPrompt(promptData, { teamId: 'xxx' })
- ```
-
- **ApiClient automatically:**
- - Reads team ID from localStorage
- - Adds `X-Team-Id` header to requests
- - Handles JSON serialization
- - Throws ApiError with status and details
-
- ### Custom Hooks
-
- **Data fetching hooks** (`hooks/use-*.js`):
- - `usePrompts(filters)` - Fetch and manage prompts
- - `usePromptDetail(id)` - Fetch single prompt
- - Access team context from TeamProvider via components
-
- **Utility hooks:**
- - `useToast()` - Show notifications
-
- ## Database Schema
-
- **Team-based tables** (prompts, tags, projects):
- - `team_id` (uuid, nullable) - Foreign key to teams table
- - `created_by` (text) - User who created the record
- - `created_at`, `updated_at` (timestamptz)
-
- **Core Tables:**
- - `teams` - Team information with `is_personal` flag
- - `team_members` - Membership with roles and status
- - `prompts` - Prompt content with versioning
- - `tags` - Categorization labels
- - `projects` - Project organization
- - `public_prompts` - Community contribution prompts
- - `prompt_contributions` - Pending contributions
- - `favorites` - User favorites
- - `provider_keys` - User API keys for testing
-
- ## Internationalization
-
- - Language files in `/messages/` directory
- - `zh.json` - Chinese translations
- - `en.json` - English translations
- - `LanguageContext` manages language state
- - `useLanguage()` hook for accessing translations
-
- ## UI & Styling
-
- - Tailwind CSS with custom theme variables in `globals.css`
- - Use component variants with class-variance-authority (CVA) for variant props
- - UI components in `components/ui/` using Radix UI primitives
- - Dark mode support via `dark:` variant classes
- - Gradient overlays and animations for polished UI
- - Accessible colors with HSL variables
-
- ## Performance Optimizations
-
- - Lazy load routes and heavy components with `next/dynamic`
- - Use useMemo/useCallback to prevent re-renders
- - Optimized images with next/image
- - CSS-in-JS via Tailwind for minimal bundle
- - PWA support with service worker
-
- ## Security Considerations
-
- - Authentication handled by Clerk
- - API routes use `requireUserId()` to ensure authenticated access
- - Team-based authorization via `teamService.requireMembership()`
- - Environment variables for sensitive configuration:
- - `CLERK_SECRET_KEY`
- - `DATABASE_URL`
- - `AUTH_SECRET`
- - `ZHIPU_API_KEY`
-
- ## Before Committing
-
- 1. Run `pnpm lint` - fix any ESLint errors
- 2. Run `pnpm test` - ensure all tests pass
- 3. Run single test: `pnpm test __tests__/path/to/test.test.js`
- 4. Check console for errors/warnings
+ # Claude Code compatibility
- Never commit:
- - Secrets (.env files, credentials)
- - .next/, node_modules/, coverage/
- - Build artifacts
- - Minimized CSS files
+ Project instructions are maintained in [`AGENTS.md`](AGENTS.md). Read that file for the applicable rules, project facts, authorization boundaries, and verification commands; do not duplicate them here.