Skip to content

Latest commit

 

History

111 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Agile Saber — OCHO Field Operations PWA

Version License

Full-stack disaster response coordination platform for Operation Agile Saber 2026. Field personnel submit damage and UXO (Unexploded Ordnance) reports, manage evacuation manifests, and track personnel status — all offline-first, syncing automatically to a PostgreSQL backend when connectivity resumes. EOC operators monitor a real-time dashboard with WebSocket-powered live updates.


Screenshots

EOC (Operator) Views

Dashboard Accountability Manifests
EOC Dashboard Accountability Manifests
Asset Tracking Medical Tracking Repatriation
Asset Tracking Medical Tracking Repatriation
Aircraft Maintenance Data Import Chat
Aircraft Maintenance Data Import EOC Chat

Mobile (Field Personnel) Views

Login 2FA Menu
Login 2FA Menu
Field Reports Map View UXO Hazard
Field Reports Map View UXO Hazard
Chat Offline Queue MOPP Friendly
Mobile Chat Offline Queue MOPP Friendly

Prerequisites

Dependency Minimum Version Notes
Node.js 18.x 22.x used in Docker builds
npm 9.x Bundled with Node 18
PostgreSQL 16.x Required for backend; skip if using Docker
Docker 24.x Required for containerized deployment
Docker Compose 2.x Required for containerized deployment

A modern browser with IndexedDB, Geolocation API, and Service Worker support is required (Chrome 90+, Firefox 88+, Safari 15+).


Installation

Option 1: Full Stack with Docker (Recommended)

git clone https://github.com/AGILE-SABER-2026/Team-8-Repository.git
cd Team-8-Repository

# Configure environment files
cp .env.example .env
cp backend/.env.example backend/.env
# IMPORTANT: Edit backend/.env and set a strong JWT_SECRET before running

# Build and start all three services (db, backend, frontend)
docker-compose up -d --build

# Initialize the database (first time only)
docker exec agile-saber-backend npm run setup

Access: Frontend → http://localhost:8080 | Backend API → http://localhost:3001/api


Option 2: Frontend Only (No Backend)

npm install
cp .env.example .env
npm run dev

Access: http://localhost:5174

The app works fully offline using IndexedDB. Sync and real-time features require the backend to be running.


Option 3: Frontend + Backend Locally

Terminal 1 — Backend:

cd backend
npm install
cp .env.example .env
# Edit .env: set DB_USER, DB_PASSWORD, DB_NAME to match your local PostgreSQL

# First time only — create the database role and database
psql postgres -c "CREATE ROLE postgres WITH SUPERUSER LOGIN PASSWORD 'postgres';"
createdb agile_saber

# Run migrations + seed demo users + seed exercise data
npm run setup

npm run dev

Terminal 2 — Frontend:

npm install
cp .env.example .env
npm run dev

Access: Frontend → http://localhost:5174 | Backend → http://localhost:3001


Demo Credentials

Username Password Role Access Level
demo demo Field Basic reporting
jsmith Saber2026! Field Field operations
eoc_ops EOC2026! EOC Dashboard + coordination
admin Admin2026! Admin Full access

2FA PIN (demo): 123456


Usage

Frontend Scripts

npm run dev       # Start Vite dev server with HMR
npm run build     # Production build → dist/
npm run lint      # ESLint (zero warnings — any warning is a failure)
npm run preview   # Serve the production build locally

Backend Scripts

cd backend
npm run dev            # Start Express with nodemon (auto-reload)
npm run start          # Start Express without auto-reload
npm run migrate        # Apply schema.sql to PostgreSQL
npm run seed           # Seed demo users
npm run seed-exercise  # Seed exercise scenario data
npm run setup          # migrate + seed + seed-exercise (first-time init)

Database Utilities

# Connect to PostgreSQL inside Docker
docker exec -it agile-saber-db psql -U postgres agile_saber
docker exec agile-saber-db pg_dump -U postgres agile_saber > backup.sql
docker exec -i agile-saber-db psql -U postgres agile_saber < backup.sql

Architecture Overview

Team-8-Repository/
├── src/                       # React frontend (Vite)
│   ├── auth/                  # AuthContext (mock users + JWT fallback), useAuth
│   ├── components/            # AppHeader (drawer nav), BottomNav (tab nav)
│   ├── config/                # Region centers (Guam, Saipan, Tinian, Rota, CNMI)
│   ├── data/                  # day1_reports.js — 31KB seed data for demo
│   ├── db/                    # Dexie v4 schema (IndexedDB)
│   ├── hooks/                 # useSync — monitors navigator.onLine, drains queue
│   ├── pages/                 # One file per route (11 pages)
│   ├── services/              # api.js (REST + WebSocket), offlineQueue.js, store.js
│   └── App.jsx                # Routes + protected route guards
├── backend/                   # Express API server
│   ├── src/
│   │   ├── config/            # database.js, migrate.js, seed.js, schema.sql
│   │   ├── middleware/        # auth.js (authenticateToken, requireRole)
│   │   └── routes/            # auth.js, reports.js, manifests.js, repatriations.js
│   └── Dockerfile
├── docker-compose.yml         # Orchestrates db + backend + frontend
├── Dockerfile                 # Frontend: Node 22 build → Nginx unprivileged
└── nginx.conf                 # Gzip, 1-year asset cache, SPA fallback

