Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f464fd2
fix: security/a11y wip
paccloud Dec 17, 2025
ed1cdf8
feat: add maritime branding foundation (colors, fonts, Tailwind config)
paccloud Mar 28, 2026
8fabd44
feat: maritime branding redesign + calculator as homepage + about pag…
paccloud Mar 28, 2026
3bb5f1c
feat: add vite-plugin-pwa with manifest and service worker config
paccloud Mar 28, 2026
3c84c6c
feat: add PWA icons and meta tags
paccloud Mar 28, 2026
c56b6e6
feat: add PWA install prompt banner
paccloud Mar 28, 2026
883d957
feat: add IndexedDB local storage layer with idb-keyval
paccloud Mar 28, 2026
a2dfbf3
feat: add DataContext for local-first data management
paccloud Mar 28, 2026
316da7f
feat: refactor Calculator and DataManagement to use local-first DataC…
paccloud Mar 28, 2026
1d6ec36
feat: add sync engine for background data synchronization
paccloud Mar 28, 2026
b716ec9
feat: add sync triggers and status indicator
paccloud Mar 28, 2026
7ee749f
fix: add iOS Safari fallback for PWA install prompt
paccloud Mar 28, 2026
d974baf
refactor: move creator bio to bottom of About page, add links
paccloud Mar 28, 2026
0af42c9
chore: update gitignore, docs, and auth context refactor
paccloud Mar 28, 2026
ac0172d
docs: add PRD, agents guide, security notice, and issue list
paccloud Mar 28, 2026
021950b
feat: calculator UX enhancements + code cleanup
paccloud Mar 28, 2026
f8a6b27
feat: redesign favicon with fish + dollar sign tail and FC branding
paccloud Mar 28, 2026
b676e59
merge: resolve conflicts merging origin/main into pr-11
paccloud Mar 28, 2026
08274d5
docs: add auth migration roadmap (Stack Auth → Better Auth + Cloudflare)
paccloud Mar 28, 2026
18bada9
ci: add CodeQL analysis workflow for PR code scanning
paccloud Mar 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: "CodeQL"

on:
push:
branches: [main]
pull_request:
branches: [main]

jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
security-events: write
contents: read

strategy:
matrix:
language: [javascript]

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}

- name: Autobuild
uses: github/codeql-action/autobuild@v3

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ server/uploads/
.vercel
.env*.local

# Worktrees
worktrees/

# Design and datasets
Design Inspiration Ideas/
datasets/
48 changes: 48 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Repository Guidelines

## Project Structure & Module Organization

- `app/`: React + Vite frontend.
- `app/src/components/`: UI (calculator, auth, data management).
- `app/src/context/`: React Context providers (auth/theme).
- `app/src/data/`: Yield datasets + validators/tests (e.g. `fish_data_v3.js`).
- `app/public/`: Static assets.
- `server/`: Local Express API + SQLite (`server/server.js`, `server/fish_app.db`, `server/uploads/`).
- `api/`: Vercel serverless endpoints; shared helpers live in `api/_lib/` (Neon/Stack Auth).
- `docs/`: `docs/ARCHITECTURE.md`, `docs/API.md`. `scripts/` contains migration/import utilities.

## Build, Test, and Development Commands

- Install dependencies:
- Frontend: `cd app && npm install`
- Local API: `cd server && npm install`
- Run locally (two terminals):
- API: `cd server && node server.js` (defaults to `http://localhost:3000`)
- UI: `cd app && npm run dev` (Vite proxies `/api` → `http://localhost:3000`)
- Quality and builds:
- Lint: `cd app && npm run lint`
- Test: `cd app && npm test`
- Build/preview: `cd app && npm run build && npm run preview`

## Coding Style & Naming Conventions

- Frontend code is ESM (`app/package.json` has `"type": "module"`). Keep imports/exports consistent.
- Indentation: 2 spaces in `app/`; elsewhere, follow the existing file’s style.
- React components: `PascalCase.jsx`; hooks: `useThing()`.
- Yield conversion keys use the exact pattern `"From State → To State"` (note the arrow), with numeric `yield` and optional `[min, max]` `range`.

## Testing Guidelines

- Test framework: Vitest (see `app/src/data/fish_data.test.js`).
- When changing yield data or validators (`app/src/data/*`), run `cd app && npm test` before opening a PR.

