Compare commits

..

No commits in common. "e4774ecd6a300ebc52b7e8d79d0b2e9dddbb5f64" and "5a2848ebcfdbbe1dc054b26ec4802f7e4a75ae7a" have entirely different histories.

25 changed files with 2532 additions and 932 deletions

View File

@ -1,40 +0,0 @@
---
name: fiddy-verify
description: Run and report the Fiddy repository verification loop. Use when Codex is finishing changes, checking repo health, validating docs/scripts/config updates, or deciding which lint/typecheck/test/build commands are appropriate for this Express/Vite/npm project.
---
# Fiddy Verification
Use this workflow from the repo root.
## Before Running Commands
- Read `AGENTS.md`, `PROJECT_INSTRUCTIONS.md`, and any doc related to the touched area.
- Check `git status --short --branch` so user work is not mistaken for Codex changes.
- Do not print real `.env` values. Inspect keys only if environment context is needed.
- Do not run DB migrations unless the user explicitly asked for migration execution.
## Choose Checks
- Docs-only changes: validate affected Markdown links/content where practical, then run JSON/script sanity checks if package files changed.
- Root or frontend script changes: run `npm run lint`, `npm run typecheck`, and the relevant build command.
- Backend behavior changes: run `npm test`; add focused Jest/Supertest coverage for changed API behavior.
- Frontend behavior changes: run `npm run lint`, `npm run typecheck`, and focused Playwright tests when a browser flow changed.
- Dependency or lockfile changes: run `npm run audit` after install/update commands.
- Migration changes: run `npm run db:migrate:stale:check` and `npm run db:migrate:verify` only against the intended external DB environment.
## Default Safe Loop
Run these when dependencies are already installed and the touched files justify them:
```bash
npm run lint
npm run typecheck
npm run audit
npm test
npm run build:backend
npm run build:frontend
```
## Report
- List exact commands run and pass/fail.
- For failures, include the short relevant error and whether it appears caused by the current changes.
- If a check is skipped, state the concrete reason.
- End with unresolved risks and the smallest useful next step.

View File

@ -5,7 +5,7 @@ on:
branches: [ "main" ]
env:
REGISTRY: git.nicosaya.com/nalalangan/grocery-app
REGISTRY: git.nicosaya.com/nalalangan/costco-grocery-list
jobs:
build:
@ -125,3 +125,4 @@ jobs:
curl -d "$MSG" \
https://ntfy.nicosaya.com/gitea

View File

@ -5,7 +5,7 @@ on:
branches: [ "main-new" ]
env:
REGISTRY: git.nicosaya.com/nalalangan/grocery-app
REGISTRY: git.nicosaya.com/nalalangan/costco-grocery-list
# REGISTRY: grocery-app
IMAGE_TAG: main-new
@ -147,3 +147,4 @@ jobs:
curl -d "$MSG" \
https://ntfy.nicosaya.com/gitea

144
AGENTS.md
View File

