accounts/dashboard/AGENTS.md
2025-12-02 16:04:53 +08:00

5.4 KiB

Agent Guidelines for dashboard/

These instructions apply only to the dashboard/ subtree of XControl. They augment the root-level AGENTS.md with stricter rules specifically for the Next.js UI codebase.

The dashboard is a Next.js App Router application implemented in TypeScript with Tailwind CSS, Zustand state management, and Vitest/Playwright tests.

This document defines the architectural rules that all contributors — human or AI agents — must follow when modifying any code under dashboard/.

📌 1. State Management Rules (Zustand-Only Architecture)

Global state inconsistencies are the primary source of UI bugs and unpredictability. To eliminate this entire class of issues, the dashboard enforces:

Zustand is the ONLY allowed global/shared state mechanism. React Context Providers are disallowed for global state.

This includes:

No createContext, useContext, or <Context.Provider> for app-level data (auth/session/user/theme/language/insight/workbench/shared config). No “hybrid” patterns where Zustand data is mirrored inside a Provider. No component-level useState / useEffect holding cross-component state.

✔ All shared state MUST live inside Zustand slices

Each slice must: Export a useXStore(selector) function. Expose clear state + actions. Remain serializable for hydration when needed. Keep the shape stable and predictable.

✔ Recommended slice structure (pattern) /dashboard/src/state/ user.ts → auth/session theme.ts → light/dark/system language.ts → i18n insight.ts → insight editor / workbench runtime.ts → runtime service config (hydrated from YAML)

Slices should follow this format:

export const useUserStore = create()( persist( (set, get) => ({ user: null, isLoading: false, setUser: (u) => set({ user: u }), clearUser: () => set({ user: null }), }), { name: 'user' } ) )

📌 2. URL-Synchronized State Must Live in Zustand

Features such as:

insight editor / workbench state encoded shareable links URL → state hydration state → URL serialization MUST be handled inside the Zustand slice not in the component tree.

Forbidden

Components containing URL parsing logic Components reading searchParams and storing them in local state Effects that attempt to “mirror” global data into component-local state ✔ Mandatory

Zustand slices must expose helpers such as:

hydrateFromURL(searchParams: URLSearchParams) syncToURL(router: AppRouterInstance) serialize(): string

This keeps the UI stateless and predictable.

📌 3. Component-level State Rules

Local UI state (modal open, hover, controlled inputs) is allowed:

Allowed:

useState for purely local visuals useEffect for browser-only side effects useRef for DOM details

Not allowed:

useState for data needed across pages/components useEffect that propagates shared state upward

When unsure: If two components could ever read it → it belongs in Zustand.

📌 4. File Structure & Code Conventions Directory structure

Maintain component, state, and utility layout:

src/ app/ → routes (App Router) components/ → presentational components state/ → Zustand slices hooks/ → reusable UI hooks lib/ → shared utilities (non-state) config/ → runtime-service-config.yaml and loaders

Code style

ESLint + Prettier formatting

2-space indentation

Single quotes

No unused exports

No default exports for slices or large utilities (Easier for static analysis + tree shaking)

📌 5. Environment, Config & Runtime Rules Declarative configuration only

Do not add browser-only environment variables.

All new runtime config fields must go into:

dashboard/config/runtime-service-config.yaml

And be hydrated by a Zustand slice (e.g., runtime.ts).

📌 6. AI Agent (Codex/GPT) Rules — Strict Mode

Because the dashboard often uses AI to refactor/upgrade code, the following constraints apply specifically to code generated by agents:

🚫 Agents MUST NOT:

Generate any form of React Provider for global state

Introduce hybrid Context+Zustand patterns

Use component-level state for shared logic

Use browser APIs (window, localStorage) in server-compatible modules

Change directory structure without explicit instruction

Generate environment variables not reflected in runtime-service-config.yaml

Agents MUST:

Implement all shared logic as Zustand slices

Keep slices serializable and deterministic

Produce code compatible with Next.js App Router (SSR + CSR safe)

Follow ESLint and existing style conventions

Ensure newly generated slices include proper actions/selectors

Prefer pure functions and stable keys for Zustand persist middlewares

📌 7. Testing Requirements

Contributors must run:

yarn --cwd dashboard lint yarn --cwd dashboard test yarn --cwd dashboard test:e2e

Slices that handle URL hydration must include unit tests verifying:

URL → state correctness

state → URL correctness

shareable link determinism

Insight-related state should always include at least minimal test coverage.

📌 8. Summary of Key Constraints (TL;DR) 🚫 Forbidden

React Context for shared/global state

useState/useEffect for cross-component data

Ad-hoc URL parsing inside components

✔ Required Zustand-only global state URL hydration inside Zustand slices Declarative runtime config (YAML → slice) AI agents must follow deterministic slice architecture