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>
161 lines
4.7 KiB
Markdown
161 lines
4.7 KiB
Markdown
# 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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
npm run dev
|
|
```
|
|
|
|
- API: http://localhost:3002
|
|
- Frontend: http://localhost:5173 (proxies `/api` to the server)
|
|
|
|
Use the frontend URL in your browser. The database file is created automatically on first request.
|
|
|
|
## Production build and run
|
|
|
|
1. Build the client:
|
|
|
|
```bash
|
|
npm run build
|
|
```
|
|
|
|
2. Run the server in production mode (serves the built client and API):
|
|
|
|
```bash
|
|
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`):
|
|
|
|
```bash
|
|
git clone https://your-git-host/your-repo/cookie-tracker.git /opt/cookie-tracker
|
|
cd /opt/cookie-tracker
|
|
```
|
|
|
|
2. Install dependencies:
|
|
|
|
```bash
|
|
npm install
|
|
cd client && npm install && cd ..
|
|
```
|
|
|
|
3. Create a `.env` file with production settings:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```nginx
|
|
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):
|
|
|
|
```bash
|
|
# 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.
|