@ -1,111 +1,57 @@
# AGENTS.md - Fiddy
# AGENTS.md - Fiddy (External DB)
## Authority
- Source of truth: `PROJECT_INSTRUCTIONS.md` in the repo root.
- Bugfix protocol: `DEBUGGING_INSTRUCTIONS.md`.
- Current-stack mapping: `docs/AGENTIC_CONTRACT_MAP.md`.
- If files conflict, follow `PROJECT_INSTRUCTIONS.md`.
- Source of truth: `PROJECT_INSTRUCTIONS.md` (repo root). If conflict, follow it.
- Bugfix protocol: `DEBUGGING_INSTRUCTIONS.md` (repo root).
- Do not implement features unless required to fix the bug.
## Project Overview
- Full-stack grocery list app with household/group behavior, RBAC, image support, and Postgres persistence.
- Backend: Express 5 CommonJS API in `backend/`.
- Frontend: React 19 + Vite SPA in `frontend/`, with partial TypeScript.
- Database: external on-prem Postgres. Do not add or assume a DB container.
- Canonical migrations live in `packages/db/migrations`.
## Non-negotiables
- External DB: `DATABASE_URL` points to on-prem Postgres (NOT a container).
- Dev/Prod share schema via migrations in `packages/db/migrations`.
- No cron/worker jobs. Fixes must work without background tasks.
- Server-side RBAC only. Client checks are UX only.
## Important Directories
- `backend/routes`, `backend/controllers`: route registration and request/response handling.
- `backend/models`, `backend/services`, `backend/middleware`, `backend/db`: DB access, domain logic, auth, RBAC, request IDs, image handling.
- `frontend/src/api`: client API wrappers using the shared Axios instance.
- `frontend/src/context`, `frontend/src/hooks`, `frontend/src/components`, `frontend/src/pages`: UI state and screens.
- `frontend/tests`: Playwright e2e tests.
- `backend/tests`: Jest/Supertest backend tests.
- `scripts`: DB migration helpers.
- `docs`: practical maps, runbooks, architecture notes, and archived implementation history.
## Security / logging (hard rules)
- Never log secrets (passwords/tokens/cookies).
- Never log receipt bytes.
- Never log full invite codes; logs/audit store last4 only.
## Setup
- Install root tools: `npm ci`
- Install backend tools: `npm --prefix backend ci`
- Install frontend tools: `npm --prefix frontend ci`
- Use Node.js 20.19+ or 22.12+ for frontend/Vite commands.
- Configure backend env from `backend/.env.example`; never commit real `.env` values.
- For migration scripts, set `DATABASE_URL` in the shell before running root DB commands.
## Non-regression contracts
- Sessions are DB-backed (`sessions` table) and cookies are HttpOnly.
- Receipt images stored in `receipts` (`bytea`).
- Entries list endpoints must NEVER return receipt bytes.
- API responses must include `request_id`; audit logs must include `request_id`.
- Frontend actions that manipulate database state must show a toast/bubble notification with basic outcome info (action + target + success/failure).
- Progress-type notifications must reuse the existing upload toaster pattern (`UploadQueueContext` + `UploadToaster`).
## Run Commands
- Dev with Docker: `docker compose -f docker-compose.dev.yml up`
- Backend only: `npm run dev:backend`
- Frontend only: `npm run dev:frontend`
- Backend default port: `5000`
- Frontend Docker-mapped port: `3010`; Vite direct default is `5173` unless overridden.
## Architecture boundaries (follow existing patterns; do not invent)
1) API routes: `app/api/**/route.ts`
- Thin: parse/validate + call service, return JSON.
2) Server services: `lib/server/*`
- Own DB + authz. Must include `import "server-only";`.
3) Client wrappers: `lib/client/*`
- Typed fetch + error normalization; always send credentials.
4) Hooks: `hooks/use-*.ts`
- Primary UI-facing API layer; components avoid raw `fetch()`.
## Verification Commands
- Backend unit/API tests: `npm test`
- Frontend lint: `npm run lint`
- Frontend typecheck: `npm run typecheck`
- Vulnerability audit: `npm run audit`
- Backend build: `npm run build:backend`
- Frontend build: `npm run build:frontend`
- Full build: `npm run build`
- E2E tests: `npm run test:e2e`
- Migration status: `npm run db:migrate:status`
- Migration verification: `npm run db:migrate:verify`
## Next.js dynamic route params (required)
- In `app/api/**/[param]/route.ts`, treat `context.params` as async:
- `const { id } = await context.params;`
## Environment Notes
- `backend/.env` is used by the backend and Docker dev service.
- `frontend/.env` may define `VITE_API_URL` and `VITE_ALLOWED_HOSTS`.
- Do not print, log, or commit secrets, tokens, cookies, DB URLs, receipt bytes, or full invite codes.
- Logs/audit entries for invite codes may include last4 only.
## Working style
- Scan repo first; do not guess file names or patterns.
- Make the smallest change that resolves the issue.
- Religiously commit work in small, verified slices; prefer frequent checkpoint commits over large end-state batches.
- Follow the commit discipline in `PROJECT_INSTRUCTIONS.md` for every slice, including Conventional Commit messages and related-file-only scope.
- Keep touched files free of TS warnings and lint errors.
- Add/update tests when API behavior changes (include negative cases).
- Keep text encoding clean (no mojibake).
## Coding Conventions
- Preserve the current stack; do not migrate to Next.js or another framework.
- Keep Express routes/controllers thin; put DB-heavy work in models/services and authz in backend layers.
- Keep frontend network calls in `frontend/src/api` wrappers and UI state in context/hooks.
- Always send credentials through the shared Axios client when touching authenticated frontend API calls.
- Enforce RBAC server-side; client guards are UX only.
- Frontend DB-mutating actions must show toast/bubble outcome notifications.
- Progress notifications must reuse `UploadQueueContext` and `UploadToaster`.
- Keep encoding clean; do not introduce mojibake.
## Dependency Rules
- npm is the package manager; do not introduce pnpm, yarn, bun, or another build tool.
- Do not add production dependencies unless the task clearly requires it and the repo has no practical existing option.
- Do not add cron, workers, polling daemons, or background job frameworks.
## Testing Expectations
- Add or update tests when API behavior changes.
- Include negative cases for authz, membership, and invalid input where applicable.
- For UI behavior changes, prefer focused Playwright tests.
- Run the narrowest relevant checks first, then broader checks when risk warrants it.
## Done Means
- Behavior is preserved unless the task explicitly requires a change.
- Relevant tests/lint/typecheck/build commands were run or the reason they could not run is documented.
- Touched files have no known TS/lint errors.
- Migrations are in `packages/db/migrations` when schema changes are required.
- Documentation is updated for changed commands, contracts, or workflows.
## Codex Must Not
- Do not read or expose real `.env` values; inspect variable names only when needed.
- Do not touch production data or run DB migrations without explicit operator intent.
- Do not log secrets, receipt bytes, or full invite codes.
- Do not delete user work or generated artifacts unless explicitly asked.
- Do not make broad refactors, file moves, or framework changes for cleanup alone.
## Deeper Docs
- `docs/PROJECT_MAP.md`: quick repo orientation.
- `docs/DEVELOPMENT.md`: setup, run, verify, and troubleshooting.
- `docs/DB_MIGRATION_WORKFLOW.md`: migration runbook.
- `docs/PLANS.md`: template for multi-step work.
- `.agents/skills/fiddy-verify/SKILL.md`: repo-specific verification workflow for Codex.
## Response Icon Legend
## Response icon legend
Use the same status icons defined in `PROJECT_INSTRUCTIONS.md` section "Agent Response Legend (required)":
- `🔄` in progress
- `✅` completed
- `🧪` verification/test result
- `📄` documentation update
- `🗄️` database or migration change
- `🚀` deploy/release step
- `⚠️` risk, blocker, or manual operator action needed
- `❌` failed command or unsuccessful attempt
- `` informational context
- `🧭` recommendation or next-step option
- `⚠️` risk/blocker/manual action
- `❌` failure
- `🧭` recommendation/next step

