# 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`. 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 --yes`; read their API first with `pnpm dlx shadcn@latest docs `. - 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`.