增加API分页和轻量级查询支持,完善备份恢复功能

主要改动:
- API: 为 /api/pages 添加 lightweight 模式和分页支持
- 备份恢复: 增强 restore API 的错误处理和验证逻辑
- 工具函数: 新增 page-utils 辅助函数
- 会话管理: 优化 session 和 auth 相关逻辑
- 文档: 添加 CLAUDE.md 项目指南,包含编辑器配置注意事项

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-03 16:30:31 +08:00
parent 7ea9bd7599
commit ce439db449
8 changed files with 324 additions and 23 deletions
+176
View File
@@ -0,0 +1,176 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
NoteAI is a local knowledge note-taking application built with Next.js, Prisma (SQLite), and TipTap editor. The app provides a hierarchical page structure with rich text editing, markdown import/export, and password-protected access.
## Development Commands
```bash
# Development server (runs on port 3001)
npm run dev
# Build for production
npm run build
# Initialize environment variables
npm run env:init
# Build with environment initialization
npm run build:init
# Start production server (port 3001)
npm start
# Linting
npm run lint
# Type checking and linting together
npm run check
# Run editor block operations tests
npm test
```
## Architecture
### Database Layer (Prisma + SQLite)
- **Schema**: `prisma/schema.prisma`
- **Client**: Singleton instance in `src/lib/prisma.ts`
- **Models**:
- `Page`: Hierarchical pages with self-referential parent-child relationships. Supports both "file" and "folder" types with ordering, locking, tags, and icons.
- `GlobalSettings`: Stores scrypt-hashed password for app-wide authentication.
### State Management
- **Zustand stores** with persistence:
- `src/lib/store.ts`: Main editor state (pages, activePageId, CRUD operations)
- `src/lib/search-store.ts`: Search functionality state
- `src/lib/settings-store.ts`: Application settings state
- `src/lib/page-history.ts`: Undo/redo history management with snapshots
### Authentication & Session
- **Session management**: `src/lib/session.ts` - Custom HMAC-based session tokens stored in cookies (24h TTL)
- **Auth utilities**: `src/lib/auth.ts` - Scrypt password hashing/verification
- **API auth**: `src/lib/api-auth.ts` - Middleware for protecting API routes
- **Rate limiting**: `src/lib/rate-limit.ts` - Token bucket rate limiter for auth endpoints
### Editor System (TipTap)
- **Extensions**: Custom TipTap extensions in `src/components/editor/extensions/`
- `callout.ts` & `callout-component.tsx`: Custom callout blocks
- `ai-mark.ts`: AI-generated content marking
- `task-item.tsx`: Custom task list items
- **Block operations**: `src/lib/editor-block-ops.ts` - Core logic for moving/reordering contiguous spans of blocks (drag-and-drop support)
- **Tests**: `src/lib/editor-block-ops.test.ts` run via `scripts/run-editor-block-ops-tests.mjs`
**CRITICAL: Editor Initialization Configuration**
When modifying `src/components/editor.tsx`, preserve these critical settings for proper markdown import functionality:
```typescript
// In useEditor() configuration:
{
extensions: [
// ... other extensions
Markdown.configure({
html: true,
transformPastedText: true,
transformCopiedText: true, // MUST be true for markdown conversion
}),
],
content, // MUST pass content prop directly, NOT empty string
onUpdate: ({ editor }) => {
// ... update logic
}
}
// In useEffect for content updates:
useEffect(() => {
if (editor && content !== editor.getHTML()) {
const normalizedContent = cleanupAccidentalStandaloneInlineCode(content);
suppressNextUpdateRef.current = true;
allowOnUpdateRef.current = false;
queueMicrotask(() => {
editor.commands.setContent(normalizedContent); // Simple call, no extra options
});
if (normalizedContent !== content) {
onChange(normalizedContent);
}
}
if (editor && onEditorReady) {
onEditorReady(editor);
}
}, [content, editor, onEditorReady]); // Dependencies: do NOT include onChange
```
**Common mistakes to avoid:**
- Setting `content: ''` instead of `content` breaks markdown import display
- Setting `transformCopiedText: false` disables markdown conversion
- Adding unnecessary options to `setContent()` can cause whitespace issues
- Including `onChange` in useEffect dependencies causes infinite re-renders
### Import/Export
- **Markdown import**: `src/lib/markdown-import.ts` - Converts markdown to HTML with special handling for fenced code blocks
- **Export**: `src/lib/export.ts` - Handles exporting pages to various formats
- **File I/O**: `src/lib/file-io.ts` - File system operations for import/export
- **HTML sanitization**: `src/lib/sanitize-html.ts` - Sanitizes HTML content
### API Routes
All routes in `src/app/api/`:
- `/api/auth/login` & `/api/auth/logout`: Authentication
- `/api/settings/init`: First-time password setup (requires `INIT_SETUP_TOKEN` in production)
- `/api/settings/password`: Change password
- `/api/settings/status`: Check initialization status
- `/api/settings/restore`: Restore from backup
- `/api/pages`: CRUD operations for pages
- `/api/pages/[id]`: Individual page operations
- `/api/pages/reorder`: Batch reorder pages
- `/api/ai/chat`: AI chat integration
### Special Features
- **Wiki links**: `src/lib/wiki-links.ts` - Internal page linking system
- **Page utilities**: `src/lib/page-utils.ts` - Helper functions for page operations
- **Search**: `src/lib/search-query.ts` - Search query parsing and execution
## Environment Variables
Required in `.env`:
```env
DATABASE_URL="file:./dev.db"
SESSION_SECRET="<32+ character random string>"
INIT_DEFAULT_PASSWORD="<initial password>"
INIT_SETUP_TOKEN="<optional token for production init>"
```
## Path Aliases
- `@/*` maps to `src/*` (configured in `tsconfig.json`)
## Testing
Tests use Node's native test runner with `--experimental-strip-types` flag. Test files use `.test.ts` extension and are run via custom scripts in `scripts/` directory.
## Database Migrations
```bash
# Generate Prisma client after schema changes
npx prisma generate
# Create and apply migrations
npx prisma migrate dev
# Apply migrations in production
npx prisma migrate deploy
```
## Build Targets
Prisma is configured for both native and `linux-musl-openssl-3.0.x` targets to support Docker deployments.