# Copilot Instructions — Fiddy (External DB) ## Source of truth - Always consult PROJECT_INSTRUCTIONS.md at the repo root. - If any guidance conflicts, PROJECT_INSTRUCTIONS.md takes precedence. - Keep this file focused on architecture/stack; keep checklists and project workflow rules in PROJECT_INSTRUCTIONS.md. - When asked to fix bugs, follow DEBUGGING_INSTRUCTIONS.md at the repo root. ## Stack - Monorepo (npm workspaces) - Next.js (App Router) + TypeScript + Tailwind - External Postgres (on-prem server) via node-postgres (pg). No ORM. - Docker Compose dev/prod - Gitea + act-runner CI/CD ## Environment - Dev and Prod must use the same schema/migrations (`packages/db/migrations`). - `DATABASE_URL` points to the external DB server (NOT a container). ## Auth - Custom email/password auth. - Use HttpOnly session cookies backed by DB table `sessions`. - NEVER trust client-side RBAC checks. ## Receipts - Store receipt images in Postgres `bytea` table `receipts`. - Entries list endpoints must not return image bytes. - Image bytes only fetched by separate endpoint when inspecting a single item. ## UI - Dark mode, minimal, mobile-first. - Dodger Blue accent (#1E90FF). - Top navbar: left nav dropdown, middle group selector, right user menu. ## Code Rules - Small files, minimal comments. - Prefer single-line `if` without braces when only one line follows. - Heavy logic lives in components/hooks/services, not page files. - Prefer API calls via exported hooks/services for reusability and cleanliness (avoid raw fetch in components when possible). - Add/update unit tests with changes (TDD). - Heavy focus on code readability and maintainability; prioritize clean code over clever code. - ie. Separating different concerns into different files, and adding helper functions to avoid nested logic and improve readability, is preferred over clever one-liners or consolidating logic into fewer files. - ie. Separate groups of related codes by adding 3 line breaks between them ## Data Model - Users (system_role USER|SYS_ADMIN) - Groups + membership (group_role MEMBER|GROUP_ADMIN) - Entries (group-scoped) + optional receipt_id - User settings (jsonb) - Reports for system admins ## Architecture Contract (Backend ↔ Client ↔ Hooks ↔ UI) ### No-Assumptions Rule (Required) - Before making structural changes, first scan the repo and identify: - the web app root (where `app/`, `components/`, `hooks/`, `lib/` live) - existing API routes and helpers - existing patterns already in use - Do not invent files, endpoints, or conventions. If something is missing, add it minimally and consistently. ### Layering (Hard Boundaries) For every domain (auth, groups, entries, receipts, etc.), keep a consistent 4-layer flow: 1) **API Route Handlers** (`app/api/.../route.ts`) - Thin: parse input, call a server service, return JSON. - No direct DB queries inside route files unless there is no existing server service. - Must enforce auth & membership checks on server. 2) **Server Services (DB + authorization)** (`lib/server/*`) - Own all DB access and authorization helpers (sessions, requireGroupMember, etc.). - Server-only modules must include `import "server-only";` - Prefer small domain modules: `lib/server/auth.ts`, `lib/server/groups.ts`, `lib/server/entries.ts`, `lib/server/session.ts`. 3) **Client API Wrappers** (`lib/client/*`) - Typed fetch helpers only (no React state). - Centralize `fetchJson()` / error normalization. - Always send credentials (cookies) and never trust client-side RBAC. 4) **Hooks (UI-facing API layer)** (`hooks/use-*.ts`) - Hooks are the primary interface for components/pages to call APIs. - Components should not call `fetch()` directly unless there’s a strong reason. ### Domain Blueprint (Consistency Rule) For any new feature/domain, prefer: - `app/api//...` - `lib/server/.ts` - `lib/client/.ts` - `hooks/use-.ts` - `components//*` - `__tests__/.test.ts` ### API Conventions - Prefer consistent JSON response shape for errors: - `{ error: { code: string, message: string } }` - Validate inputs at the route boundary (basic shape/type), and validate authorization in server services. - When adding endpoints, mirror existing REST style used in the project. ### Non-Regression Contracts (Do Not Break) - Entries list endpoints must **never** include receipt image bytes; image bytes are fetched via a separate endpoint only. - Auth is DB-backed HttpOnly sessions; all auth checks are server-side. - Groups require server-side membership checks; active group persists per user. - Group invite codes: - shown once immediately after group creation - modal renders outside navbar/header so it overlays the viewport correctly - avoid re-exposing invite code elsewhere without explicit “group settings” work ### UI Structure - Page files stay thin; heavy logic stays in hooks/services/components. - Dark mode, minimal, mobile-first. - Dodger Blue accent (#1E90FF). - Navbar: left nav dropdown, middle group selector, right user menu. ### Environment - Dev and Prod must use the same schema/migrations (`packages/db/migrations`). - `DATABASE_URL` points to external Postgres (NOT a container). - `DATABASE_URL` format must be a full connection string; URL-encode special chars in passwords. ### Tests (Required) - Add/update tests for API behavior changes: - auth - groups - entries (group scoping) - Tests must include negative cases: unauthorized, not-a-member, invalid inputs.