Files
fluxent-web/AGENTS.md
T

39 lines
3.9 KiB
Markdown

<!-- BEGIN:nextjs-agent-rules -->
# This is NOT the Next.js you know
This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
<!-- END:nextjs-agent-rules -->
# Fluxent Web
## Commands
- Use `pnpm`. Checks: `pnpm lint`, `pnpm typecheck`, `pnpm build`; there is no `test` script. `pnpm format` formats all `**/*.{ts,tsx}` with Prettier and the Tailwind plugin (2 spaces, double quotes, no semicolons, LF, 80 columns).
- Add shadcn primitives only with `pnpm dlx shadcn@latest add <component> --yes`; read their API first with `pnpm dlx shadcn@latest docs <component>`.
- This is Next.js 16.2.6. Read the relevant guide under `node_modules/next/dist/docs/` before changing Next.js APIs or conventions; do not assume older Next.js patterns.
## App And Auth
- App Router entry points live in `app/`. Each authenticated page validates `auth()` and composes `SidebarProvider`, `AppSidebar`, and `SidebarInset`; the proxy check does not replace server-side validation.
- Next.js 16 uses `proxy.ts`, not `middleware.ts`. Keep auth configuration imported by `proxy.ts` edge-safe; database and password code belongs in `lib/auth/index.ts`.
- Public routes are `/login`, `/register`, and `/api/auth/*`; other routes are protected. OIDC registers only when `AUTH_OIDC_ENABLED=true` and issuer/client ID are configured.
- Sidebar active state comes from `usePathname()` (`/` exact, child routes prefix). Add a navigation item only with its route.
## Database And Ledger
- PostgreSQL uses Drizzle + `postgres`; schema source of truth is `lib/db/schema.ts`. `drizzle.config.ts` explicitly loads `.env.local`. For local DB use `pnpm db:up` (Compose waits for health), `pnpm db:down` (keeps the named volume), and `pnpm db:logs`. Compose binds only to `127.0.0.1:5432`; Postgres data mounts at `/var/lib/postgresql` for the current PostgreSQL image layout. `docker compose down -v` permanently deletes local DB data.
- Apply schema changes with `pnpm drizzle-kit push --force`. Never run `pnpm tsx lib/db/reset.ts` unless explicitly instructed; it drops application tables.
- Scope business-data queries and mutations by the authenticated `session.user.id`, exclude soft-deleted rows with `isNull(table.deletedAt)`, and verify referenced accounts/channels belong to that user.
- Draft/imported transactions belong in `transactions_dirty`. `cleanseTransactionsAction` in `lib/actions/bookkeeping.ts` validates the whole batch and atomically moves valid rows to `transactions`.
- `/import` currently accepts CCBA CSV only (PDF conversion is not implemented); its server action stages rows in `transactions_dirty` and resolves account-to-channel mappings.
- Card brands are stored as lowercase keys. Use `normalizeCardBrand()` from `lib/payment/card-brand.ts` and local SVGs under `/payment-logos/`.
## UI And Copy
- UI stack: shadcn `base-nova` on `@base-ui/react`, Lucide, Tailwind v4, and CSS variables in `app/globals.css`. `components/ui/` contains shadcn CLI-managed primitives; the reusable responsive grid list is `components/data-list.tsx`.
- Base UI: keep `SelectItem` inside `SelectGroup`; give `SelectValue` plain-text children or explicit formatting when item content is complex. For object-valued Combobox `items`, provide both `itemToStringValue` and `itemToStringLabel`.
- Forms use `FieldGroup`, `Field`, and `FieldLabel`; use `FieldSet`/`FieldLegend` only for meaningful groups. Dialogs use `DialogHeader`, content/form, and `DialogFooter` directly inside `DialogContent`.
- Use `gap-*`, not `space-x-*`/`space-y-*`; use semantic tokens, not hardcoded palettes or manual `dark:` overrides. Icon buttons use `data-icon="inline-start"` or `data-icon="inline-end"`.
- Product-facing copy is Chinese. Do not add English parentheticals to labels, menus, options, or headings; preserve user-entered values and standard tokens such as `CNY` and `Visa`.