3.9 KiB
3.9 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. Checks:pnpm lint,pnpm typecheck,pnpm build; there is notestscript.pnpm formatformats 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 withpnpm 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 validatesauth()and composesSidebarProvider,AppSidebar, andSidebarInset; the proxy check does not replace server-side validation. - Next.js 16 uses
proxy.ts, notmiddleware.ts. Keep auth configuration imported byproxy.tsedge-safe; database and password code belongs inlib/auth/index.ts. - Public routes are
/login,/register, and/api/auth/*; other routes are protected. OIDC registers only whenAUTH_OIDC_ENABLED=trueand 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 islib/db/schema.ts.drizzle.config.tsexplicitly loads.env.local. For local DB usepnpm db:up(Compose waits for health),pnpm db:down(keeps the named volume), andpnpm db:logs. Compose binds only to127.0.0.1:5432; Postgres data mounts at/var/lib/postgresqlfor the current PostgreSQL image layout.docker compose down -vpermanently deletes local DB data. - Apply schema changes with
pnpm drizzle-kit push --force. Never runpnpm tsx lib/db/reset.tsunless explicitly instructed; it drops application tables. - Scope business-data queries and mutations by the authenticated
session.user.id, exclude soft-deleted rows withisNull(table.deletedAt), and verify referenced accounts/channels belong to that user. - Draft/imported transactions belong in
transactions_dirty.cleanseTransactionsActioninlib/actions/bookkeeping.tsvalidates the whole batch and atomically moves valid rows totransactions. /importcurrently accepts CCBA CSV only (PDF conversion is not implemented); its server action stages rows intransactions_dirtyand resolves account-to-channel mappings.- Card brands are stored as lowercase keys. Use
normalizeCardBrand()fromlib/payment/card-brand.tsand local SVGs under/payment-logos/.
UI And Copy
- UI stack: shadcn
base-novaon@base-ui/react, Lucide, Tailwind v4, and CSS variables inapp/globals.css.components/ui/contains shadcn CLI-managed primitives; the reusable responsive grid list iscomponents/data-list.tsx. - Base UI: keep
SelectIteminsideSelectGroup; giveSelectValueplain-text children or explicit formatting when item content is complex. For object-valued Comboboxitems, provide bothitemToStringValueanditemToStringLabel. - Forms use
FieldGroup,Field, andFieldLabel; useFieldSet/FieldLegendonly for meaningful groups. Dialogs useDialogHeader, content/form, andDialogFooterdirectly insideDialogContent. - Use
gap-*, notspace-x-*/space-y-*; use semantic tokens, not hardcoded palettes or manualdark:overrides. Icon buttons usedata-icon="inline-start"ordata-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
CNYandVisa.