How the pieces connect

  1. Submit reportDamageReport.jsx writes to Dexie with synced: false and queues a CREATE_REPORT action.
  2. Go onlineuseSync.js detects navigator.onLine, drains offlineQueue.js, POSTs to /api/reports, marks records synced: true.
  3. EOC Dashboard → Uses Dexie liveQuery() for local reactivity; also receives WebSocket pushes from the backend for real-time cross-client updates.
  4. MapView → Reads Dexie locally, renders severity-coded Leaflet markers on OSM tiles cached offline by Workbox (500 tiles, 30-day TTL).
  5. Auth → JWT issued by backend, stored in sessionStorage. If backend is unreachable, AuthContext.jsx falls back to hardcoded mock users so the app remains functional offline.

Key Design Decisions

Offline-first with Dexie/IndexedDB — Connectivity in field operations is unreliable. Every write is local-first; the backend is treated as an optional sync target, not a dependency.

WebSocket for real-time coordination — The backend broadcasts mutations (new reports, person status changes) to all connected clients except the sender, enabling EOC operators to see field updates without polling.

JWT with no refresh token — Tokens expire in 7 days. There is no silent refresh flow; this is a known limitation.

Nginx in Docker — The frontend container uses nginxinc/nginx-unprivileged (rootless). The SPA fallback (try_files $uri $uri/ /index.html) ensures React Router routes work on direct load.

Severity as integers 1–51 = Critical, 5 = Monitoring. This integer scale is used in the DB schema, map color coding, and EOC dashboard; all must stay in sync.

No TypeScript — The project uses JSX. @types/react is present only for IDE autocomplete.


Contributing

Branch Naming

<ticket-number>-<short-description>
# Examples:
6-add-login-function-to-the-landing-page
22-websocket-reconnect-backoff

PR Process

  1. Branch off main.
  2. Run lint before pushing:
    npm run lint
  3. Verify the production build completes:
    npm run build
  4. Open a PR targeting main.

No CI pipelines exist — reviewers verify lint and build manually. There is no test suite.


Environment Variables

Frontend (.env)

Variable Required Default Description
VITE_API_URL No http://localhost:3001/api Backend REST base URL
VITE_WS_URL No ws://localhost:3001 Backend WebSocket endpoint

Backend (backend/.env)

Variable Required Default Description
DATABASE_URL Yes* Full PostgreSQL connection string
DB_HOST Yes* localhost PostgreSQL host
DB_PORT Yes* 5432 PostgreSQL port
DB_NAME Yes* agile_saber Database name
DB_USER Yes* postgres Database user
DB_PASSWORD Yes postgres Database password
JWT_SECRET Yes (insecure default) Must be changed before production
JWT_EXPIRES_IN No 7d Token lifetime
PORT No 3001 Express listen port
NODE_ENV No development production disables error stack traces
ALLOWED_ORIGINS No localhost variants CORS whitelist (comma-separated)
UPLOAD_DIR No ./uploads Local file upload path (multer, not yet wired)
MAX_FILE_SIZE No 10485760 (10MB) Max upload size in bytes
AWS_REGION No S3 region (future photo upload)
AWS_ACCESS_KEY_ID No S3 credentials (future)
AWS_SECRET_ACCESS_KEY No S3 credentials (future)
S3_BUCKET No S3 bucket name (future)

* Either DATABASE_URL or the individual DB_* variables are required.


Deployment

Docker Compose (Full Stack)

# Copy and configure both env files first
cp .env.example .env
cp backend/.env.example backend/.env
# IMPORTANT: Set a strong JWT_SECRET in backend/.env before deploying

docker-compose up -d --build

# First-time database init
docker exec agile-saber-backend npm run setup

# Check health
curl http://localhost:3001/health

Services: frontend on :8080, backend API on :3001, PostgreSQL on :5432.

For production details (security checklist, cloud platforms, scaling), see DEPLOYMENT.md.

Manual Static Hosting (Frontend Only)

npm run build
# Deploy dist/ to any static host (S3, Netlify, Vercel, Cloudflare Pages)
# The host must redirect all 404s to index.html for React Router to work

PWA / Mobile

The app is installable on iOS and Android via the browser's "Add to Home Screen" prompt. HTTPS is required for Service Worker registration on mobile. No separate native build process exists.


Known Issues / Roadmap

Issue Details
No JWT refresh Tokens expire after 7 days with no silent refresh. Users are silently deauthenticated post-expiry.
Mock 2FA The 2FA PIN 123456 is hardcoded in AuthContext.jsx. Not production-safe.
No photo size enforcement Photos stored as base64 in IndexedDB. Large images can exhaust browser storage quotas on mobile.
Multer installed but unused backend/package.json includes multer; no file upload endpoint exists yet.
Dexie schema migrations Adding/removing indexed fields in src/db/index.js requires a version bump or existing users get a startup crash.
No CI/CD No automated pipelines. Lint and build must be run manually pre-merge.
Rate limiter in dev Backend limits 100 req/15 min per IP; rapid dev scripts or browser devtools can trigger it unexpectedly.
WebSocket unauthenticated WebSocket connection carries no auth — any client on the network can connect.

License

Developed for Operation Agile Saber 2026 — Team 8 (OCHO). See LICENSE.

About

Ocho

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages