A real-time maritime fleet tracking and command system for the Strait of Hormuz. Features live ship simulation, AI-powered distress analysis, weather-aware routing, and role-based operations for Command and Captain roles.
- Node.js 20+
- npm
- Supabase project (for persistence)
- Clerk account (for authentication)
- Groq API key (for AI analysis)
cd backend
npm install
node index.jsExpected output:
π Backend listening on http://localhost:4000
π WebSocket at ws://localhost:4000/ws
π Health check at http://localhost:4000/health
π’ Simulator started β 15 ships, tick 1000ms
π Weather service started (5-min refresh)
cd frontend
npm install
npm run devOpens on http://localhost:3000
- Open http://localhost:3000 β Sign in with Clerk
- Navigate to
/commandfor Command dashboard - Navigate to
/captainfor Captain view
PORT=4000
FRONTEND_URL=http://localhost:3000
CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=
SUPABASE_URL=
SUPABASE_SERVICE_ROLE_KEY=
GROQ_API_KEY=
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
NEXT_PUBLIC_BACKEND_URL=http://localhost:4000
NEXT_PUBLIC_WS_URL=ws://localhost:4000/ws
Run the following in the Supabase SQL Editor:
create table ship_snapshots (
id uuid default gen_random_uuid() primary key,
snapshot_time timestamptz default now(),
ships_data jsonb not null,
created_at timestamptz default now()
);
create table alerts (
id uuid default gen_random_uuid() primary key,
type text not null,
ship_id text not null,
message text,
severity text default 'medium',
acknowledged boolean default false,
created_at timestamptz default now()
);
create table directives (
id uuid default gen_random_uuid() primary key,
ship_id text not null,
issued_by text,
type text not null,
payload jsonb,
status text default 'pending',
created_at timestamptz default now()
);
create table distress_messages (
id uuid default gen_random_uuid() primary key,
ship_id text not null,
raw_message text,
ai_analysis jsonb,
created_at timestamptz default now()
);| Layer | Technology |
|---|---|
| Frontend | Next.js 16 (App Router), React, TypeScript, Tailwind CSS |
| Map | Leaflet + react-leaflet |
| Auth | Clerk (RBAC: command / captain) |
| Backend | Node.js, Express, WebSocket (ws library) |
| Database | Supabase (PostgreSQL) |
| AI | Groq API (LLaMA 3.3 70B) |
| Weather | Open-Meteo (free, no API key) |
βββββββββββββββ WebSocket βββββββββββββββββββ
β Frontend βββββββββββββββββββββΊβ Backend β
β Next.js β (STATE_UPDATE, β Express + WS β
β Port 3000 β ALERT, etc.) β Port 4000 β
βββββββββββββββ ββββββββ¬βββββββββββ
β
ββββββββ΄βββββββ
β Simulator β
β Engine β
β (1Hz tick) β
ββββββββ¬βββββββ
β
βββββββββββββΌββββββββββββ
βΌ βΌ βΌ
Supabase Open-Meteo Groq AI
(persist) (weather) (NLP)
- 15 ships simulating in the Strait of Hormuz with realistic positions and routes
- A* grid-based pathfinding constrained to navigable water polygon
- 1Hz simulation tick with position updates, fuel depletion, and status management
- WebSocket real-time sync (< 500ms latency, 5+ simultaneous clients)
- 60fps interpolated ship movement on map (requestAnimationFrame)
- normal β ship en route to destination
- rerouting β recalculating path around zones
- distressed β captain escalated emergency
- stopped β manually held or out of fuel
- stranded β no valid route to destination
- arrived β reached destination port
- insufficient_fuel β predicted to run out before arrival (continues moving)
- out_of_fuel β fuel depleted (stops moving)
- Real-time weather from Open-Meteo (wind speed + wave height)
- 5Γ5 grid overlay on map showing adverse conditions
- Adverse threshold: wind > 25 kn OR wave > 2.5m
- 30% fuel burn penalty in adverse weather cells
- Storm icon indicator on affected ships
- Refreshes every 5 minutes with fallback data
- Geofence breach β ship enters restricted zone (< 1 second detection)
- Proximity warning β ships within 2 km (hysteresis clears at 2.5 km)
- Fuel prediction β alerts when ship can't reach destination with remaining fuel
- Zone prediction β alerts when ship will enter restricted zone within 5 minutes
- Stranded β no valid path exists
- Priority scoring: base type score Γ severity multiplier + urgency bonuses
- Audio alert (440Hz Web Audio tone) on new alerts
POST /api/ai/analyze-distressβ structured distress message analysisPOST /api/ai/fleet-advisorβ proactive fleet management suggestions- AI analysis includes: severity, category, injury count, damage estimate, recommended action
- Results saved to Supabase and displayed in real-time
- Command β full fleet overview, draw zones, issue directives, AI advisor
- Captain β own ship status, directives inbox, distress composer
- Roles from Clerk
publicMetadata.role("command" | "captain")
- 60-minute history at 30-second snapshot resolution
- Timeline scrubber with play/pause and speed controls (1Γ/2Γ/5Γ)
- Event dots on timeline for alert visualization
- "PLAYBACK MODE" banner when scrubbing, "Live" button to return
| Method | Path | Description |
|---|---|---|
| GET | /health |
Server status, ship count, client count |
| GET | /api/ships |
Current state of all 15 ships |
| GET | /api/alerts |
All alerts (prioritized) |
| GET | /api/directives |
All directives from Supabase |
| GET | /api/weather |
Current weather grid and adverse cells |
| GET | /api/history |
Last 60 min snapshots at 30s resolution |
| POST | /api/ai/analyze-distress |
AI distress message analysis |
| POST | /api/ai/fleet-advisor |
AI fleet management suggestions |
| Direction | Type | Description |
|---|---|---|
| ServerβClient | INIT_STATE |
Full fleet state on connect |
| ServerβClient | INIT_ALERTS |
Unacknowledged alerts on connect |
| ServerβClient | STATE_UPDATE |
Periodic ship positions + weather |
| ServerβClient | ALERT |
New alert fired |
| ServerβClient | ALERT_ACKNOWLEDGED |
Alert was acknowledged |
| ServerβClient | DIRECTIVE_ISSUED |
New directive issued |
| ServerβClient | CAPTAIN_RESPONDED |
Captain response to directive |
| ServerβClient | ZONE_ADDED |
New restricted zone |
| ServerβClient | ZONE_REMOVED |
Zone removed |
| ClientβServer | ACKNOWLEDGE_ALERT |
Acknowledge an alert |
| ClientβServer | ISSUE_DIRECTIVE |
Issue directive to ship |
| ClientβServer | ADD_ZONE |
Create restricted zone |
| ClientβServer | REMOVE_ZONE |
Remove restricted zone |
| ClientβServer | CAPTAIN_RESPONSE |
ACCEPT or ESCALATE_DISTRESS |
1. Docker / docker compose β not implemented. Run backend and frontend manually (see above).
2. Railway deploy β not implemented. System runs locally only.
3. Real coastline data β not used. A simplified navigable water polygon is used as specified.
4. Multiple route options (bonus) β not implemented.
5. Ship-to-ship assistance (bonus) β not implemented.
6. AI fleet advisor proactive suggestions (bonus) β partially implemented via /api/ai/fleet-advisor endpoint.
7. Predictive alerts (bonus) β implemented via 5-minute projection in tick loop.
| Feature | Status | Details |
|---|---|---|
| Predictive zone alerts | β Full | 5-minute forward projection, fires alert with ETA |
| Predictive fuel alerts | β Full | Distance-short calculation, severity-based |
| Proximity hysteresis | β Full | Warn at < 2km, clear at > 2.5km, no flapping |
| Weather integration | β Full | Open-Meteo real data, 5Γ5 grid, fuel penalty |
| AI distress analysis | β Full | Groq LLaMA 3.3 70B, structured JSON output |
| AI fleet advisor | β Partial | Endpoint works, UI panel for accept/dismiss |
| Playback timeline | β Full | 60min history, scrub, speed controls, event dots |
| Audio alerts | β Full | Web Audio API, 440Hz tone on new alerts |