chore: import clean Agent Desk snapshot (1/7)

This commit is contained in:
2026-10-16 11:55:22 +00:00
parent 24f6423407
commit 79176541c7
323 changed files with 34882 additions and 2 deletions

275
AGENTS.md Normal file
View File

@@ -0,0 +1,275 @@
# AGENTS.md
This file defines the mandatory working agreement for AI agents in this repository. It is intentionally based on the current codebase rather than historical conventions.
## 1. Scope and Priorities
- These rules apply to the repository root and every subdirectory.
- Explicit user instructions take precedence over this file. Mention any deliberate deviation in the final summary.
- Inspect the relevant implementation before editing. Reuse current helpers, component APIs, generated-code workflows, and neighboring patterns instead of relying on memory.
- Keep changes narrowly scoped. Preserve unrelated and user-owned worktree changes, including staged changes.
- A review, investigation, or diagnosis request is read-only unless the user also asks for implementation.
## 2. Current Architecture
The repository contains three application areas:
- Go server: `cmd/server` and `internal/*`
- Next.js application: `web/*`
- Embedded workflow editor: `flowgram-editor/*`, built into `web/public/flowgram-editor`
The main stack is:
- Go 1.26, Gin, GORM, `github.com/mlogclub/simple`
- SQLite and MySQL
- Next.js 16 App Router, React 19, TypeScript, Tailwind CSS, shadcn/Base UI
- `pnpm` for both frontend projects
- Optional LanceDB builds through CGO; Qdrant is also supported by the application
Important entry points:
- Server assembly and middleware: `internal/bootstrap/server.go`
- Explicit API routes: `internal/bootstrap/routes.go`
- Model registration: `internal/models/models.go`
- Schema/data migration startup: `internal/bootstrap/migration.go`
- CRUD generator: `cmd/generator/generator.go`
- Frontend enum generator: `cmd/enums/generator.go`
- Frontend API client: `web/lib/api/client.ts`
- Frontend i18n: `web/i18n/*` and `web/messages/*`
- Dashboard shared components: `web/components/dashboard/*`
- Project commands: `Taskfile.yml`
## 3. General Change Rules
- Read the actual type, function, or component signature before using it.
- Prefer the highest-level existing abstraction that fits the requirement. Do not duplicate query state, pagination, auth refresh, localization, or dashboard CRUD behavior.
- Do not edit generated artifacts by hand. Change their source and run the corresponding generator/build command.
- Do not add a second implementation style when the repository already has a shared path for the same concern.
- Use `log/slog` for new Go logging and structured key-value fields for relevant context.
- New Go code uses `any`, not `interface{}`. Existing generated or legacy code does not need unrelated cleanup.
- Secrets, tokens, credentials, and private customer data must never be committed or printed in logs/tests.
## 4. Go Backend
### 4.1 Layer Ownership
The normal dependency and data flow is:
`models -> repositories -> services -> handlers -> builders/response DTOs`
- `internal/models`: entity fields, GORM mappings, associations, and schema metadata only.
- `internal/repositories`: GORM/SQL access, conditions, ordering, pagination, locks, and persistence details.
- `internal/services`: business validation, state changes, authorization-independent domain rules, aggregation, transactions, and event orchestration.
- `internal/handlers/{api,dashboard,third}`: HTTP parameter parsing, authentication/permission checks, service calls, and response writing.
- `internal/builders`: pure model/aggregate-to-response mapping. Builders must not query the database.
- `internal/pkg/dto/request` and `internal/pkg/dto/response`: external request/response contracts.
Mandatory boundaries:
- Handlers must not call repositories or issue GORM queries directly.
- Models and repositories must not contain HTTP, permission, or cross-resource workflow logic.
- GORM models must not be returned directly from an API. Map them to response DTOs/builders.
- A service may return models internally, but public response shape remains owned by builders/DTOs.
- Put reusable SQL in repositories. A genuinely one-off aggregate query may stay near its domain service only when extraction would make ownership less clear.
### 4.2 Database and Transactions
- Repository methods that participate in transactions accept `db *gorm.DB`; call them with `sqls.DB()` outside a transaction and `ctx.Tx` inside one.
- Services own transaction boundaries through `sqls.WithTransaction`.
- Use a transaction for atomic multi-write workflows and consistency-sensitive read-modify-write operations.
- Do not add a transaction around a single independent SQL write.
- Every database operation inside a transaction must use the same `ctx.Tx`; never escape to `sqls.DB()` mid-transaction.
- Use `sqls.Cnd`/`sqls.NewCnd()` and repository methods for ordinary filtering and pagination.
- Preserve SQLite and MySQL compatibility. Avoid dialect-specific SQL unless both dialects are explicitly implemented and tested.
- Use portable column types and `int64` primary/foreign identifiers. Keep time handling compatible with MySQL `parseTime=True`.
### 4.3 Models, Generation, and Migrations
- Register persistent models in `internal/models/models.go` so startup `AutoMigrate(models.Models...)` includes them.
- New tables, columns, indexes, and compatible constraints are normally applied by GORM `AutoMigrate` in `internal/bootstrap/migration.go`.
- Use `internal/migration/*` only for versioned, idempotent data migration/backfill/repair work. Its version must increase monotonically.
- When a model uses the standard generated repository/service surface, register it in `cmd/generator/generator.go` and run `task generator`.
- Treat generator output as mechanical infrastructure. Put business-specific methods in handwritten files and do not manually patch generated CRUD output.
- Backend/frontend shared enums are defined in `internal/pkg/enums`, annotated using the existing enum pattern, and generated with `task enums` into `web/lib/generated/enums.ts`.
- Never create a handwritten frontend duplicate of a generated backend enum.
### 4.4 HTTP APIs
- All routes are explicit in `internal/bootstrap/routes.go`; handler names do not create endpoints.
- Public/product APIs live under `/api/*`, authenticated management APIs under `/api/dashboard/*`, callbacks under `/api/third/*`, and WebSockets under `/api/ws/*`.
- Add a resource-specific `register...Routes` function or extend the existing one, then mount it from `addRouter` under the correct group.
- Follow the existing resource contract: detail commonly uses `GET /:id`, list uses `/list`, writes use explicit POST actions such as `/create`, `/update`, `/delete`, and domain actions retain their established snake_case path names.
- Do not introduce `/api/v1`, automatic routing assumptions, or unnecessary deeply nested resource paths.
- Handler names mirror the registered method and path, for example `XxxGetBy`, `XxxAnyList`, and `XxxPostCreate`.
- Parse JSON/form/query/path values with `internal/pkg/httpx/params` and `internal/pkg/httpx` helpers.
- Dashboard permission checks use `services.AuthService.RequirePermission` or the established permission helper before domain work.
- Write responses through `httpx.WriteJSON`; preserve the shared `JsonResult` contract.
- Paginated responses use `web.PageResult` with `data.results` and `data.page`.
- Convert not-found, validation, permission, and persistence failures into stable application errors. Never expose raw SQL errors to clients.
### 4.5 Backend Internationalization
- Any new or changed user-visible backend error must support every backend locale, currently `zh-CN` and `en-US`.
- Add matching keys to both `internal/pkg/i18nx/locales/zh-CN.yml` and `internal/pkg/i18nx/locales/en-US.yml` in the same change.
- Services should return localized application errors through the `errorsx.*I18n` helpers.
- Handlers that need an immediate localized response use `httpx.JsonErrorMsg(ctx, key, args...)`; other request-context translation uses `i18nx.T`.
- Do not hard-code Chinese or English error sentences in handlers/services when the text can reach a user.
- Keep format arguments equivalent across locales and cover new reusable/error-format behavior with focused tests.
## 5. Frontend
### 5.1 Component and Data Boundaries
- Application routes live under `web/app`; reusable business components live under `web/components`; route-private components live in the route's `_components` directory.
- Reuse `web/components/ui/*` primitives. Do not edit these shadcn base components for a feature-specific requirement.
- Use the current Base UI/shadcn component API as implemented in the repository; do not assume APIs such as Radix `asChild` exist.
- Use `@/*` imports for code within `web`.
- Client components must declare `"use client"` when they use state, effects, browser APIs, or client-only hooks.
- Keep resource APIs in `web/lib/api/*` and route all normal requests through `web/lib/api/client.ts`.
- Pages, business components, and stores must not implement their own `JsonResult` parsing, auth header handling, token refresh, or login-expiry cleanup.
- Direct `fetch` is reserved for unsupported transports such as third-party calls, binary transfers, SSE, and WebSocket handshakes; explain the exception in code.
- Prefer `OptionCombobox` for standard dropdowns rather than adding shadcn Select-based business controls.
- Format displayed timestamps with `formatDateTime` from `web/lib/utils.ts` unless the product explicitly requires a different representation.
### 5.2 Dashboard Pages
Before building a dashboard page, inspect `web/components/dashboard/crud`, `web/components/dashboard/list`, and `web/components/dashboard-page.tsx`.
Use this order of preference:
1. `DashboardCrudPage` for standard create/read/update/delete resources.
2. `DashboardListPage` for read-only or custom-content paginated resources.
3. `useDashboardPagedList` when layout is bespoke but list query/filter/pagination lifecycle is standard.
4. `DashboardPage`, `DashboardToolbar`, `DashboardTableShell`, and related low-level primitives only for interactions that cannot fit the higher-level components.
Rules:
- Do not copy a resource page to recreate standard filters, query/reset/refresh actions, pagination, loading/empty states, confirmations, row actions, or dialogs.
- Configure `DashboardCrudPage` through its filters, columns, labels, service callbacks, row actions, sorting, and form/dialog extension points before adding page-local infrastructure.
- Use its schema-driven `DashboardCrudFormDialog` when supported. A genuinely custom form may live in `_components` and should normally use `react-hook-form`, `zod`, and `Field`.
- Configure `DashboardListPage` with columns or `renderContent`, and use `renderToolbarActions` for resource-specific actions.
- Business API knowledge stays in the page/service module; generic dashboard components must not import a resource-specific API.
- A change to `web/components/dashboard/*` must be generic, backward-compatible, and useful beyond one page. Otherwise keep it local to the feature.
### 5.3 Frontend Internationalization
- Every frontend feature and modification must work in all `SUPPORTED_LOCALES`, currently `zh-CN` and `en-US`.
- Add every new key to both `web/messages/zh-CN.json` and `web/messages/en-US.json` in the same change, preserving matching structure.
- React pages/components use `useI18n()`; locale-aware formatting/mapping may also use `useAppLocale()`.
- Non-React code uses `translateCurrentMessage()` or `translateMessage()` from `web/i18n/messages.ts`.
- Do not hard-code user-visible copy in JSX/TSX, toast messages, dialogs, confirmations, placeholders, validation, empty/loading/error states, tooltips, accessibility labels, or client-side fallback errors.
- Product names, protocol literals, user content, and raw business data do not need translation unless the UI already provides a display-name mapping.
- Dashboard labels supplied to shared CRUD/list components must come from translation keys.
- Centralize localized display names for backend identifiers/enums in a reusable `web/lib/*-i18n.ts` helper instead of duplicating locale switches across pages.
- Preserve the same placeholders in every locale and interpolate with `t(key, values)`; do not assemble sentences by concatenating translated fragments.
- Locale configuration belongs to `AppI18nProvider` and `web/i18n/config.ts`; features must not introduce separate locale detection or state.
### 5.4 Commercial-Grade UI and Interaction
This is a commercial product, not a prototype or component demo. UI work is complete only when it is visually coherent, interaction-complete, responsive, localized, and credible with real production data.
#### Visual Quality
- Follow the existing design language, spacing scale, typography, radius, color tokens, and component variants. A new feature must look native to the product rather than like a pasted template.
- In support platform UI, if rounded corners are needed, use `rounded-md` consistently.
- Support platform components should not add `shadow`.
- Establish a clear hierarchy: page title/primary action, filters or context, main content, and secondary information. Do not make every region a card or every action visually prominent.
- Prefer restrained, purposeful styling. Avoid decorative gradients, oversized hero text, excessive shadows, glass effects, emoji icons, random accent colors, and ornamental copy unless the product context explicitly calls for them.
- Use Lucide icons consistently. Choose icons by meaning, keep icon size and stroke weight aligned with neighboring controls, and never use icons as decoration without communicative value.
- Keep spacing and alignment deliberate at every breakpoint. Labels, inputs, table columns, action groups, dialog footers, and empty states must align cleanly without ad hoc offsets.
- Design for realistic content, not ideal sample text. Verify long names, multiline content, large counts, missing optional fields, and mixed Chinese/English values. Use wrapping, truncation, tooltips, or scroll containers intentionally.
- Preserve information density appropriate to an operations dashboard. Do not waste large areas on decoration, but do not compress controls until scanning and clicking become difficult.
#### Interaction Completeness
- Every asynchronous action must have an immediate and unambiguous state: pending/loading, success, failure, and retry or recovery when appropriate.
- Prevent duplicate submissions. Disable or lock the initiating control while a mutation is pending and show action-specific progress text or a spinner without causing layout shift.
- Keep feedback close to the action. Use inline validation for field problems, contextual error states for failed content, and toast notifications for completed background or page-level actions.
- Never silently discard user input. Warn before closing, navigating away, resetting, or switching context when there are meaningful unsaved changes.
- Destructive, irreversible, security-sensitive, or broad-impact operations require confirmation that clearly names the object and consequence. Do not use a generic “Are you sure?” message.
- Confirmation is not a substitute for good defaults: routine reversible actions should remain efficient and should not be interrupted by unnecessary modal prompts.
- After create/update/delete operations, keep list state coherent: refresh affected data, preserve useful filters/page position when possible, close dialogs only on success, and prevent stale selections or detail panels.
- Buttons and menu items must use precise verbs describing the result. Avoid vague labels such as “OK”, “Submit”, or “Process” when a specific action name is available.
- Preserve keyboard behavior and focus flow: Enter submits only where expected, Escape closes dismissible overlays, focus moves into dialogs and returns to the trigger, and destructive actions are not the accidental default.
- Interactive rows, icons, badges, and text links must look interactive only when they are interactive. Do not rely on hover-only discoverability for essential actions.
#### Forms and Dialogs
- Use the smallest suitable interaction container: inline editing for simple local changes, a dialog for focused tasks, and a full page/workbench for complex or multi-step workflows.
- Dialogs need a clear title, concise context when necessary, stable body layout, and a consistent footer with secondary action before primary action. Long content must scroll inside the dialog without pushing actions off-screen.
- Forms must have visible labels, appropriate controls, useful defaults, required/optional semantics, and examples or help text only where they reduce ambiguity.
- Validate at the right time: do not show errors before the user has interacted, clear stale errors after correction, and map backend validation failures to the relevant field when possible.
- Preserve entered values after failed submission. Do not reset or close a form until the server confirms success.
- Dependent fields must clearly reflect disabled/loading/empty states. When one field invalidates another, update it predictably and explain the dependency when it is not obvious.
- Configuration and high-impact forms should not expose a permanently editable surface when a deliberate edit mode improves safety. Saving sensitive configuration requires explicit user intent and appropriate confirmation.
#### Lists, Tables, and Operational Screens
- Use the shared Dashboard CRUD/list system and maintain consistent toolbar, filter, pagination, loading, empty, and action placement across resources.
- Filters must distinguish draft values from applied query state. Query, reset, refresh, pagination, and URL/state behavior should be predictable and must not unexpectedly erase one another.
- Tables must remain scannable: align comparable values, keep action columns stable, use badges sparingly for status, avoid dense multiline cells when a detail view is more appropriate, and provide horizontal overflow on narrow screens.
- Empty states must distinguish “no data exists” from “no results match the current filters” and offer the most relevant next action when the user can resolve the state.
- Loading states should preserve layout. Prefer skeletons for content whose shape is known and compact spinners for localized actions; avoid replacing an entire stable page with a centered spinner.
- Error states must explain what failed in user terms and provide retry when retry is meaningful. Never leave a blank table or empty panel after a request failure.
- Bulk actions must show selection count, affected scope, eligibility, and partial-failure results. Clear selection when it is no longer valid.
#### Responsive and Accessibility Requirements
- Every changed screen must work at desktop and narrow/mobile widths. Do not treat horizontal clipping, overlapping controls, wrapped action chaos, or off-screen dialog buttons as acceptable.
- Responsive behavior must preserve task priority: primary actions remain reachable, secondary actions may move into menus, filters may stack or collapse, and tables may scroll without hiding row identity/actions.
- Use semantic controls and accessible names. Icon-only buttons require localized accessible labels and tooltips where the meaning is not universally obvious.
- Maintain visible focus states, logical tab order, sufficient target sizes, and adequate text/background contrast. Do not encode status or errors using color alone.
- Respect reduced-motion preferences. Animations should explain state or continuity, remain subtle, and never delay work.
#### Product Copy and Data Credibility
- Copy must sound like a finished product: concise, specific, consistent, and action-oriented. Do not expose implementation jargon, placeholder prose, “TODO”, mock labels, debug wording, or developer instructions to users.
- Do not ship fake statistics, sample records, disabled-looking placeholder buttons, decorative charts without meaning, or interactions that only log to the console.
- Distinguish unavailable features from empty data. If a capability is not implemented, do not render a control that pretends it is functional.
- User-visible names, statuses, permissions, dates, and errors must use the established formatting and i18n mappings rather than raw backend identifiers.
#### UI Verification
- For meaningful UI changes, inspect the finished screen in a real browser at representative desktop and narrow widths. Source review and typecheck alone are not sufficient visual validation.
- Exercise the complete interaction, including initial load, populated state, empty/filtered state, validation failure, server failure when practical, pending/disabled behavior, success, cancel/close, and refresh.
- Check both `zh-CN` and `en-US`; verify that translated copy does not overflow, truncate critical meaning, or break control alignment.
- Before handoff, remove temporary data, debug UI, console output, test-only shortcuts, and visual artifacts introduced during verification.
- When browser verification cannot be performed, state that limitation explicitly; do not describe the UI as visually verified.
### 5.5 Generated and Embedded Frontend Assets
- `web/lib/generated/enums.ts` is generated by `task enums`; do not edit it manually.
- `web/public/sdk/agent-desk-sdk.min.js` is generated from the SDK source. When SDK source changes, run `cd web && pnpm build:sdk` and its focused SDK tests.
- `web/public/flowgram-editor` is produced from `flowgram-editor`; edit the source project, not the generated public output.
- When changing `flowgram-editor`, use its own `pnpm` scripts and ensure the embedding build still succeeds.
- The Next.js application is statically exported/embedded into the Go binary. Avoid runtime-only Next.js features that conflict with the current export and embedding model.
## 6. Testing and Validation
Validation must match the changed surface. Do not claim checks that were not run.
- Go formatting: run `gofmt` on every changed `.go` file.
- Go behavior: add focused tests for changed business rules, transactions, security boundaries, parsing, and reusable helpers; run the narrow package tests first, then `go test ./...` when practical.
- Frontend TypeScript: run `cd web && pnpm typecheck` for frontend changes.
- Frontend lint: run `cd web && pnpm lint` for broader component/page changes or when lint-sensitive code changed.
- Frontend logic: run relevant `node --test ...` files when changing utilities, i18n mappings, generated SDK behavior, or other modules with focused tests.
- Workflow editor: run the relevant `flowgram-editor` lint/build commands for changes in that project.
- Generation: after model CRUD or shared enum changes, run the corresponding `task generator` or `task enums` and review generated diffs.
- Build: use `task build` when changes affect frontend embedding, build configuration, generated public assets, or release assembly.
- Browser verification is expected for meaningful visual or interaction changes when a runnable environment is available; state explicitly when it was not performed.
- Documentation-only changes require at least `git diff --check` and verification that every referenced path/command exists.
## 7. Completion Checklist
Before handing off a change, confirm the applicable items:
- The implementation follows current layer/component ownership and does not create reverse dependencies.
- Transactions cover exactly the operations that must be atomic, and all transactional DB calls use the same `ctx.Tx`.
- API routes are explicitly registered and responses preserve `JsonResult`/`PageResult` contracts.
- Models, migrations, queries, and tests remain compatible with SQLite and MySQL.
- Backend and frontend user-visible text is complete in both Chinese and English.
- Dashboard pages reuse the highest-level suitable component under `web/components/dashboard/*`.
- UI changes meet the commercial-grade standard: complete states, precise feedback, safe mutations, responsive layout, accessible controls, credible copy/data, and no demo-only behavior.
- Generated files were regenerated from their source and were not manually edited.
- Relevant tests/typechecks/lint/build/browser checks were run, and any validation limitation is reported.
- `git diff --check` passes and unrelated worktree changes remain untouched.