adamp 7068ea354e Fix bugs, harden validation, and improve robustness
P0 fixes:
- Fix OrderDetail product change overwriting product_id due to React
  state batching (single setItems call now updates both fields)
- Validate all :id route params via parseId helper; return 400 for
  invalid IDs instead of passing raw strings to SQLite
- Product/customer delete now checks for references first, returns
  409 Conflict instead of letting FK constraint produce 500

P1 fixes:
- Disallow quantity_on_hand in product PUT so all stock changes go
  through PATCH /stock (preserves audit trail)
- Add global Express error handler and unhandledRejection listener

P2 fixes:
- Validate report date params (YYYY-MM-DD format) and stock-history
  limit (positive integer, capped at 1000)
- Add jsonSafe() helper to api.js for safe 204 handling
- OrderNew setSubmitting now runs in finally block
- Login shows specific message for 429 rate limit, generic message
  for other auth failures

P3 fixes:
- Replace brittle try/catch ALTER TABLE with schema_version migration
  table and versioned migrations
- Fix OrderDetail useEffect missing dependency (useCallback + [load])

Also: expanded README with full production deployment instructions
(PM2, nginx, backups)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-09 21:35:53 -06:00
2026-02-09 17:48:42 -06:00
2026-02-09 17:48:42 -06:00
2026-02-09 17:48:42 -06:00
2026-02-09 17:48:42 -06:00
2026-02-09 17:48:42 -06:00

Girl Scout Cookie Tracker

A self-hosted web app for tracking cookie inventory and customers for a single troop. Works on desktop and mobile.

Features

  • Inventory: Add cookie products (name, price, quantity, low-stock threshold). Adjust stock (restock or deduct). Low-stock highlighting.
  • Customers: Store name, phone, email, address, notes. Search by name, email, or phone.
  • Orders: Create orders with customer (or walk-in), line items (product + quantity), status (pending, paid, delivered), payment method and amount paid. Inventory is deducted automatically. Edit or delete orders (stock is restored on delete). Balance due tracking.
  • Reports: Sales by product, top customers, revenue over time, order status breakdown, and inventory summary. Filterable by date range (all time, this week, this month, custom).
  • Stock Audit Trail: Every stock change (restock, order create/update/delete) is logged with reason and reference.
  • Dashboard: Summary counts, low-stock list, recent orders.

Requirements

  • Node.js 18+
  • npm

Setup

  1. Clone or download this repo.

  2. Install dependencies:

    npm install
    cd client && npm install && cd ..
    
  3. Optional: copy .env.example to .env and set:

    • PORT — API port (default 3002)
    • DATABASE_PATH — path to SQLite file (default ./data/cookies.db)
    • Authentication (optional): Set APP_PASSWORD to require a password to log in. Set APP_SECRET to a long random string (used to sign session cookies). If APP_PASSWORD is not set, the app runs without login; if set, users must enter the password to access the app. Use "Log out" in the nav to sign out.

Development

Run the API server and the Vite dev server together:

npm run dev

Use the frontend URL in your browser. The database file is created automatically on first request.

Production build and run

  1. Build the client:

    npm run build
    
  2. Run the server in production mode (serves the built client and API):

    npm start
    

    Or set NODE_ENV=production and run node server/index.js. The app will serve static files from client/dist and handle the SPA fallback.

  3. Open http://localhost:3002 (or your PORT).

Deployment (self-hosted)

Prerequisites

  • A Linux server with Node.js 18+ and npm installed
  • Git access to the repository
  • (Recommended) PM2 for process management: npm install -g pm2
  • (Recommended) A reverse proxy (e.g. nginx) for HTTPS

Initial setup

  1. Clone the repo to your server (e.g. /opt/cookie-tracker):

    git clone https://your-git-host/your-repo/cookie-tracker.git /opt/cookie-tracker
    cd /opt/cookie-tracker
    
  2. Install dependencies:

    npm install
    cd client && npm install && cd ..
    
  3. Create a .env file with production settings:

    cp .env.example .env
    

    Edit .env and set:

    • APP_PASSWORD — required in production so only authorized users can access the app
    • APP_SECRET — a long random string for signing session cookies (generate with openssl rand -hex 32)
    • DATABASE_PATH — path to a persistent location (e.g. /var/data/cookies.db) so the database survives restarts
    • PORT — API port (default 3002)
  4. Build the client and start with PM2:

    npm run build
    pm2 start npm --name cookie-tracker -- start
    pm2 save
    pm2 startup  # follow the instructions to enable auto-start on boot
    

Deploying updates

After pushing changes to the repository:

cd /opt/cookie-tracker
git pull origin master
npm run build
pm2 restart cookie-tracker

Reverse proxy (nginx)

If serving over HTTPS, add a site config like:

server {
    listen 443 ssl;
    server_name cookies.example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://127.0.0.1:3002;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Session cookies are httpOnly and Secure when served over HTTPS in production.

Backups

Back up the SQLite file regularly (e.g. via cron):

# Add to crontab: daily backup at 2am
0 2 * * * cp /var/data/cookies.db /var/backups/cookies-$(date +\%Y\%m\%d).db

Project structure

  • server/ — Express API and SQLite (products, customers, orders, dashboard).
  • client/ — Vite + React SPA (Dashboard, Inventory, Customers, Orders, New order, Order detail).
  • data/ — Created at runtime; contains cookies.db by default.
Description
Girl Scout Cookie tracking application
Readme 253 KiB
Languages
JavaScript 93.5%
CSS 6.2%
HTML 0.3%