380 lines
14 KiB
Markdown
380 lines
14 KiB
Markdown
# CLAUDE.md
|
|
|
|
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
|
|
## Project Overview
|
|
|
|
This is a **Chinese Tobacco AI Contract and Case Audit System** (中国烟草AI合同及卷宗审核系统) - a Remix-based full-stack application for intelligent document review and evaluation. The system provides AI-powered contract auditing, risk assessment, and compliance checking.
|
|
|
|
**Tech Stack:**
|
|
- Frontend: Remix (React) + TypeScript + Vite
|
|
- Styling: Tailwind CSS + custom CSS
|
|
- Icons: Remixicon (locally hosted)
|
|
- Document Processing: react-pdf, mammoth, docx-preview
|
|
- Backend API: PostgreSQL + PostgREST
|
|
- Authentication: OAuth2.0 + JWT + cookie-based sessions
|
|
- Deployment: Docker + PM2 (multi-instance setup)
|
|
|
|
## Core Commands
|
|
|
|
### Development
|
|
```bash
|
|
npm run dev # Start dev server (port 5173)
|
|
npm run typecheck # Run TypeScript type checking
|
|
npm run lint # Run ESLint
|
|
```
|
|
|
|
### Building
|
|
```bash
|
|
npm run build # Production build
|
|
npm run build:production:multi # Build for production multi-instance
|
|
npm run build:test:multi # Build for testing multi-instance
|
|
npm run build:dev # Build for development
|
|
```
|
|
|
|
### Production Deployment
|
|
```bash
|
|
npm start # Start production server (single instance)
|
|
npm run start:pm2:production:multi # Build and start PM2 multi-instance (production)
|
|
npm run start:pm2:multi # Build and start PM2 multi-instance (testing)
|
|
```
|
|
|
|
### JWT Secret Generation
|
|
```bash
|
|
npm run generate:jwt-secret # Generate a secure JWT secret for production
|
|
```
|
|
|
|
### Docker Deployment
|
|
```bash
|
|
# Build image
|
|
docker build -t docreview-app .
|
|
|
|
# Run with docker-compose
|
|
docker-compose up -d
|
|
|
|
# The system exposes 6 ports for different regional clients:
|
|
# 51703: Meizhou (main)
|
|
# 51704: Yunfu
|
|
# 51705: Jieyang
|
|
# 51706: Chaozhou
|
|
# 51707: Province
|
|
# 51708: Test instance (limited to /cross-checking routes)
|
|
```
|
|
|
|
## Architecture
|
|
|
|
### Multi-Instance Deployment Strategy
|
|
|
|
The system uses a **port-based multi-client architecture** where:
|
|
- One codebase serves multiple regional clients
|
|
- Each client runs on a different port with isolated configurations
|
|
- Port-specific API configurations are defined in `app/config/api-config.ts`
|
|
- PM2 manages multiple instances via `ecosystem.config.cjs`
|
|
- Each instance has its own environment variables (PORT, CLIENT_ID, API_PORT_CONFIG)
|
|
|
|
### Authentication Flow
|
|
|
|
1. **OAuth2.0 Integration** (IDaaS-based):
|
|
- OAuth client configuration in `app/api/login/oauth-client.ts`
|
|
- Callback handling in `app/routes/callback.tsx`
|
|
- User info sync with local PostgreSQL database
|
|
|
|
2. **JWT Token Management**:
|
|
- Frontend JWT generated after OAuth success (`app/api/jwt-helper.server.ts`)
|
|
- JWT contains user info, role, and permissions
|
|
- Stored in encrypted cookie session
|
|
- Auto-refresh when OAuth token refreshes
|
|
- **CRITICAL**: JWT_SECRET must be set in `.env` (use `npm run generate:jwt-secret`)
|
|
|
|
3. **Session Management**:
|
|
- Cookie-based sessions via `createCookieSessionStorage`
|
|
- Global authentication check in `app/root.tsx` loader
|
|
- Role-based access control (common vs developer roles)
|
|
- Developer-only paths: /settings, /config-lists, /document-types, /prompts
|
|
|
|
### API Configuration System
|
|
|
|
**Port-Based Configuration** (`app/config/api-config.ts`):
|
|
- Automatically detects current port and applies correct API config
|
|
- Each port maps to specific backend services (PostgreSQL, MinIO, etc.)
|
|
- Environment variables can override port configs:
|
|
- `NEXT_PUBLIC_API_BASE_URL` - PostgreSQL API base URL
|
|
- `NEXT_PUBLIC_DOCUMENT_URL` - MinIO document storage URL
|
|
- `NEXT_PUBLIC_UPLOAD_URL` - File upload endpoint
|
|
|
|
**Configuration Priority**: Port-specific config > Environment variables > Default environment config
|
|
|
|
### Route Structure
|
|
|
|
- `app/routes/` - Remix file-based routing
|
|
- `_index.tsx` - Home page (redirects to /documents or /cross-checking based on port)
|
|
- `login.tsx` - Login page with OAuth flow
|
|
- `callback.tsx` - OAuth callback handler
|
|
- `documents.tsx` / `documents._index.tsx` - Document management
|
|
- `cross-checking.tsx` - Cross-examination system
|
|
- `contract-template.tsx` - Contract template search
|
|
- `chat-with-llm._index.tsx` - AI chat interface
|
|
- `api.*.tsx` - API routes for backend proxy
|
|
|
|
### API Layer Organization
|
|
|
|
- `app/api/` - API client modules
|
|
- `axios-client.ts` - Configured axios instance with auth headers
|
|
- `postgrest-client.ts` - PostgREST API client
|
|
- `db-client.server.ts` - Server-side database client
|
|
- `jwt-helper.server.ts` - JWT generation and validation
|
|
- `login/auth.server.ts` - Authentication service (getUserSession, logout)
|
|
- `login/oauth-client.ts` - OAuth2.0 client implementation
|
|
- `login/token-manager.server.ts` - Token refresh and management
|
|
|
|
**Important**: Always use `axios-client.ts` for API calls. It automatically:
|
|
- Adds JWT authentication headers
|
|
- Handles API base URL configuration
|
|
- Includes proper error handling
|
|
|
|
### Component Architecture
|
|
|
|
**Design System** (`app/components/ui/`):
|
|
- All components follow BEM naming convention
|
|
- Primary color: `#00684a` (tobacco corporate green)
|
|
- Components are self-contained with co-located styles
|
|
- Import styles in `app/styles/main.css`
|
|
|
|
**Key Components**:
|
|
- `Layout.tsx` - Main layout with sidebar and header
|
|
- `Sidebar.tsx` - Navigation sidebar (role-based menu filtering)
|
|
- `MessageModal.tsx` - Confirmation/alert modal system
|
|
- `Toast.tsx` - Toast notification provider
|
|
- `LoadingBar.tsx` - Top loading bar for route transitions
|
|
- `FilePreview.tsx` - PDF/Word document preview (react-pdf + Collabora integration)
|
|
|
|
### Document Preview System
|
|
|
|
**Current Implementation** (`app/components/reviews/FilePreview.tsx`):
|
|
- **PDF files**: Rendered using `react-pdf` library
|
|
- **DOCX files**: Needs Collabora Online integration (planned)
|
|
|
|
**Integration Plan - Collabora Online for DOCX Preview**:
|
|
|
|
The FilePreview component should support multiple file types:
|
|
1. `.pdf` → Use react-pdf (current implementation)
|
|
2. `.docx` → Use Collabora Online viewer (to be integrated from collabora-test project)
|
|
|
|
**Key Pages Using FilePreview**:
|
|
- `app/routes/reviews.tsx` - Document review page (uses `document.path`)
|
|
- `app/routes/contract-template.detail.$id.tsx` - Contract template details (uses `template.file_path`)
|
|
|
|
**Data Flow for Collabora Integration**:
|
|
```
|
|
Page Component (reviews.tsx / contract-template.detail.$id.tsx)
|
|
↓ passes fileContent.path
|
|
FilePreview Component (detects file extension)
|
|
↓ if .docx
|
|
CollaboraViewer Component (app/components/collabora/)
|
|
↓ calls API
|
|
app/routes/api.collabora.config.tsx (Remix loader)
|
|
↓ generates JWT + WOPISrc URL
|
|
↓ returns { iframeUrl, accessToken }
|
|
CollaboraViewer renders iframe
|
|
↓ Collabora Online loads document
|
|
↓ calls WOPI endpoints
|
|
app/routes/api.collabora.wopi.files.$fileId.tsx (Remix loader/action)
|
|
↓ CheckFileInfo (GET) / GetFile (GET /contents) / PutFile (POST /contents)
|
|
↓ interacts with MinIO storage
|
|
Returns document data to Collabora
|
|
```
|
|
|
|
**Files to Migrate from collabora-test**:
|
|
- `CollaboraViewer.tsx` - Main viewer component
|
|
- `hooks.ts` - useCollaboraConfig, useCollaboraUICustomization, useDocumentReady, useCollaboraUnoCommands
|
|
- `api.ts` - API client for Collabora config
|
|
- `Uno.ts` - LibreOffice UNO commands wrapper
|
|
- `CollaboraIframeUI.ts` - UI customization utilities
|
|
- `types.ts` - TypeScript type definitions
|
|
|
|
**Backend API Routes to Create**:
|
|
1. `app/routes/api.collabora.config.tsx` - Generate Collabora iframe URL and JWT token
|
|
2. `app/routes/api.collabora.wopi.files.$fileId.tsx` - WOPI protocol implementation (CheckFileInfo, GetFile, PutFile)
|
|
|
|
**Environment Variables Needed**:
|
|
```bash
|
|
# Collabora Online server URL
|
|
COLLABORA_URL=http://10.79.97.17:9980
|
|
|
|
# Application base URL (must be accessible from Collabora server)
|
|
APP_URL=http://10.79.97.17:51703
|
|
|
|
# JWT secret for WOPI token signing (reuse existing JWT_SECRET)
|
|
```
|
|
|
|
**Security Considerations**:
|
|
- JWT token must include `fileId` for WOPI endpoint validation
|
|
- File path sanitization to prevent directory traversal attacks
|
|
- CORS configuration for Collabora server to access WOPI endpoints
|
|
- WOPI CheckFileInfo should return pure JSON (not wrapped in API response format)
|
|
|
|
**File Type Detection in FilePreview**:
|
|
```typescript
|
|
const fileExtension = fileContent.path.split('.').pop()?.toLowerCase();
|
|
|
|
if (fileExtension === 'pdf') {
|
|
// Use react-pdf
|
|
return <PDFViewer />;
|
|
} else if (fileExtension === 'docx') {
|
|
// Use Collabora
|
|
return <CollaboraViewer fileId={fileContent.path} mode="view" />;
|
|
} else {
|
|
// Unsupported format
|
|
return <UnsupportedFileMessage />;
|
|
}
|
|
```
|
|
|
|
**Reference Implementation**:
|
|
- See `collabora-test` workspace for complete working example
|
|
- Adapt Next.js API routes to Remix loader/action pattern
|
|
- Convert Next.js `route.ts` GET/POST to Remix `loader()` and `action()` functions
|
|
|
|
**RemixIcon Usage**:
|
|
- Icons are locally hosted in `public/fonts/`
|
|
- Use class syntax: `<i className="ri-home-line"></i>`
|
|
- Preloaded via link tag for instant display
|
|
- **CRITICAL**: When using CSS isolation (like `all: unset`), add exception rules for RemixIcon classes (see `docs/docreview-development-standards.md` for examples)
|
|
|
|
### Cross-Checking System
|
|
|
|
**Overview**: Democratic proposal and voting system for document evaluation disputes.
|
|
|
|
**Key Concepts**:
|
|
- **Tasks**: Evaluation assignments with multiple reviewers
|
|
- **Proposals**: Suggestions to modify evaluation scores
|
|
- **Voting**: Democratic decision-making with approval threshold
|
|
- **Arbitration**: Automatic status determination based on vote counts
|
|
|
|
**Database Tables**:
|
|
- `cross_examination_tasks` - Task assignments
|
|
- `cross_task_document_mapping` - Document-task relationships
|
|
- `cross_scoring_proposals` - Score modification proposals
|
|
- `cross_opinion_votes` - Vote records
|
|
|
|
**API Routes** (via `app/routes/api.*.tsx` proxies):
|
|
- `POST /admin/cross_review/tasks/assign` - Assign cross-checking task
|
|
- `POST /admin/cross_review/proposals` - Create proposal
|
|
- `POST /admin/cross_review/proposals/{id}/votes` - Vote on proposal
|
|
- `DELETE /admin/cross_review/proposals/{id}` - Withdraw proposal
|
|
|
|
See `docs/交叉评查系统完整文档.md` for complete documentation.
|
|
|
|
## Environment Variables
|
|
|
|
**Required** (create `.env` file):
|
|
```bash
|
|
# JWT Secret - MUST be set for production
|
|
JWT_SECRET=your-super-secret-jwt-key-change-this-in-production
|
|
|
|
# OAuth2.0 Configuration (set in PM2 config or env)
|
|
OAUTH_CLIENT_SECRET=your-oauth-client-secret
|
|
|
|
# API Configuration (optional, overrides port-based config)
|
|
NEXT_PUBLIC_API_BASE_URL=http://10.79.97.17:8000
|
|
NEXT_PUBLIC_DOCUMENT_URL=http://10.76.244.156:9000/docauditai/
|
|
NEXT_PUBLIC_UPLOAD_URL=http://10.79.97.17:8000/admin/documents
|
|
```
|
|
|
|
**PM2 Instance Variables** (set in `ecosystem.config.cjs`):
|
|
- `NODE_ENV` - Environment (production/testing/development)
|
|
- `PORT` - Server port
|
|
- `CLIENT_ID` - Regional client identifier
|
|
- `API_PORT_CONFIG` - Port-based API configuration selector
|
|
|
|
## Development Guidelines
|
|
|
|
### Code Style
|
|
|
|
**TypeScript**:
|
|
- Use explicit types for function parameters and return values
|
|
- Interface naming: PascalCase (e.g., `DocumentUI`, `ApiConfig`)
|
|
- Use string literal unions for status types
|
|
- Avoid `any` - use `unknown` if type is truly unknown
|
|
|
|
**React Components**:
|
|
- Use function declarations, not arrow functions: `export function Component() {}`
|
|
- Group hooks at top: useState first, then useEffect
|
|
- Event handlers: `handleClick`, `handleSubmit` naming
|
|
- Props interface: `ComponentNameProps`
|
|
|
|
**File Naming**:
|
|
- Components: `PascalCase.tsx` (Button.tsx)
|
|
- Routes: `kebab-case.tsx` (user-profile.tsx)
|
|
- Utilities: `camelCase.ts` (utils.ts)
|
|
|
|
**Import Order**:
|
|
1. React and Remix imports
|
|
2. Third-party libraries
|
|
3. Internal components with `~/` alias
|
|
4. Type imports
|
|
5. Styles
|
|
|
|
### Styling
|
|
|
|
**Color Variables** (defined in `app/root.tsx`):
|
|
```css
|
|
--color-primary: #00684a; /* Tobacco green */
|
|
--color-primary-hover: #005a3f;
|
|
--color-primary-light: rgba(0, 104, 74, 0.1);
|
|
--color-success: #52c41a;
|
|
--color-warning: #faad14;
|
|
--color-error: #f5222d;
|
|
```
|
|
|
|
**Spacing**: Use Tailwind defaults (4px base: p-4, mt-6, etc.)
|
|
**Border Radius**: `rounded-md` (6px) for buttons/cards
|
|
**Shadows**: `shadow-sm` default, `shadow-md` on hover
|
|
|
|
### Error Handling
|
|
|
|
- Use `ErrorBoundary` component for route-level errors
|
|
- API errors: Log and return appropriate Response.json with status
|
|
- Display user-friendly messages via MessageModal or Toast
|
|
- Never expose sensitive error details to users
|
|
|
|
### Performance
|
|
|
|
- Use `React.memo` for pure components that re-render frequently
|
|
- Lazy load heavy components (PDF viewers, code editors)
|
|
- Debounce search inputs (300ms standard)
|
|
- Optimize images and use appropriate formats
|
|
|
|
## Security Considerations
|
|
|
|
1. **JWT Secret**: NEVER commit JWT_SECRET to version control
|
|
2. **OAuth Client Secret**: Store in environment variables, not code
|
|
3. **API Keys**: Use server-side only (no NEXT_PUBLIC_ prefix)
|
|
4. **Session Cookies**: httpOnly, secure in production
|
|
5. **Port 51708 Restrictions**: Limited to /cross-checking routes only
|
|
|
|
## Testing
|
|
|
|
- Test OAuth flow with IDaaS server at `http://10.79.112.85`
|
|
- Verify JWT generation and validation
|
|
- Check port-based API configuration switching
|
|
- Test role-based access control (common vs developer)
|
|
- Validate cross-checking voting logic and thresholds
|
|
|
|
## Common Pitfalls
|
|
|
|
1. **RemixIcon not showing**: Check for CSS rules overriding `font-family: 'remixicon'`
|
|
2. **API config not updating**: Port detection may need window.location.port on client
|
|
3. **JWT expired**: Implement token refresh or re-authenticate
|
|
4. **PM2 env vars not working**: Ensure NEXT_PUBLIC_ prefix for client-side vars
|
|
5. **File upload fails**: Check UPLOAD_URL configuration for current port
|
|
|
|
## Additional Documentation
|
|
|
|
Detailed documentation is available in `docs/`:
|
|
- `docreview-development-standards.md` - Comprehensive coding standards
|
|
- `交叉评查系统完整文档.md` - Cross-checking system specification
|
|
- `JWT_IMPLEMENTATION.md` - JWT authentication implementation
|
|
- `OAuth2.0认证协议集成指南.md` - OAuth integration guide
|
|
- `docker-deployment.md` - Docker deployment instructions
|
|
- `deployment-config.md` - Multi-instance deployment configuration
|