diff --git a/Project/fonrey/DATA_MODEL/DATA_MODEL文档要求.md b/Project/fonrey/DATA_MODEL/DATA_MODEL文档要求.md new file mode 100644 index 00000000..45a36522 --- /dev/null +++ b/Project/fonrey/DATA_MODEL/DATA_MODEL文档要求.md @@ -0,0 +1,262 @@ +`DATA_MODEL.md` 的核心目标是:**让 AI 在触碰任何数据相关代码时,都能理解业务语义,而不只是看到一堆字段名。** + +--- + +### 必须包含的内容 + +#### 1. 领域概览(Domain Overview) + +用业务语言(不是技术语言)描述核心概念和它们的关系。这是 AI 理解"为什么"的基础。 + +md + +```md +## Domain Overview + +This is a **multi-tenant** project management tool. + +Core concepts: +- **Workspace**: The top-level container, maps to a paying customer (company) +- **Project**: Lives inside a Workspace, has a lifecycle (draft → active → archived) +- **Task**: The atomic unit of work, always belongs to a Project +- **Member**: A User's role within a specific Workspace (not global) + +Key business rules: +- A User can belong to multiple Workspaces with different roles +- Deleting a Project soft-deletes all its Tasks (never hard delete) +- Only Workspace `owner` or `admin` can invite new Members +``` + +--- + +#### 2. 实体关系图(Entity Relationship) + +用文字或 ASCII 图表达清楚关系,不要依赖读者去脑补。 + +md + +```md +## Entity Relationships + +Workspace (1) ──── (N) Project +Workspace (1) ──── (N) Member +Member (N) ──── (1) User ← same User, different roles per Workspace +Project (1) ──── (N) Task +Task (N) ──── (1) Member ← assignee +Task (1) ──── (N) Comment +Task (N) ──── (N) Tag ← via task_tags join table +``` + +--- + +#### 3. 完整 Schema 定义(Schema Definition) + +每个表都需要:字段 + 类型 + 约束 + **业务注释**。注释是给 AI 的关键上下文。 + +md + +```md +## Schema + +### workspaces +| Column | Type | Constraints | Notes | +|--------------|-------------|-------------------|--------------------------------| +| id | uuid | PK, default gen | | +| slug | text | UNIQUE, NOT NULL | URL identifier, immutable after creation | +| name | text | NOT NULL | | +| plan | text | NOT NULL | enum: 'free' | 'pro' | 'enterprise' | +| created_at | timestamptz | NOT NULL, default now() | | +| deleted_at | timestamptz | nullable | soft delete, filter WHERE deleted_at IS NULL | + +### members +| Column | Type | Constraints | Notes | +|--------------|-------------|-------------------|--------------------------------| +| id | uuid | PK | | +| workspace_id | uuid | FK → workspaces.id, CASCADE DELETE | | +| user_id | uuid | FK → users.id | | +| role | text | NOT NULL | enum: 'owner' \| 'admin' \| 'member' \| 'viewer' | +| invited_by | uuid | FK → members.id, nullable | null = founding owner | +| joined_at | timestamptz | nullable | null = invitation pending | + +-- UNIQUE(workspace_id, user_id) — one membership per workspace per user +``` + +--- + +#### 4. 枚举与常量(Enums & Constants) + +把所有枚举值集中在一处,AI 就不会自己发明状态值。 + +md + +```md +## Enums & Constants + +### Task Status (ordered, represents workflow progression) +pending → in_progress → in_review → done → cancelled + +Rules: +- Only forward transitions are allowed (no reopening cancelled tasks) +- `done` and `cancelled` are terminal states +- Changing status logs an entry in task_activity + +### Member Role Permissions +| Action | owner | admin | member | viewer | +|---------------------|-------|-------|--------|--------| +| Invite members | ✅ | ✅ | ❌ | ❌ | +| Delete project | ✅ | ❌ | ❌ | ❌ | +| Create tasks | ✅ | ✅ | ✅ | ❌ | +| Comment on tasks | ✅ | ✅ | ✅ | ✅ | +``` + +--- + +#### 5. 索引策略(Indexes) + +告诉 AI 哪些查询是热路径,避免它写出全表扫描的代码。 + +md + +```md +## Indexes + +-- tasks is the most queried table, optimize for these patterns: +CREATE INDEX idx_tasks_project_status ON tasks(project_id, status) WHERE deleted_at IS NULL; +CREATE INDEX idx_tasks_assignee ON tasks(assignee_id) WHERE deleted_at IS NULL; +CREATE INDEX idx_members_user ON members(user_id); -- "get all workspaces for a user" + +-- Avoid: never query tasks without a project_id filter +-- Avoid: never do SELECT * on tasks, always select specific columns +``` + +--- + +#### 6. 软删除约定(Soft Delete Convention) + +如果使用软删除,必须明确说明规则,否则 AI 会写出漏掉过滤条件的查询。 + +md + +```md +## Soft Delete Convention + +Tables with soft delete: workspaces, projects, tasks + +Rules: +- ALL queries MUST include `WHERE deleted_at IS NULL` unless explicitly retrieving deleted records +- Use `deletedAt: new Date()` to soft delete, never use DELETE SQL +- Cascading: deleting a Project sets deleted_at on all its Tasks in the same transaction +- Deleted records are purged by a cron job after 30 days (hard delete) + +⚠️ AI Note: Never generate a query on these tables without the soft delete filter. +``` + +--- + +#### 7. 多租户隔离规则(Multi-tenancy Rules) + +这是安全的核心,必须让 AI 理解每次查询都要带租户过滤。 + +md + +```md +## Multi-tenancy & Data Isolation + +This is a **workspace-scoped** multi-tenant system. + +Rules: +- EVERY query involving projects, tasks, members MUST be scoped by workspace_id +- Never query tasks directly by id alone — always join through project → workspace +- The workspace_id must come from the authenticated session, never from user input +- Row Level Security (RLS) is enabled on Supabase for all tenant tables + +Correct pattern: + SELECT * FROM tasks + JOIN projects ON tasks.project_id = projects.id + WHERE projects.workspace_id = :workspaceId ← always present + AND tasks.id = :taskId + +Wrong pattern (security hole): + SELECT * FROM tasks WHERE id = :taskId ← missing tenant scope +``` + +--- + +#### 8. 核心查询模式(Common Query Patterns) + +把最常用的查询写出来,AI 会直接复用,而不是重新发明。 + +md + +````md +## Common Query Patterns + +### Get tasks for a project (with assignee info) +```sql +SELECT t.*, m.user_id, u.name as assignee_name +FROM tasks t +LEFT JOIN members m ON t.assignee_id = m.id +LEFT JOIN users u ON m.user_id = u.id +WHERE t.project_id = :projectId + AND t.deleted_at IS NULL +ORDER BY t.created_at DESC; +``` + +### Check if user has permission in workspace +```sql +SELECT role FROM members +WHERE workspace_id = :workspaceId + AND user_id = :userId + AND joined_at IS NOT NULL; -- pending invitations don't count +``` +```` + +--- + +#### 9. 明确禁止的操作(Forbidden Operations) + +md + +```md +## Forbidden Operations + +- ❌ Never hard DELETE on workspaces, projects, or tasks — use soft delete +- ❌ Never UPDATE a task's status by skipping intermediate states +- ❌ Never expose internal UUIDs in URLs — use slugs for workspaces/projects +- ❌ Never store user PII (email, name) in tasks or comments — always join from users table +- ❌ Never write a migration that drops a column without a deprecation period +``` + +--- + +#### 10. 数据迁移约定(Migration Convention) + +md + +```md +## Migration Convention + +- Migration tool: Drizzle Kit +- File naming: `0001_create_workspaces.ts`, sequential, never rename +- Every migration must be reversible (include `down` function) +- Never edit a migration that has been merged to main +- Backfill scripts go in /scripts, not in migrations +``` + +--- + +### 内容优先级总结 + +|优先级|内容|为什么关键| +|---|---|---| +|🔴 必须|领域概览 + 业务规则|AI 需要理解"为什么"才能做正确取舍| +|🔴 必须|完整 Schema + 字段注释|防止字段命名歧义和类型错误| +|🔴 必须|软删除 + 多租户规则|安全漏洞和数据污染的高发区| +|🟡 重要|枚举常量 + 状态机|防止 AI 自己发明状态值| +|🟡 重要|常用查询模式|复用 > 重新发明| +|🟢 加分|索引策略|引导 AI 写出性能友好的查询| +|🟢 加分|迁移约定|保持 schema 演进的可控性| + +--- + +**核心原则**:`DATA_MODEL.md` 写的不是给数据库看的 DDL,而是给 AI 看的**业务契约**。每一个"显而易见"的业务规则,在 AI 眼里都是需要被明确告知的约束。没写的,它都会自己猜。 \ No newline at end of file diff --git a/Project/fonrey/TECH_STACK/TECH_STACK 文档要求.md b/Project/fonrey/TECH_STACK/TECH_STACK 文档要求.md new file mode 100644 index 00000000..c010f983 --- /dev/null +++ b/Project/fonrey/TECH_STACK/TECH_STACK 文档要求.md @@ -0,0 +1,161 @@ +#### 1. 项目概览(Project Overview) + +用 2-3 句话说清楚这是什么项目、核心用途、目标用户。AI 需要这个"北极星"来判断所有技术取舍。 + +md + +```md +## Project Overview +A B2B SaaS invoice management tool. Target users are SMB accountants. +Prioritize reliability and data integrity over flashy UI. +``` + +--- + +#### 2. 核心技术栈(Core Stack) + +每一层都要写清楚,**不要只写框架名,要写版本号和选型原因**。 + +md + +```md +## Core Stack +- Runtime: Node.js 22 (not Bun, not Deno) +- Framework: Next.js 15 (App Router only, never Pages Router) +- Language: TypeScript 5.x, strict mode enabled +- Database: PostgreSQL 16 via Supabase +- ORM: Drizzle ORM (not Prisma) +- Styling: Tailwind CSS v4 + shadcn/ui +- Auth: Clerk +- Deployment: Vercel +``` + +--- + +#### 3. 关键约定(Key Conventions) + +这是 vibe coding 最容易出错的地方,AI 会有自己的"默认习惯",必须显式覆盖。 + +md + +```md +## Key Conventions +- File naming: kebab-case for files, PascalCase for components +- All server actions in /actions, never inline in components +- Use `server components` by default; add 'use client' only when needed +- Environment variables: never hardcode, always use process.env.NEXT_PUBLIC_* +- Error handling: always use Result pattern, never throw in server actions +- No `any` types. No `// @ts-ignore`. +``` + +--- + +#### 4. 目录结构(Directory Structure) + +AI 需要知道把新文件放在哪里,否则它会自己"发明"结构。 + +md + +```md +## Directory Structure +src/ +├── app/ # Next.js routes only, minimal logic +├── components/ # Reusable UI components +│ └── ui/ # shadcn primitives, DO NOT edit +├── actions/ # Server actions +├── lib/ # Utilities and helpers +├── db/ # Drizzle schema and migrations +└── types/ # Global TypeScript types +``` + +--- + +#### 5. 明确禁止的东西(Explicitly Forbidden) + +这是最被忽视但最重要的部分。告诉 AI **不要用什么**,比告诉它用什么更有效。 + +md + +```md +## Do NOT Use +- ❌ `axios` — use native `fetch` +- ❌ `moment.js` — use `date-fns` +- ❌ `useEffect` for data fetching — use server components or React Query +- ❌ `pages/` directory — App Router only +- ❌ `class components` — functional only +- ❌ CSS Modules or styled-components — Tailwind only +- ❌ `console.log` in production code +``` + +--- + +#### 6. 第三方服务与集成(External Services) + +列出已经接入的服务,避免 AI 重复造轮子或引入冲突的 SDK。 + +md + +```md +## External Services +- Payments: Stripe (already configured in /lib/stripe.ts) +- Email: Resend + React Email templates +- File storage: Supabase Storage (not S3) +- Analytics: PostHog +- Error tracking: Sentry +``` + +--- + +#### 7. 代码风格与 Linting(Code Style) + +md + +```md +## Code Style +- Formatter: Prettier (config in .prettierrc) +- Linter: ESLint with eslint-config-next +- Imports: absolute paths via `@/` alias, no relative `../../` +- Prefer `const` over `let`, avoid `var` +- Async/await over `.then()` chains +``` + +--- + +#### 8. 测试策略(Testing, 如果有的话) + +md + +```md +## Testing +- Unit tests: Vitest +- E2E tests: Playwright (critical flows only) +- No snapshot tests +- Test files co-located: `component.test.ts` next to `component.ts` +``` + +--- + +### 一个实用的小技巧 + +在文件开头加一句 AI 专用说明: + +md + +```md +> **For AI assistants**: Read this entire file before writing any code. +> All decisions here are final. Do not suggest alternatives unless asked. +``` + +--- + +### 内容优先级总结 + +|优先级|内容|原因| +|---|---|---| +|🔴 必须|核心技术栈 + 禁止列表|防止 AI 用错库| +|🔴 必须|目录结构 + 文件约定|防止结构混乱| +|🟡 重要|外部服务清单|防止重复实现| +|🟡 重要|关键约定|保持风格一致| +|🟢 加分|测试策略 + 代码风格|提升整体质量| + +**核心原则**:写给 AI 看的文档要比写给人看的**更具体、更强硬、更少歧义**。任何"视情况而定"的描述,AI 都会做出你不想要的选择。 \ No newline at end of file diff --git a/Project/fonrey/UI&UX/UI_SYSTEM文档要求.md b/Project/fonrey/UI&UX/UI_SYSTEM文档要求.md new file mode 100644 index 00000000..3a0252e4 --- /dev/null +++ b/Project/fonrey/UI&UX/UI_SYSTEM文档要求.md @@ -0,0 +1,432 @@ +`UI_SYSTEM.md` 的核心目标是:**让 AI 生成的每一个组件,都像是同一个设计师写的,而不是从五个不同的 UI 库里随机拼凑的。** + +--- + +## 必须包含的内容 + +### 1. 设计哲学(Design Philosophy) + +在写任何具体规则之前,先定义"感觉"。AI 在模糊情况下会回到这里做判断。 + +```md +## Design Philosophy + +**Core aesthetic**: Clean, functional, low-friction. +We build tools, not experiences. Every UI element must earn its place. + +**Principles** (in priority order): +1. **Clarity over cleverness** — if you have to explain the UI, it failed +2. **Density over whitespace** — our users are power users, don't waste screen space +3. **Consistency over novelty** — use existing patterns before inventing new ones +4. **Motion is functional** — animate only to communicate state change, never for decoration + +**Anti-patterns we actively avoid**: +- Skeleton loaders for data that loads in < 300ms (just show a spinner) +- Modal dialogs for destructive actions that are easily reversible +- Infinite scroll (we use pagination, users need to share URLs to specific pages) +- Tooltips on mobile +``` + +--- + +### 2. 设计 Token(Design Tokens) + +这是整个系统的基础。所有颜色、间距、字体都必须来自这里,AI 不能自己发明数值。 + +````md +## Design Tokens + +### Color System +We use CSS variables. NEVER use raw hex values in components. + +**Semantic colors** (use these, not primitives): +```css +--color-bg-base /* page background */ +--color-bg-subtle /* card, sidebar backgrounds */ +--color-bg-muted /* disabled states, placeholders */ + +--color-text-primary /* body text */ +--color-text-secondary /* labels, captions */ +--color-text-disabled /* disabled text */ +--color-text-inverse /* text on dark backgrounds */ + +--color-border /* default borders */ +--color-border-strong /* focused, emphasized borders */ + +--color-accent /* primary actions, links */ +--color-accent-hover /* hover state of accent */ + +--color-success /* confirmations, completed states */ +--color-warning /* non-blocking alerts */ +--color-danger /* destructive actions, errors */ +--color-info /* informational, neutral alerts */ +```` + +**Rule**: If you find yourself writing `text-gray-500`, stop. Map it to a semantic token. + +### Spacing Scale + +We use an 4px base grid. Only use these values: `4px / 8px / 12px / 16px / 24px / 32px / 48px / 64px / 96px` + +In Tailwind: `p-1 / p-2 / p-3 / p-4 / p-6 / p-8 / p-12 / p-16 / p-24` + +Never: `p-5`, `p-7`, `p-9`, `p-10`, `p-11` — these break the grid. + +### Border Radius + +``` +--radius-sm: 4px → rounded-sm (inputs, badges) +--radius-md: 8px → rounded (cards, buttons) ← default +--radius-lg: 12px → rounded-xl (modals, panels) +--radius-full: 9999px → rounded-full (avatars, pills) +``` + +Never mix radius sizes within the same component. + +### Elevation / Shadow + +``` +--shadow-sm → subtle card lift +--shadow-md → dropdowns, popovers +--shadow-lg → modals, dialogs +``` + +Never use `drop-shadow` filter — use `box-shadow` only. + +```` + +--- + +### 3. 字体系统(Typography System) + +```md +## Typography + +**Font stack**: +- UI: `Inter` (loaded via next/font, variable weight) +- Code: `JetBrains Mono` (code blocks, inline code only) +- Never import fonts from Google Fonts directly + +**Type scale** (use only these, no arbitrary sizes): + +| Token | Size | Weight | Line-height | Usage | +|----------------|-------|--------|-------------|--------------------------| +| `text-xs` | 12px | 400 | 1.5 | Labels, badges, metadata | +| `text-sm` | 14px | 400 | 1.5 | Body, secondary content | +| `text-base` | 16px | 400 | 1.6 | Primary body text | +| `text-lg` | 18px | 500 | 1.4 | Section headings | +| `text-xl` | 20px | 600 | 1.3 | Page sub-headings | +| `text-2xl` | 24px | 700 | 1.2 | Page titles | +| `text-3xl` | 30px | 700 | 1.1 | Hero headings only | + +**Rules**: +- Max 2 font sizes per component +- `font-weight: 500` is the minimum for anything interactive (buttons, links) +- Never use `text-3xl` outside of marketing pages +- Line length: max 72 characters for body text (`max-w-prose`) +```` + +--- + +### 4. 核心组件规范(Core Component Specs) + +为每个高频组件定义变体、状态和使用规则。这是 AI 最需要的部分。 + +````md +## Core Component Specs + +### Button + +**Variants**: +| Variant | Use case | Never use for | +|-------------|---------------------------------------|----------------------------| +| `primary` | Single main CTA per view | Destructive actions | +| `secondary` | Secondary actions | Main CTA | +| `ghost` | Toolbar actions, low-priority | Standalone CTAs | +| `danger` | Irreversible destructive actions only | Anything reversible | +| `link` | Navigation only | Form submissions | + +**Sizes**: `sm` (28px h) / `md` (36px h, default) / `lg` (44px h) + +**States** (all must be handled): +- `default` / `hover` / `active` / `focus-visible` / `disabled` / `loading` + +**Loading state rule**: +Show spinner + disable button immediately on click. +Never let the button be clicked twice. +```tsx +// Correct + + +// Wrong — no loading state + +```` + +**Icon buttons**: Always include `aria-label`. Never use icon-only buttons for primary actions. + +--- + +### Form Inputs + +**Anatomy** (always in this order, no exceptions): + +``` +[Label] ← always visible, never placeholder-only +[Input field] +[Helper text] ← optional, describes expected format +[Error message] ← replaces helper text on error +``` + +**States**: `default` / `focus` / `error` / `disabled` / `readonly` + +**Rules**: + +- Label always above input, never to the side (except checkbox/radio) +- Placeholder text is NOT a label — both must exist +- Error messages: specific and actionable ("Enter a valid email" not "Invalid input") +- Required fields: mark with asterisk (*) next to label, explain at top of form +- Never disable a submit button to prevent submission — show errors inline instead + +--- + +### Data Table + +```md +### Table + +**Default behavior**: +- Sticky header on scroll +- Row hover highlight +- Checkbox column for bulk actions (leftmost) +- Actions column (rightmost, visible on row hover only) +- Empty state: illustration + message + CTA (never just "No data") + +**Pagination**: +- Default page size: 25 rows +- Options: 10 / 25 / 50 / 100 +- Always show total count ("Showing 1–25 of 143 results") +- Preserve page position on filter change + +**Column rules**: +- Numbers: right-aligned, monospace font +- Dates: relative time for < 7 days ("2 hours ago"), absolute for older +- Status: always a colored badge, never plain text +- Long text: truncate with tooltip showing full value +``` + +--- + +### Modal / Dialog + +```md +### Modal + +**Size variants**: +| Size | Max-width | Use case | +|-------|-----------|---------------------------| +| `sm` | 400px | Confirmation dialogs | +| `md` | 560px | Forms with < 5 fields | +| `lg` | 720px | Complex forms, previews | +| `xl` | 960px | Multi-step flows | + +**Rules**: +- Always trap focus inside modal +- ESC key always closes (unless unsaved changes → show confirmation) +- Click outside closes (unless form with unsaved changes) +- Never nest modals — use a multi-step flow instead +- Destructive confirm dialogs: danger button on RIGHT, cancel on LEFT +- Never auto-close a modal after async action — wait for user to dismiss +``` + +--- + +### 5. 状态与反馈模式(State & Feedback Patterns) + +````md +## State & Feedback Patterns + +### Loading States +| Duration | Pattern | +|---------------|--------------------------------| +| < 300ms | Nothing (avoid flash of spinner)| +| 300ms – 1s | Inline spinner | +| 1s – 3s | Spinner + "Loading..." | +| > 3s | Progress bar + estimated time | +| Background | Subtle pulsing indicator in nav| + +### Empty States +Every list/table must handle empty state: +```tsx +// Required elements: +// 1. Relevant icon (not a generic "no data" icon) +// 2. Friendly headline ("No tasks yet") +// 3. Explanation of why ("Projects with tasks will appear here") +// 4. CTA if user can fix it ("Create your first task →") +```` + +### Toast Notifications + +|Type|When to use|Duration| +|---|---|---| +|`success`|Async action completed|3s| +|`error`|Action failed, user must retry|persistent| +|`warning`|Completed with caveats|5s| +|`info`|Background process started|3s| + +**Rules**: + +- Max 3 toasts visible at once (queue the rest) +- Never show success toast for page navigations +- Error toasts must include a retry action when possible +- Never use toast for validation errors — show inline instead + +### Skeleton vs Spinner + +- Skeleton: only for content with known layout (profile cards, feed items) +- Spinner: for unknown-shape content, buttons, inline actions +- Never both at the same time in the same view + +```` + +--- + +### 6. 响应式断点(Responsive Breakpoints) + +```md +## Responsive Breakpoints + +**Strategy**: Desktop-first (our users are 85% desktop) + +| Breakpoint | Token | Value | Target | +|------------|--------|--------|--------------------------| +| Desktop | (base) | > 1280px | Primary design target | +| Laptop | `lg` | 1024px | Minor adjustments | +| Tablet | `md` | 768px | Collapsed sidebar | +| Mobile | `sm` | 640px | Single column, no tables | + +**Component-specific rules**: +- Data tables → horizontal scroll on `md` and below +- Sidebar → collapses to bottom nav on `sm` +- Modals → full-screen on `sm` +- Multi-column forms → single column on `md` and below + +**Never**: +- Hide critical functionality on mobile (adapt it, don't remove it) +- Use fixed px widths for layout containers +- Assume touch input on desktop or mouse on mobile +```` + +--- + +### 7. 动效规范(Motion & Animation) + +```md +## Motion & Animation + +**Principle**: Motion communicates state, it doesn't decorate. + +**Duration scale**: +``` + +--duration-fast: 100ms → micro-interactions (checkbox, toggle) --duration-normal: 200ms → most transitions (hover, focus) --duration-slow: 350ms → larger elements (modal, drawer enter) --duration-crawl: 500ms → only for page-level transitions + +``` + +**Easing**: +``` + +--ease-default: cubic-bezier(0.2, 0, 0, 1) → most UI transitions --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1) → playful elements only --ease-linear: linear → progress bars only + +``` + +**What to animate**: +- ✅ Opacity (enter/exit) +- ✅ Transform: translateY (panel slide-in) +- ✅ Max-height (accordion expand) + +**Never animate**: +- ❌ `width` or `height` directly (use `max-height` or `transform`) +- ❌ `top/left/right/bottom` (use `transform: translate`) +- ❌ `box-shadow` on hover (use opacity trick instead) +- ❌ Anything if `prefers-reduced-motion: reduce` +``` + +--- + +### 8. 可访问性基线(Accessibility Baseline) + +```md +## Accessibility (Non-negotiable) + +**Every component must**: +- Meet WCAG 2.1 AA contrast ratios (4.5:1 body, 3:1 large text) +- Be fully keyboard navigable +- Have visible focus indicators (never `outline: none` without replacement) +- Work with screen readers (proper ARIA roles and labels) + +**Required patterns**: +- Icon-only buttons: always `aria-label` +- Form inputs: always `htmlFor` ↔ `id` pairing +- Images: `alt` text always (empty string `""` for decorative images) +- Modals: `role="dialog"`, `aria-modal="true"`, focus trap +- Loading states: `aria-busy="true"` on the loading container +- Error messages: `aria-describedby` linking input to error text + +**Color alone is never enough**: +- Status badges: color + icon + text +- Form errors: color + icon + message below field +- Graphs: color + pattern or label +``` + +--- + +### 9. 禁止模式(Anti-patterns) + +```md +## UI Anti-patterns — Never Do These + +**Layout**: +- ❌ Centering body text wider than 72 characters +- ❌ Full-width buttons on desktop (max-width: 320px) +- ❌ Mixing card and table layouts in the same list view + +**Interaction**: +- ❌ Double-click to perform actions (single click only) +- ❌ Drag-and-drop as the *only* way to reorder +- ❌ Hover-only affordances (invisible until you hover) +- ❌ Auto-submitting forms on change without explicit confirmation + +**Feedback**: +- ❌ Generic error messages ("Something went wrong") +- ❌ Success messages that don't tell the user what happened +- ❌ Blocking UI with a spinner for optimistic actions +- ❌ Alert dialogs (window.alert) — use our Dialog component + +**Content**: +- ❌ Lorem ipsum in any committed code +- ❌ Hardcoded user names or emails in components +- ❌ Placeholder images (use our Avatar initials fallback) +``` + +--- + +## 优先级总结 + +|优先级|内容|为什么关键| +|---|---|---| +|🔴 必须|设计 Token(颜色、间距、圆角)|AI 最容易乱用原始数值| +|🔴 必须|核心组件规范(Button、Input、Table)|高频生成,最容易出现不一致| +|🔴 必须|状态与反馈模式|最能体现产品质感的细节| +|🟡 重要|字体系统|防止 AI 混用字号和字重| +|🟡 重要|可访问性基线|事后补救成本极高| +|🟡 重要|禁止模式|比"应该做什么"更有效| +|🟢 加分|动效规范|统一产品"手感"| +|🟢 加分|响应式断点|避免断点不一致的多设备问题| + +--- + +**核心原则**:`UI_SYSTEM.md` 不是设计文档,是给 AI 的**决策树**。当 AI 面对"这里用什么颜色?""这个按钮多大?""错误怎么展示?"时,答案必须在这里找到,不能靠猜。 \ No newline at end of file diff --git a/Project/fonrey/UI&UX/组件清单.md b/Project/fonrey/UI&UX/组件清单.md new file mode 100644 index 00000000..3d42dfd0 --- /dev/null +++ b/Project/fonrey/UI&UX/组件清单.md @@ -0,0 +1,1265 @@ +## 技术选型 + +- Frontend: HTMX + Alpine.js + Tailwind CSS +- Backend: Django 4.x (ASGI mode) +- Multi-tenant: django-tenants (Postgres schema isolation) +- Database: PostgreSQL + PgBouncer +- Cache: Redis +- Tasks: Celery + Celery Beat +- Storage: Cloudflare R2 (or AWS S3) +- CDN: Cloudflare +- Server: Gunicorn + Uvicorn workers + Nginx +- Monitoring: Sentry + Grafana + +## Data Table (数据表格) + +![[Data Table.png]] + +#### 1. Data Table(数据表格)— 核心组件 + +**你描述的"数据列表"正式名称是:Sortable Data Table with Column Visibility Control** + +图中包含的子特性: + +|子特性|技术实现方式|可行性| +|---|---|---| +|多列表头,带排序箭头(↑↓)|Django 后端排序 + HTMX 请求 + Tailwind 样式|✅ 完全可行| +|行 Checkbox 多选|Alpine.js 管理选中状态|✅ 完全可行| +|行高亮(图中蓝色高亮行)|Alpine.js `:class` 绑定|✅ 完全可行| +|红色/橙色 Tag 标签(买卖、出租)|Tailwind `badge` 样式|✅ 完全可行| +|行内小图标按钮(电梯、满五等)|Tailwind + inline SVG icon|✅ 完全可行| +|价格字段带趋势小箭头(↑绿色)|Alpine.js 条件渲染|✅ 完全可行| +|列固定宽度 + 横向滚动条|Tailwind `overflow-x-auto` + `min-w`|✅ 完全可行| + +--- + +#### 2. Pagination(分页组件) + +图中右下角的 `共3629条 < 1 2 3 4 5 … 182 > 20条/页 跳至` + +|子特性|实现方式|可行性| +|---|---|---| +|页码导航|Django Paginator + HTMX `hx-get`|✅ 完全可行| +|每页条数选择(20条/页)|Alpine.js 下拉 + HTMX 请求|✅ 完全可行| +|跳至指定页|Alpine.js 输入框 + HTMX 请求|✅ 完全可行| +|省略号(…)页码|Django 后端分页逻辑生成|✅ 完全可行| + +--- + +#### 3. Column Visibility Panel(自定义列显示) + +图中右上角的 **"自定义列表"** 按钮 + +|子特性|实现方式|可行性| +|---|---|---| +|弹出面板,勾选显示/隐藏列|Alpine.js `x-show` + `x-data`|✅ 完全可行| +|列显示状态持久化|Alpine.js + `localStorage` 或后端存储|✅ 完全可行| +|动态隐藏表格列|Alpine.js `:class="{'hidden': !col.visible}"`|✅ 完全可行| + +--- + +#### 4. Toolbar(操作工具栏) + +图中顶部的 `房源海报 批量分享 批量收藏 取消收藏 设置保护房 更多▼` + +|子特性|实现方式|可行性| +|---|---|---| +|批量操作按钮(依赖 Checkbox 选中状态)|Alpine.js 全局选中状态 + 按钮 disabled 控制|✅ 完全可行| +|"更多"下拉菜单(Dropdown Menu)|Alpine.js `x-show` + `@click.away`|✅ 完全可行| +|共 N 条(动态数字)|HTMX 局部刷新 或 Alpine.js 绑定|✅ 完全可行| + +--- + +#### 5. Export Button(导出按钮) + +图中右上角 **"导出"** 按钮 + +|实现方式|可行性| +|---|---| +|Django 后端生成 CSV/Excel(用 `openpyxl`),返回文件流|✅ 完全可行,无需前端特殊处理| +|异步导出(数据量大时走 Celery 任务,邮件通知)|✅ 你的 Celery 栈已完全支持| + +--- + +#### 6. Smart Sort(智能排序) + +图中右上角 **"按智能排序"** 标签 + +| 实现方式 | 可行性 | +| ------------------------------- | ------ | +| 后端 Django ORM 多字段排序,HTMX 切换排序模式 | ✅ 完全可行 | + + +## Modal Dialog (模态对话框) +![[Modal Dialog.png]] +### 🪟 组件名称:Modal Dialog(模态对话框) + +图中这个"编辑房源价格"弹窗,包含以下子组件: + +#### 弹窗本体结构 + +|部位|组件名称|实现方式|可行性| +|---|---|---|---| +|灰色半透明遮罩层|Backdrop / Overlay|Tailwind `bg-black/50 fixed inset-0`|✅| +|白色弹窗卡片|Modal Panel|Tailwind `bg-white rounded-lg shadow-xl`|✅| +|顶部标题栏 + ✕ 关闭按钮|Modal Header|Alpine.js `@click="open=false"`|✅| +|底部确定/取消按钮组|Modal Footer / Button Group|Tailwind 按钮样式|✅| +|拖拽手柄(左上角 ⠿ 图标)|Draggable Handle|需要少量原生 JS 或 Alpine.js 插件|⚠️| + +#### 弹窗内的表单组件 + +|组件|名称|实现方式|可行性| +|---|---|---|---| +|带星号必填标记的标签|Required Field Label|Tailwind `text-red-500` + `*` 字符|✅| +|数字输入框 + 单位后缀(万)|Input with Suffix Addon|Tailwind Input Group|✅| +|普通文本输入框(售价/备案价)|Text Input|Tailwind `input` 样式|✅| +|多行文本域(更改理由)|Textarea|Tailwind `textarea` + 字数统计 `0/200`|✅| +|字数计数(右下角 0/200)|Character Counter|Alpine.js `x-model` + `:text="val.length + '/200'"`|✅| + +--- + +### ⚠️ 唯一需要注意的点:弹窗拖拽 + +图中左上角有一个 **⠿ 拖拽图标**,说明这个弹窗支持**拖动位置**。这个功能: + +- Alpine.js 原生**不内置**拖拽 +- 可以用 **Alpine.js 官方插件 `@alpinejs/drag`** 解决,无需引入额外大型库 + +### ✅ 结论 + +> 这个 Modal 弹窗及其内部所有表单组件,**用 Alpine.js + Tailwind CSS 完全可以实现**,包括开关状态、表单验证、字数统计。拖拽功能用 Alpine 官方插件即可覆盖,无需引入 Vue/React。 + +## Tree Select/Cascading Dropdown(树形下拉选择器) + +### 🌲 组件名称:Tree Select / Cascading Dropdown(树形下拉选择器) +![[Tree Select.png]] +#### 结构拆解 + +|部位|组件名称|说明| +|---|---|---| +|触发框(点击展开)|Select Trigger Input|显示已选内容,点击展开下拉| +|下拉面板|Dropdown Panel|绝对定位浮层,`z-index` 覆盖页面| +|可折叠父节点(▶ 沪居地产)|Tree Node / Collapsible Group|点击 ▶ 展开/收起子节点| +|子节点列表(上海豪园店等)|Tree Leaf Node|可点击选中| +|带头像的叶节点(沪居地产共享)|Tree Leaf with Avatar|头像 + 姓名 + 编号 + 操作链接| +|带状态标签的节点(沪居 关闭)|Node with Badge|橙色"关闭"tag| +|底部操作行(隐藏离职员工)|Footer Action|固定在下拉底部的全局操作| + +--- + +### 技术实现评估 + +#### ✅ 可行部分(Alpine.js 处理) + +``` +树形数据展开/折叠 → Alpine.js x-data 维护每个节点的 open 状态 +选中节点高亮 → Alpine.js :class 绑定 +点击外部关闭 → Alpine.js @click.away +头像/Badge/标签 → 纯 Tailwind CSS +底部固定操作行 → Tailwind sticky bottom +``` + +#### ⚠️ 需要重点关注的点 + +**这是你上传的三张图里技术难度最高的组件**,原因: + +1. **树形数据递归渲染**:HTMX 本身不擅长递归组件,需要 Alpine.js 配合后端返回的 JSON 数据,在前端用 `template` + `x-for` 递归渲染树节点 +2. **多级嵌套状态管理**:每个父节点独立维护 `open/close` 状态,需要 Alpine.js `x-data` 设计合理的数据结构 +3. **搜索过滤**(如果需要在下拉内搜索员工):需要 Alpine.js 实时过滤树节点,或 HTMX 请求后端过滤 + +--- + +### 💡 实现建议 + +**方案一(推荐):Alpine.js 纯前端渲染** + +> 后端一次性返回完整树形 JSON,Alpine.js 前端递归渲染,适合数据量不大的组织架构树 + +**方案二:HTMX 懒加载节点** + +> 点击展开节点时,HTMX `hx-get` 请求该节点的子数据,适合层级很深、数据量很大的场景 + +--- + +### ✅ 结论 + +> 可以实现,但这是你目前三个组件里**唯一需要认真设计前端数据结构**的组件,不能直接套 Flowbite 现成组件(Flowbite 没有 TreeSelect)。建议直接基于 Alpine.js 手写,逻辑量约 80~120 行 JS,可复用。 + + +## 带搜索的 Tree Select 完整功能清单 +![[Tree Select Search 2.png]] +### 🔍 带搜索的 Tree Select 完整功能清单 + +#### 新增的搜索相关特性 + +| 特性 | 说明 | 实现方式 | 可行性 | +| ------------ | -------------- | --------------------------- | --- | +| 下拉顶部搜索输入框 | 打开下拉后可直接键入关键词 | Alpine.js `x-model="query"` | ✅ | +| 实时过滤节点 | 输入时同步过滤匹配的节点 | Alpine.js computed 过滤 | ⚠️ | +| 搜索命中时自动展开父节点 | 子节点匹配时其父节点强制展开 | 需要递归遍历树形数据 | ⚠️ | +| 无结果时显示空状态 | "暂无匹配结果" | Alpine.js `x-show` | ✅ | +| 清空搜索恢复原始树结构 | 删除关键词后还原展开状态 | Alpine.js 状态重置 | ✅ | + +## Data Range Picker (日期范围选择) + +![[Date Range Picker.png]] +这个组件的正式名称是 **Date Range Picker(日期范围选择器)**,也叫 **Dual-Month Calendar Picker**。 + +--- + +### 📅 组件名称:Date Range Picker / 双月日历范围选择器 + +#### 结构拆解 + +|部位|说明| +|---|---| +|顶部输入框组(开始日期 → 结束日期)|Range Input Group,两个输入框用箭头连接,点击任意一个触发日历展开| +|双月并排日历面板|Dual Calendar Panel,左侧当月、右侧次月,联动翻页| +|月份导航(« < 2026年4月 > »)|单箭头切换月,双箭头切换年| +|今日高亮(23日红框)|当天日期特殊样式| +|选中日期高亮(26日蓝底)|已选日期样式| +|范围区间高亮(开始~结束之间蓝色背景)|Range Highlight,区间内日期浅蓝背景| +|跨月灰色日期(上下月溢出日)|灰色不可选日期| + +--- + +### 技术实现评估 + +#### ⚠️ 这是目前为止难度最高的组件 + +**难点在于:** + +1. **双月联动**:左右两个月份需要同步,翻页时右月始终等于左月+1 +2. **区间拖选高亮**:鼠标 hover 时实时预览区间,需要精细的状态管理 +3. **日期计算**:需要处理月份天数、周几起始、跨年等边界情况 + +--- + +### 💡 强烈推荐:直接用成熟库,不要手写 + +用 Alpine.js 从零手写一个双月 Date Range Picker 工作量巨大(400~600 行),且边界情况多,极易出 Bug。 + +#### 推荐方案:**Pikaday** 或 **Flatpickr** + +|库|特点|与你技术栈的兼容性| +|---|---|---| +|**Flatpickr**(强烈推荐)|轻量、无依赖、原生支持 Range 模式和双月显示,样式可用 Tailwind 覆盖|✅ 完美兼容,CDN 引入即用| +|**Pikaday**|更轻量,但双月需手动配置|✅ 可用,略需配置| + +**Flatpickr 双月 Range 模式只需三行配置:** + +javascript + +```javascript +flatpickr("#dateRange", { + mode: "range", + showMonths: 2, +}); +``` + +> 样式用 Tailwind 自定义覆盖即可达到图中效果,不破坏你"不混用技术"的原则——Flatpickr 是无框架依赖的纯 JS 工具库,不是 React/Vue 组件。 + +--- + +### ✅ 结论 + +> **不建议用 Alpine.js 手写**,引入 **Flatpickr**(CDN,约 16KB)是最优解,与你的 HTMX + Alpine.js + Tailwind 技术栈**完全兼容、无冲突**,实现图中效果只需少量配置。 + + +## Tab Navigation (标签页导航) + +### 🗂️ 组件名称:Tabs / Tab Navigation(标签页导航) + +#### 结构拆解 + +|部位|说明| +|---|---| +|Tab 标签栏|横向排列的标签按钮组,当前激活项(修改跟进)有橙色下划线 + 橙色文字| +|激活指示器|Active Indicator,图中为橙色底部边框线| +|Tab 内容面板|切换标签时显示对应内容区域| +|内容区:Timeline(时间线)|按日期分组的操作记录列表,左侧橙色圆点| +|内容区:Banner 提示条|顶部"智能总结"广告/提示横条| +|内容区:Activity Item(活动记录项)|每条记录含【操作类型】+ 操作人 + 时间 + 详情文字| +|每条记录右侧:Visibility Toggle|"公开/隐藏"文字切换按钮| +|底部:Load More Button|"查看全部跟进"加载更多按钮| + +--- + +### 技术实现评估 + +#### Tab 切换本体 + +这是所有组件里**实现最简单**的之一: + +html + +```html + +