## Commit & Pull Request Guidelines

- Use feature branches: `feature/...`, `fix/...`, `refactor/...`, `docs/...` (avoid direct commits to `main`).
- Prefer the commit style used in recent history: `feat:`, `fix:`, `refactor:`, `test(data):` + a short imperative summary.
- PRs should include: clear description of user impact, linked issue (if any), screenshots for UI changes, and citations for any new/updated yield data.

## Configuration & Security

- Do not commit secrets. Use example files like `app/.env.example` and `server/.env.example`, then local overrides (e.g. `.env.local`).
- Local development uses SQLite (`server/`); production deployment uses Vercel serverless endpoints in `api/` with Neon-backed storage.
85 changes: 50 additions & 35 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,18 @@ Local Catch is a fish yield calculator for the seafood industry. It calculates t
# Frontend (Vite + React) - runs on http://localhost:5173
cd app && npm run dev

# Backend (Express + SQLite) - runs on http://localhost:3000
# Backend (Express + SQLite) - local dev only, runs on http://localhost:3000
cd server && node server.js

# Alternative: test Vercel serverless functions locally (uses Neon DB)
vercel dev

# Lint frontend
cd app && npm run lint

# Run tests (Vitest)
cd app && npm test

# Build frontend for production
cd app && npm run build
```
Expand All @@ -27,29 +33,42 @@ cd app && npm run build
```bash
cd app && npm install
cd ../server && npm install
# Copy and configure env files (no quotes around values — Vite includes them literally)
cp app/.env.example app/.env.development
```

## Architecture

### Dual Backend Design

The project has **two separate backend implementations** that serve different environments:

1. **`server/server.js`** — Local development Express server with SQLite (`fish_app.db`). Single-file, JWT auth with bcrypt. Used when running `node server.js`.

2. **`api/`** — Vercel serverless functions for production. Each file is a separate endpoint. Uses Neon PostgreSQL via `@neondatabase/serverless`. Shared helpers in `api/_lib/`:
- `db.js` — Neon connection pool
- `auth.js` — Dual auth: JWT tokens (password) + Neon Auth/Stack Auth sessions (OAuth), with `requireAuth()` HOF
- `cors.js` — Origin allowlist from `ALLOWED_ORIGINS` env var, with `handleCors()` HOF
- `neon-auth.js` — Stack Auth session verification + local user auto-creation

**Important:** Changes to API logic must be applied to both `server/server.js` (local) and the corresponding `api/*.js` file (production) to stay in sync.

### Frontend (`app/`)
- **React 19 + Vite 7** with Tailwind CSS
- **React 19 + Vite 7** with Tailwind CSS 3
- Entry: `src/main.jsx` → `src/App.jsx`
- Routes defined in `App.jsx`: `/` (Calculator), `/login`, `/upload`, `/about`, `/data-sources`, `/manage-data`
- Main calculator logic in `src/components/Calculator.jsx`
- Fish yield data in `src/data/fish_data_v3.js` - contains 60+ species with conversion yields from MAB-37 research publication
- Auth state managed via React Context in `src/context/AuthContext.jsx`

### Backend (`server/`)
- **Express 5** server with SQLite database (`fish_app.db`)
- Single file: `server.js` handles all API routes
- JWT authentication with bcrypt password hashing
- File uploads via multer for Excel/CSV import
- Auth: Stack Auth (OAuth) via `@stackframe/react` wrapping the entire app, plus custom JWT-based password auth via `src/context/AuthContext.jsx`
- API base URL configured in `src/config/api.js` — uses `VITE_API_URL` in dev (localhost:3000), empty string in prod (same-origin)
- Routes defined in `App.jsx`:
- `/` (Home), `/calculator`, `/login`, `/upload`, `/about`, `/submit-request`
- `/data-sources`, `/manage-data`, `/profile`, `/roadmap`
- `/handler/*` (Stack Auth handler routes)
- Fish yield data in `src/data/fish_data_v3.js` — 60+ species with conversion yields from MAB-37 research publication

### Data Flow
1. Fish yield data is static in `fish_data_v3.js` (from MAB-37 PDF research document)
2. Users can add custom yield data stored in SQLite `user_data` table
2. Users can add custom yield data stored in SQLite (local) or Neon PostgreSQL (prod) `user_data` table
3. Calculator merges static + user data, performs yield/cost calculations client-side
4. Saved calculations stored in SQLite `calculations` table
4. Saved calculations stored in `calculations` table

### Key Data Structures
Fish conversions use "From State → To Product" pattern with yield percentages:
Expand All @@ -68,8 +87,18 @@ Common acronyms: Round (whole fish), D/H-On (dressed/head-on), D/H-Off (dressed/
Auth: `POST /api/register`, `POST /api/login`
Calculations: `GET/POST /api/saved-calcs`, `POST /api/save-calc`
User Data: `GET/POST/PUT/DELETE /api/user-data`, `POST /api/upload-data` (Excel/CSV)
Public: `GET /api/public-calcs`, `GET /api/contributors`, `GET /api/fish-data`
Export: `GET /api/export`

All endpoints except register/login/public require JWT Bearer token or Stack Auth session.

All endpoints except register/login require JWT Bearer token.
## Deployment

Deployed on **Vercel** with Neon PostgreSQL. See `DEPLOYMENT.md` for full guide.
- `vercel.json` configures build, output dir (`app/dist`), and API rewrites
- Frontend env vars use `VITE_` prefix (bundled into client, not secret)
- Server env vars: `DATABASE_URL`, `JWT_SECRET`, `ALLOWED_ORIGINS`, `STACK_SECRET_SERVER_KEY`
- **No quotes in `.env` files** — Vite includes them literally. See `docs/ENVIRONMENT_VARIABLES.md`

## Git Workflow

Expand All @@ -82,26 +111,12 @@ All endpoints except register/login require JWT Bearer token.
- Docs: `docs/<short-description>`

### Required Workflow
1. **Create a new branch** before starting any work:
```bash
git checkout -b feature/your-feature-name
```

2. **Make changes** and commit frequently with clear messages

3. **Push the branch** to remote:
```bash
git push -u origin feature/your-feature-name
```

4. **Create a Pull Request** using GitHub CLI:
```bash
gh pr create --title "Your PR title" --body "Description of changes"
```

5. **Never commit directly to main** - all changes must go through PRs
1. Create a new branch before starting any work
2. Make changes and commit frequently with clear messages
3. Push the branch and create a Pull Request via `gh pr create`
4. **Never commit directly to main** — all changes must go through PRs

### Commit Message Format
- Use present tense ("Add feature" not "Added feature")
- Keep first line under 70 characters
- Use conventional commit prefixes: `feat:`, `fix:`, `refactor:`, `test:`, `docs:`
- Present tense, under 70 characters
- Reference issue numbers when applicable
15 changes: 6 additions & 9 deletions DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,10 @@ Before deploying, add these environment variables in Vercel:
| Variable | Value | Notes |
|----------|-------|-------|
| `DATABASE_URL` | Your Neon connection string | From Step 1.1 |
| `JWT_SECRET` | Your generated secret | From Step 2 |
| `JWT_SECRET` | Your generated secret | From Step 2 (required; API fails fast if missing) |
| `ALLOWED_ORIGINS` | Comma-separated allowlist (e.g. `https://your-app.vercel.app,http://localhost:5173`) | Required for CORS |
| `CORS_ALLOW_CREDENTIALS` | `true` or `false` | Only enable when you need cookies across origins |
| `JWT_EXPIRES_IN_SECONDS` | Optional, default `86400` | JWT lifetime (same value should be used locally) |

**How to add:**
1. In Vercel project settings → Environment Variables
Expand Down Expand Up @@ -143,13 +146,7 @@ In Vercel Dashboard → Functions → View logs for any errors

### Update Frontend URL (Optional)

If you want to restrict CORS in production:

1. Update `api/_lib/cors.js`:
```javascript
res.setHeader('Access-Control-Allow-Origin', 'https://your-app.vercel.app');
```
2. Commit and push
If you want to restrict CORS in production, set `ALLOWED_ORIGINS` to your live + preview URLs (for example `https://your-app.vercel.app,https://your-app-git-preview.vercel.app`). No code changes are required.

---

Expand Down Expand Up @@ -212,7 +209,7 @@ This will:
### "CORS errors"

- Check browser console for specific error
- Verify CORS headers in `api/_lib/cors.js`
- Verify `ALLOWED_ORIGINS` includes your current origin
- Test with public endpoints first (`/api/contributors`)

### Cold starts are slow
Expand Down
Loading
Loading