docs: refresh repository agent guidance
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<!-- 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.
|
||||
@@ -8,35 +9,30 @@ This version has breaking changes — APIs, conventions, and file structure may
|
||||
|
||||
## 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).
|
||||
- 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
|
||||
|
||||
- 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.
|
||||
- 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 Architecture
|
||||
## Database And Ledger
|
||||
|
||||
- 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/`.
|
||||
- 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
|
||||
|
||||
- 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.
|
||||
- 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`.
|
||||
|
||||
Reference in New Issue
Block a user