Files
fluxent-web/AGENTS.md
T
SerinaNya c33857ffac feat(ledger): add bookkeeping workbench and transaction views
- Add transactions_dirty table and zero-tolerance cleansing action

- Implement bookkeeping workbench (/bookkeeping) with searchable Combobox channel selector and card suffix / account identifier

- Implement transaction ledger (/transactions) with date groupings, multi-currency metrics, and filters

- Update AGENTS.md guidelines for Base UI Select and Combobox bindings
2026-09-06 23:23:29 +08:00

4.1 KiB

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.

Fluxent Web

Commands

  • Use pnpm. Primary checks are pnpm lint, pnpm typecheck, and pnpm build; run pnpm typecheck && pnpm build to verify changes. There is no committed test suite.
  • Add UI primitives only via pnpm dlx shadcn@latest add <component> --yes. Read the referenced docs via pnpm dlx shadcn@latest docs <component> before using.
  • Format with pnpm format (Prettier + Tailwind plugin: double quotes, no semicolons, 2 spaces, LF, 80-column wrap).

App And Auth

  • Next.js 16 App Router application under app/. Authenticated pages compose SidebarProvider, AppSidebar, and SidebarInset themselves.
  • Next.js 16 uses proxy.ts, NOT middleware.ts. Keep proxy.ts edge-safe: import only lib/auth/config.ts, never database or password-hashing code.
  • Public routes: /login, /register, /api/auth/*. All other routes are protected by proxy.ts; server pages and server actions must still validate sessions via auth().
  • lib/auth/index.ts owns Node-side Auth.js providers and database operations. OIDC is disabled unless AUTH_OIDC_ENABLED=true with full issuer/client credentials configured.
  • Sidebar active state must derive from usePathname() (/ exact match, child routes prefix match). Do not add navigation links until their route exists.

Database And Ledger Architecture

  • PostgreSQL access via Drizzle ORM + postgres; schema truth is lib/db/schema.ts. Drizzle Kit loads DATABASE_URL from .env.local via drizzle.config.ts.
  • Schema sync: pnpm drizzle-kit push --force. Never execute pnpm tsx lib/db/reset.ts unless explicitly instructed (drops all data tables).
  • Multi-tenancy & safety: Every action in lib/actions/ must enforce userId = session.user.id and filter out soft-deleted records with isNull(table.deletedAt). Verify that referenced accounts or channels belong to the same user.
  • Two-tier transaction ledger:
    • Fast/draft entry stores records in transactions_dirty.
    • Cleansing action (cleanseTransactionsAction in lib/actions/bookkeeping.ts) performs atomic zero-tolerance validation before moving items into transactions.
  • Card brands: Stored as lowercase machine keys (visa, mastercard, unionpay, amex, diners, discover, jcb). Always use normalizeCardBrand() from lib/payment/card-brand.ts and local SVGs under /payment-logos/.

UI And Copy

  • Tech stack: shadcn base-nova on @base-ui/react, Lucide icons, Tailwind v4, semantic CSS variables from app/globals.css.
  • Base UI Select & Combobox:
    • <SelectValue />: When <SelectItem> contains complex JSX/icons and no plain string children, Base UI falls back to rendering raw values (e.g. UUIDs). Provide plain text children or explicit formatting logic.
    • <Combobox>: When items is an array of objects, always provide both itemToStringValue (string serialization for search matching and value keying) and itemToStringLabel (input display string) to avoid [object Object] display bugs.
  • Form composition: Use FieldGroup, Field, and FieldLabel. Put SelectItem inside SelectGroup. Use FieldSet/FieldLegend only when grouping adds visible user meaning.
  • Dialog composition: Follow standard structure (DialogHeader, form/content, DialogFooter directly inside DialogContent). Do not add p-0, negative margins, sticky footers, or manual scroll wrappers without a verified requirement.
  • Styling: Use gap-*, NEVER space-x-* or space-y-*. Use semantic color tokens, avoid hardcoded palettes or manual dark: overrides. Buttons with icons use data-icon="inline-start" or data-icon="inline-end".
  • Product copy is Chinese only: Do not add English parentheticals to labels, menus, options, or headings (e.g., no "账户 (Accounts)"). Retain user-entered values and standard business tokens (e.g., currency codes CNY, card brand names Visa) verbatim.