View File

@ -2,8 +2,6 @@
A full-stack web application for managing grocery shopping lists with role-based access control, image support, and intelligent item classification.
> Current maintainer notes: `PROJECT_INSTRUCTIONS.md` is the source of truth for project constraints. For current setup, run, and verification commands, start with `docs/DEVELOPMENT.md` and `docs/PROJECT_MAP.md`; some older sections below are historical and should be checked against current code before changing behavior.
![License](https://img.shields.io/badge/license-MIT-blue.svg)
![Node](https://img.shields.io/badge/node-20.x-green.svg)
![React](https://img.shields.io/badge/react-19.2.0-blue.svg)
@ -326,8 +324,8 @@ router.post("/add",
1. **Clone the repository**
```bash
git clone https://git.nicosaya.com/nalalangan/grocery-app.git
cd grocery-app
git clone https://github.com/your-org/costco-grocery-list.git
cd costco-grocery-list
```
2. **Configure environment variables**
@ -423,7 +421,7 @@ Authorization: Bearer <your_jwt_token>
## 📁 Project Structure
```
grocery-app/
costco-grocery-list/
├── .gitea/
│ └── workflows/
│ └── deploy.yml # CI/CD pipeline configuration
@ -749,7 +747,7 @@ This project is licensed under the MIT License - see the LICENSE file for detail
## 👤 Author
**Nico Saya**
- Repository: [git.nicosaya.com/nalalangan/grocery-app](https://git.nicosaya.com/nalalangan/grocery-app)
- Repository: [git.nicosaya.com/nalalangan/costco-grocery-list](https://git.nicosaya.com/nalalangan/costco-grocery-list)
---

View File

@ -1,62 +0,0 @@
"use strict";
const fs = require("fs");
const path = require("path");
const rootDir = __dirname;
const distDir = path.join(rootDir, "dist");
const directoriesToCopy = [
"config",
"constants",
"controllers",
"db",
"middleware",
"models",
"routes",
"services",
"utils",
"public",
];
const filesToCopy = ["app.js", "server.js", "package.json", "package-lock.json"];
function copyFile(sourcePath, targetPath) {
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
fs.copyFileSync(sourcePath, targetPath);
}
function copyDirectory(sourceDir, targetDir) {
if (!fs.existsSync(sourceDir)) {
return;
}
for (const entry of fs.readdirSync(sourceDir, { withFileTypes: true })) {
const sourcePath = path.join(sourceDir, entry.name);
const targetPath = path.join(targetDir, entry.name);
if (entry.isDirectory()) {
copyDirectory(sourcePath, targetPath);
continue;
}
if (entry.isFile()) {
copyFile(sourcePath, targetPath);
}
}
}
fs.mkdirSync(distDir, { recursive: true });
for (const directory of directoriesToCopy) {
copyDirectory(path.join(rootDir, directory), path.join(distDir, directory));
}
for (const file of filesToCopy) {
const sourcePath = path.join(rootDir, file);
if (fs.existsSync(sourcePath)) {
copyFile(sourcePath, path.join(distDir, file));
}
}
console.log(`Backend build copied runtime files to ${path.relative(rootDir, distDir)}`);

2208
backend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,12 +10,13 @@
"sharp": "^0.34.5"
},
"devDependencies": {
"cpx": "^1.5.0",
"esbuild": "^0.25.5",
"nodemon": "^3.1.11",
"rimraf": "^6.0.1"
},
"scripts": {
"build": "rimraf dist && node build.js",
"build": "rimraf dist && node build.js && cpx \"public/**/*\" dist/public",
"dev": "nodemon server.js"
}
}

View File

@ -1,6 +1,6 @@
services:
backend:
image: git.nicosaya.com/nalalangan/grocery-app/backend:main-new
image: git.nicosaya.com/nalalangan/costco-grocery-list/backend:main-new
# image: grocery-app/backend:main-new
restart: always
env_file:
@ -9,7 +9,7 @@ services:
- "5001:5000"
frontend:
image: git.nicosaya.com/nalalangan/grocery-app/frontend:main-new
image: git.nicosaya.com/nalalangan/costco-grocery-list/frontend:main-new
# image: grocery-app/frontend:main-new
restart: always
env_file:

View File

@ -1,6 +1,6 @@
services:
backend:
image: git.nicosaya.com/nalalangan/grocery-app/backend:latest
image: git.nicosaya.com/nalalangan/costco-grocery-list/backend:latest
restart: always
env_file:
- ./backend.env
@ -8,7 +8,7 @@ services:
- "5000:5000"
frontend:
image: git.nicosaya.com/nalalangan/grocery-app/frontend:latest
image: git.nicosaya.com/nalalangan/costco-grocery-list/frontend:latest
restart: always
env_file:
- ./frontend.env

View File

@ -1,95 +0,0 @@
# Development
Use this as the practical setup and verification guide. `PROJECT_INSTRUCTIONS.md` remains the source of truth for constraints.
## Prerequisites
- Node.js 20.19+ or 22.12+ for the current Vite toolchain.
- npm.
- PostgreSQL client tools if running migration scripts (`psql` must be on `PATH`).
- Access to the external Postgres database through `DATABASE_URL` or backend DB variables.
- Docker is optional for local app containers.
## Install
Run installs separately because this repo does not define npm workspaces.
```bash
npm ci
npm --prefix backend ci
npm --prefix frontend ci
```
## Environment
- Copy `backend/.env.example` to `backend/.env` for backend runtime configuration.
- Copy `frontend/.env.example` to `frontend/.env` if the frontend needs non-default API or host settings.
- Do not commit real `.env` files.
- Root DB migration scripts read `DATABASE_URL` from the shell environment; they do not load `backend/.env` automatically.
Important variables:
| Variable | Used by | Notes |
| --- | --- | --- |
| `DATABASE_URL` | backend, root migration scripts | Preferred external Postgres connection string. |
| `DB_USER`, `DB_PASS`, `DB_HOST`, `DB_PORT`, `DB_NAME` | backend fallback | Used only when `DATABASE_URL` is absent. |
| `JWT_SECRET` | backend auth | Required for token/session-compatible auth paths. |
| `ALLOWED_ORIGINS` | backend CORS | Comma-separated allowed frontend origins. |
| `SESSION_COOKIE_NAME`, `SESSION_TTL_DAYS` | backend cookies | Optional; defaults are defined in code. |
| `VITE_API_URL` | frontend | Defaults to `http://localhost:5000`. |
| `VITE_ALLOWED_HOSTS` | Vite dev server | Comma-separated host allowlist. |
| `PLAYWRIGHT_BASE_URL` | Playwright | Defaults to `http://localhost:3010`. |
## Run Locally
Docker dev stack:
```bash
docker compose -f docker-compose.dev.yml up
```
Separate terminals:
```bash
npm run dev:backend
npm run dev:frontend
```
Default local endpoints:
- Backend: `http://localhost:5000`
- Frontend through Docker compose port mapping: `http://localhost:3010`
- Frontend direct Vite default: `http://localhost:5173`
## Verification Commands
Root entry points:
```bash
npm test
npm run lint
npm run typecheck
npm run audit
npm run build:backend
npm run build:frontend
npm run build
npm run test:e2e
```
Migration checks:
```bash
npm run db:migrate:status
npm run db:migrate:verify
npm run db:migrate:stale:check
```
Do not run `npm run db:migrate` against a shared or production database unless that is the explicit operator task.
## Common Troubleshooting
- `DATABASE_URL is required`: export/set `DATABASE_URL` in the shell before root migration commands.
- `psql executable was not found in PATH`: install PostgreSQL client tools.
- Frontend cannot reach backend: confirm `VITE_API_URL`, backend port `5000`, and backend `ALLOWED_ORIGINS`.
- Playwright starts the frontend but API calls fail: start the backend separately or use the Docker dev stack.
- CORS blocked origin: add the exact frontend origin to `ALLOWED_ORIGINS`.
## Before Finishing Work
- Re-read `AGENTS.md` and any relevant deeper doc.
- Run the smallest useful checks first.
- For API behavior changes, add/update Jest tests with negative cases.
- For user-facing UI behavior changes, add/update focused Playwright coverage.
- Summarize any command that failed, whether it appears pre-existing, and the unresolved risk.

View File

@ -1,36 +0,0 @@
# Planning Template
Use this template for multi-step features, refactors, risky bugfixes, or DB work. Keep plans short and update them as evidence changes.
## Goal
- What user-visible or operator-visible outcome should be true?
## Context
- Relevant files, routes, data tables, docs, tests, and prior decisions.
- Current behavior and desired behavior.
## Constraints
- External DB only; migrations go in `packages/db/migrations`.
- No cron, workers, or background jobs.
- RBAC must be enforced server-side.
- No secrets, receipt bytes, or full invite codes in logs.
- Preserve current behavior outside the target area.
## Milestones
1. Recon and evidence.
2. Minimal design.
3. Implementation slice.
4. Tests and verification.
5. Documentation update.
## Validation
- Commands to run.
- Manual checks needed.
- Negative cases to cover.
## Rollback
- Files or migrations that would need reverting.
- Data or operator action needed, if any.
## Open Questions
- Only questions that materially affect architecture, runtime behavior, public APIs, data storage, security, deployment, package manager, or dependency footprint.

View File

@ -1,61 +0,0 @@
# Project Map
This is the fast orientation map for Fiddy.
## Stack
- Backend: Express 5 on Node 20, CommonJS modules, PostgreSQL via `pg`.
- Frontend: React 19 + Vite, mostly JSX with partial TypeScript.
- Package manager: npm.
- Database: external on-prem Postgres. Migrations are canonical in `packages/db/migrations`.
## Root
- `PROJECT_INSTRUCTIONS.md`: source-of-truth constraints and delivery contract.
- `AGENTS.md`: concise Codex/human working guide.
- `DEBUGGING_INSTRUCTIONS.md`: required bugfix workflow.
- `package.json`: root DB, test, lint, typecheck, build, and e2e command entry points.
- `docker-compose.dev.yml`: local app containers with backend env loaded from `backend/.env`.
- `.gitea/workflows`: deploy workflows for `main` and `main-new`.
- `.github/copilot-instructions.md`: compatibility shim that points back to root instructions.
## Backend
- `backend/server.js`: starts the Express app.
- `backend/app.js`: middleware, CORS, route mounting, and error handling.
- `backend/build.js`: copies runtime backend files into `backend/dist` for the existing backend build script.
- `backend/routes`: Express routers.
- `backend/controllers`: request handlers.
- `backend/models`: database query modules.
- `backend/services`: domain service logic where present.
- `backend/middleware`: auth, optional auth, RBAC, request IDs, rate limiting, and image upload processing.
- `backend/utils`: logging, HTTP response helpers, cookies, redaction.
- `backend/tests`: Jest/Supertest tests run from the root Jest config.
- `backend/migrations`: legacy/reference SQL only; do not add new canonical migrations here.
## Frontend
- `frontend/src/main.tsx`: browser entry point.
- `frontend/src/App.jsx`: top-level routing and providers.
- `frontend/src/config.ts`: API base URL.
- `frontend/src/api`: API wrappers and shared Axios client.
- `frontend/src/context`: app state providers.
- `frontend/src/hooks`: reusable UI-facing hooks.
- `frontend/src/pages`: route-level pages.
- `frontend/src/components`: shared and domain UI components.
- `frontend/src/styles`: global, page, component, and theme CSS.
- `frontend/tests`: Playwright e2e tests.
## Database and Scripts
- `packages/db/migrations`: canonical SQL migration set.
- `packages/db/migrations/stale-files.json`: known skipped/stale migration filenames.
- `scripts/db-migrate*.js`: migration apply/status/verify/new/stale helpers.
- `docs/DB_MIGRATION_WORKFLOW.md`: operator runbook for DB changes.
## Documentation
- `docs/DEVELOPMENT.md`: setup, run, verification, and troubleshooting.
- `docs/AGENTIC_CONTRACT_MAP.md`: maps Next.js-oriented architecture language to the current Express/Vite stack.
- `docs/PLANS.md`: lightweight template for multi-step work.
- `docs/architecture`, `docs/features`, `docs/guides`, `docs/migration`: deeper reference docs.
- `docs/archive`: historical implementation notes; useful context, not necessarily current.
## Known Maintainability Hotspots
- `frontend/src/pages/GroceryList.jsx` is large and should be split only during focused UI work.
- `frontend/src/components/manage/ManageHousehold.jsx`, `backend/services/group-invites.service.js`, and `backend/models/group-invites.model.js` are also large enough to review carefully before editing.
- Some older README/guides may describe pre-session or pre-household behavior; verify against current code and root instructions before relying on them.

View File

@ -1,41 +1,77 @@
# Documentation Index
This directory contains practical project documentation. Root-level rules still take precedence:
This directory contains all project documentation organized by category.
1. `../PROJECT_INSTRUCTIONS.md`
2. `../DEBUGGING_INSTRUCTIONS.md` for bugfix work
3. `../AGENTS.md` for Codex and human workflow shortcuts
## 📁 Directory Structure
## Start Here
- `PROJECT_MAP.md`: quick repo structure and ownership map.
- `DEVELOPMENT.md`: install, run, test, lint, build, and troubleshooting.
- `DB_MIGRATION_WORKFLOW.md`: external Postgres migration runbook.
- `AGENTIC_CONTRACT_MAP.md`: maps source-of-truth architecture language to the current Express/Vite stack.
- `PLANS.md`: lightweight template for multi-step work.
### `/architecture` - System Design & Structure
- **[component-structure.md](architecture/component-structure.md)** - Frontend component organization and patterns
- **[multi-household-architecture-plan.md](architecture/multi-household-architecture-plan.md)** - Multi-household system architecture design
## Architecture
- `architecture/component-structure.md`: frontend component organization and patterns.
- `architecture/multi-household-architecture-plan.md`: multi-household system planning notes.
### `/features` - Feature Implementation Details
- **[classification-implementation.md](features/classification-implementation.md)** - Item classification system (zones, types, groups)
- **[image-storage-implementation.md](features/image-storage-implementation.md)** - Image storage and handling (bytea, MIME types)
## Features
- `features/classification-implementation.md`: item classification notes.
- `features/image-storage-implementation.md`: image storage and handling notes.
### `/guides` - How-To & Reference Guides
- **[api-documentation.md](guides/api-documentation.md)** - REST API endpoints and usage
- **[frontend-readme.md](guides/frontend-readme.md)** - Frontend development guide
- **[MOBILE_RESPONSIVE_AUDIT.md](guides/MOBILE_RESPONSIVE_AUDIT.md)** - Mobile-first design guidelines and audit checklist
- **[setup-checklist.md](guides/setup-checklist.md)** - Development environment setup steps
## Guides
- `guides/api-documentation.md`: REST API reference. Verify against current code before changing APIs.
- `guides/frontend-readme.md`: frontend development notes.
- `guides/MOBILE_RESPONSIVE_AUDIT.md`: mobile design and audit checklist.
- `guides/setup-checklist.md`: older setup checklist; prefer `DEVELOPMENT.md` for current commands.
### `/migration` - Database Migrations & Updates
- **[MIGRATION_GUIDE.md](migration/MIGRATION_GUIDE.md)** - Multi-household migration instructions (also in `backend/migrations/`)
- **[POST_MIGRATION_UPDATES.md](migration/POST_MIGRATION_UPDATES.md)** - Required updates after migration
## Migration
- `migration/MIGRATION_GUIDE.md`: historical multi-household migration instructions.
- `migration/POST_MIGRATION_UPDATES.md`: historical post-migration notes.
### `/archive` - Completed Implementation Records
Historical documentation of completed features. Useful for reference but not actively maintained.
## Archive
Files in `archive/` are historical implementation records. They are useful for context, but they are not guaranteed to describe current behavior.
- **[ACCOUNT_MANAGEMENT_IMPLEMENTATION.md](archive/ACCOUNT_MANAGEMENT_IMPLEMENTATION.md)** - Phase 4: Display name and password change
- **[code-cleanup-guide.md](archive/code-cleanup-guide.md)** - Code cleanup checklist (completed)
- **[HOUSEHOLD_MANAGEMENT_IMPLEMENTATION.md](archive/HOUSEHOLD_MANAGEMENT_IMPLEMENTATION.md)** - Household management UI implementation
- **[IMPLEMENTATION_STATUS.md](archive/IMPLEMENTATION_STATUS.md)** - Multi-household migration sprint status
- **[settings-dark-mode.md](archive/settings-dark-mode.md)** - Dark mode implementation notes
- **[TEST_SUITE_README.md](archive/TEST_SUITE_README.md)** - Testing infrastructure documentation
## Documentation Rules
- Keep docs concise and linked to real files or commands.
- Prefer updating `PROJECT_MAP.md` and `DEVELOPMENT.md` before adding new top-level docs.
- Move completed implementation narratives to `archive/` when they are no longer active runbooks.
- Keep text encoding clean.
---
## 📄 Root-Level Documentation
These files remain at the project root for easy access:
- **[../README.md](../README.md)** - Project overview and quick start
- **[../PROJECT_INSTRUCTIONS.md](../PROJECT_INSTRUCTIONS.md)** - Canonical project constraints and delivery contract
- **[../AGENTS.md](../AGENTS.md)** - Agent behavior and guardrails
- **[../DEBUGGING_INSTRUCTIONS.md](../DEBUGGING_INSTRUCTIONS.md)** - Required bugfix workflow
- **[../.github/copilot-instructions.md](../.github/copilot-instructions.md)** - Copilot compatibility shim to root instructions
---
## 🔍 Quick Reference
**Setting up the project?** → Start with [setup-checklist.md](guides/setup-checklist.md)
**Understanding the API?** → See [api-documentation.md](guides/api-documentation.md)
**Working on mobile UI?** → Check [MOBILE_RESPONSIVE_AUDIT.md](guides/MOBILE_RESPONSIVE_AUDIT.md)
**Need architecture context?** → Read [AGENTIC_CONTRACT_MAP.md](AGENTIC_CONTRACT_MAP.md) and [../PROJECT_INSTRUCTIONS.md](../PROJECT_INSTRUCTIONS.md)
**Running migrations?** → Follow [DB_MIGRATION_WORKFLOW.md](DB_MIGRATION_WORKFLOW.md)
---
## 📝 Contributing to Documentation
When adding new documentation:
1. **Guides** (`/guides`) - General how-to, setup, reference
2. **Features** (`/features`) - Specific feature implementation details
3. **Architecture** (`/architecture`) - System design, patterns, structure
4. **Migration** (`/migration`) - Database migrations and upgrade guides
5. **Archive** (`/archive`) - Completed implementation records (for reference only)
Keep documentation:
- ✅ Up-to-date with code changes
- ✅ Concise and scannable
- ✅ Linked to relevant files (use relative paths)
- ✅ Organized by category

View File

@ -1,2 +0,0 @@
VITE_API_URL=http://localhost:5000
VITE_ALLOWED_HOSTS=localhost,127.0.0.1

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,6 @@
"type": "module",
"scripts": {
"dev": "vite",
"typecheck": "tsc -b",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview",
@ -20,8 +19,8 @@
"react-router-dom": "^7.9.6"
},
"devDependencies": {
"@playwright/test": "^1.52.0",
"@eslint/js": "^9.39.1",
"@playwright/test": "^1.58.2",
"@types/node": "^24.10.0",
"@types/react": "^19.2.5",
"@types/react-dom": "^19.2.2",

View File

@ -170,7 +170,7 @@ export default function ConfirmSlideModal({
onPointerCancel={handlePointerCancel}
aria-label="Slide to confirm"
>
&gt;
>
</button>
</div>
</div>

View File

@ -150,8 +150,8 @@ test("manage stores opens a modal to edit and delete household store items", asy
const managerModal = page.locator(".store-items-modal");
await expect(managerModal).toBeVisible();
await expect(managerModal.getByText("milk", { exact: true })).toBeVisible();
await expect(managerModal.getByText("apples", { exact: true })).toBeVisible();
await expect(managerModal.getByText("milk")).toBeVisible();
await expect(managerModal.getByText("apples")).toBeVisible();
await managerModal.locator(".store-items-table-row").filter({ hasText: "apples" }).getByRole("button", { name: "Edit Settings" }).click();
const editorModal = page.locator(".available-item-editor-modal");

View File

@ -271,9 +271,7 @@ test("add-details modal validates with toasts and persists classification detail
const yogurtRow = page.locator(".glist-li").filter({ hasText: "yogurt" });
await expect(yogurtRow).toBeVisible();
await expect(
page.locator(".action-toast.action-toast-success").filter({ hasText: "Added item" })
).toContainText("Added item");
await expect(page.locator(".action-toast.action-toast-success")).toContainText("Added item");
await openEditModal(yogurtRow, page);
@ -304,9 +302,7 @@ test("edit modal supports zone-only updates and shows API error toasts", async (
await editModal.locator(".edit-modal-select").nth(1).selectOption("Checkout Area");
await editModal.getByRole("button", { name: "Save Changes" }).click();
await expect(
page.locator(".action-toast.action-toast-success").filter({ hasText: "Updated item" })
).toContainText("Updated item");
await expect(page.locator(".action-toast.action-toast-success")).toContainText("Updated item");
await expect(editModal).toBeHidden();
await openEditModal(yogurtRow, page);

View File

@ -39,14 +39,14 @@ test("new users with no households see create and join actions instead of a load
await expect(page.getByRole("button", { name: "Create or Join Household" })).toBeVisible();
await expect(page.getByRole("heading", { name: "No household yet" })).toBeVisible();
await expect(page.getByRole("button", { name: "Create Household", exact: true })).toBeVisible();
await expect(page.getByRole("button", { name: "Join Household", exact: true })).toBeVisible();
await expect(page.getByRole("button", { name: "Create Household" })).toBeVisible();
await expect(page.getByRole("button", { name: "Join Household" })).toBeVisible();
await page.getByRole("button", { name: "Join Household", exact: true }).click();
await page.getByRole("button", { name: "Join Household" }).click();
await expect(page.getByLabel("Invite Code or Link")).toBeVisible();
await page.getByRole("button", { name: "Close household dialog" }).click();
await page.getByRole("button", { name: "Create Household", exact: true }).click();
await page.getByRole("button", { name: "Create Household" }).click();
await expect(page.getByLabel("Household Name")).toBeVisible();
await page.getByRole("button", { name: "Close household dialog" }).click();
@ -54,6 +54,6 @@ test("new users with no households see create and join actions instead of a load
await expect(page.getByRole("heading", { name: "Manage" })).toBeVisible();
await expect(page.getByRole("heading", { name: "No household yet" })).toBeVisible();
await expect(page.getByRole("button", { name: "Create Household", exact: true })).toBeVisible();
await expect(page.getByRole("button", { name: "Join Household", exact: true })).toBeVisible();
await expect(page.getByRole("button", { name: "Create Household" })).toBeVisible();
await expect(page.getByRole("button", { name: "Join Household" })).toBeVisible();
});

View File

@ -71,7 +71,7 @@ test("join household modal accepts invite links but rejects legacy invite codes"
});
await page.goto("/manage");
await page.getByRole("button", { name: "Join Household", exact: true }).click();
await page.getByRole("button", { name: "Join Household" }).click();
await page.getByLabel("Invite Link").fill("HABC123");
await page.getByRole("button", { name: "Open Invite" }).click();

View File

@ -38,7 +38,7 @@ test("login failure shows inline error and error toast", async ({ page }) => {
await page.getByPlaceholder("Password").fill("bad-password");
await page.getByRole("button", { name: "Login" }).click();
await expect(page.getByText("Invalid credentials", { exact: true })).toBeVisible();
await expect(page.getByText("Invalid credentials")).toBeVisible();
await expect(page.locator(".action-toast.action-toast-error")).toContainText("Login failed");
await expect(page.locator(".action-toast.action-toast-error")).toContainText("Invalid credentials");
});

48
package-lock.json generated
View File

@ -1,10 +1,10 @@
{
"name": "grocery-app",
"name": "Costco-Grocery-List",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "grocery-app",
"name": "Costco-Grocery-List",
"devDependencies": {
"cross-env": "^10.1.0",
"jest": "^30.2.0",
@ -1544,9 +1544,9 @@
}
},
"node_modules/brace-expansion": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz",
"integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0"
@ -3130,9 +3130,9 @@
}
},
"node_modules/jest-util/node_modules/picomatch": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"dev": true,
"engines": {
"node": ">=12"
@ -3421,12 +3421,12 @@
}
},
"node_modules/minimatch": {
"version": "9.0.9",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz",
"integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==",
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.2"
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@ -3671,9 +3671,9 @@
"dev": true
},
"node_modules/picomatch": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"engines": {
"node": ">=8.6"
@ -3746,9 +3746,9 @@
]
},
"node_modules/qs": {
"version": "6.15.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz",
"integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==",
"version": "6.14.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.1.tgz",
"integrity": "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==",
"dev": true,
"dependencies": {
"side-channel": "^1.1.0"
@ -4191,9 +4191,9 @@
}
},
"node_modules/test-exclude/node_modules/brace-expansion": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz",
"integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==",
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
@ -4222,9 +4222,9 @@
}
},
"node_modules/test-exclude/node_modules/minimatch": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz",
"integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==",
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"

View File

@ -1,18 +1,5 @@
{
"name": "grocery-app",
"private": true,
"scripts": {
"dev:backend": "npm --prefix backend run dev",
"dev:frontend": "npm --prefix frontend run dev",
"build": "npm run build:backend && npm run build:frontend",
"build:backend": "npm --prefix backend run build",
"build:frontend": "npm --prefix frontend run build",
"lint": "npm --prefix frontend run lint",
"typecheck": "npm --prefix frontend run typecheck",
"audit": "npm run audit:root && npm run audit:backend && npm run audit:frontend",
"audit:root": "npm audit",
"audit:backend": "npm --prefix backend audit",
"audit:frontend": "npm --prefix frontend audit",
"db:migrate": "node scripts/db-migrate.js",
"db:migrate:status": "node scripts/db-migrate-status.js",
"db:migrate:verify": "node scripts/db-migrate-verify.js",