12 Commits
Author SHA1 Message Date
vinihcrosaandClaude Opus 4.8 d86116e33f fix(sim): address review round 1 (6 issues)
- manager: surface worker_thread errors/exit to clients and tear the sim
  down (issue 001); cache last status/state and replay on attach so a
  reconnecting client sees current state even when paused (issue 002)
- web socket: capped exponential reconnect backoff + bounded command queue
  (issue 003); derive ws/wss URL from page origin (issue 004)
- runner: build replacement engine before freeing the old one (issue 005)
- remove dead VesselConfig message path across types/api/web (issue 006)

Tests added for each fix. Full monorepo suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-05 12:05:05 -03:00
vinihcrosaandClaude Opus 4.8 cd29ee66b2 test(api): replace fixed delays with vi.waitFor to de-flake under load
The fan-out and router roundtrip tests waited a fixed 180ms for the 20 Hz
loop to emit a State, which was flaky under CPU contention (full turbo
run). Poll for the State event with vi.waitFor instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 20:46:59 -03:00
vinihcrosaandClaude Opus 4.8 4a1727e13e feat(api): WebSocket /ws gateway + message router
Add @fastify/websocket (v8, Fastify 4) and a GET /ws endpoint. MessageRouter
validates inbound ClientMessages (TypeBox), dispatches to SimulationManager,
binds each connection to its sim_id on Create/Attach, and maps worker events
to ServerMessage frames. REST routes coexist unchanged.

Task: task_05. Tests: 31 passing (real Fastify + WebSocket roundtrip,
malformed-message handling, REST coexistence); branches 82.5%.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 20:31:36 -03:00
vinihcrosaandClaude Opus 4.8 99b202317d feat(api): add SimulationManager (sim lifecycle, sim_id, TTL, fan-out)
Owns every live simulation on the Fastify main thread: spawns one
worker_thread per sim (ADR-002), maps sim_id -> worker + connections,
fans events out to connected clients, enforces a max-sim limit, and
tears orphaned sims down after a configurable TTL (ADR-006). Make
SimulationRunner.dispose idempotent.

Task: task_04. Tests: 19 passing incl. a real worker_thread booting the
engine; coverage 93.6% stmts / 88% branches.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 20:27:18 -03:00
vinihcrosaandClaude Opus 4.8 18aeb0a525 feat(api): add SimulationRunner + worker_thread bridge
Server-side simulation runtime: SimulationRunner owns one real WASM
engine and its 20 Hz tick loop, applying commands (loadScenario,
play/pause/reset, actuators, environment) and producing snapshots.
attachRunnerToPort bridges it to a worker_thread port; the thread
entrypoint lives in simulation-worker.entry.ts. Adds vitest to apps/api.

Task: task_03. Tests: 12 passing (real engine + MessageChannel bridge),
coverage 98.6% stmts / 89.5% branches.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-03 20:21:59 -03:00
vinihcrosaandClaude Opus 4.8 6049f3af31 fix(api): type scenario initialConditions backfill explicitly (fixes docker build)
The legacy-row backfill spread `Record<string,number>` which tsc could not narrow
to InitialCondition, breaking `pnpm --filter @ymir/api build` (and the docker api
image). Construct each InitialCondition explicitly with defaults. Verified
`apps/api` tsc + full `docker compose build` + up (api/web healthy).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 23:25:18 -03:00
vinihcrosaandClaude Opus 4.8 e2b50cde87 feat(web): scenario list screen + routing (Meus cenários)
Add react-router-dom with two routes: "/" → MyScenariosPage (scenario grid with
search, create, open, delete against the scenarios API) and "/editor" → AppShell.
"Sair do cenário" returns to the list. New: use-scenarios hook, ScenarioCard,
MyScenariosPage (+ tests, 235 web tests green).

API: backfill legacy initialConditions rows missing instanceId so GET /scenarios
serializes under the updated schema.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 22:19:20 -03:00
vinihcrosaandClaude Sonnet 4.6 6ba2755448 fix(web): downgrade react-leaflet to v4 for React 18 compatibility
react-leaflet v5 requires React 19 — caused "render2 is not a function"
runtime crash and white screen. Downgraded to v4.2.1.

fix(docker): separate DB volume mount from API dist directory

Volume was mounted at /app/apps/api, overwriting compiled dist/ with stale
files from previous container runs. Changed mount to /app/data for DB only.

fix(api): copy area.json and vessel1.json into API Docker image

Seed files could not resolve JSON data at container startup.
Added COPY in Dockerfile and corrected path depth from 5 to 4 levels.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 03:44:16 -03:00
vinihcrosaandClaude Sonnet 4.6 a9061fbf2b feat(persistence): add simulation area model with geographic boundary
Introduces the Area entity: geographic origin (lat/lng = simulation 0,0),
GeoJSON polygon boundary, and environmental constants (gravity, water/air
density, magnetic correction). A simulation cannot run outside its area.

- areas table with origin, polygon (GeoJSON), and environment constants
- Auto-seed from area.json on startup (Baía de Guanabara)
- GET/POST/DELETE /areas endpoints (route → service → repository)
- scenarios.area_id FK — nullable for existing rows, idempotent ALTER migration
- AreaDTO + CreateAreaDTO in @ymir/types; ScenarioDTO gains optional areaId

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 02:52:23 -03:00
vinihcrosaandClaude Sonnet 4.6 5d937ca07b feat(persistence): store full vessel physics config from vessel1.json
Adds 6 supplementary SQLite tables (physical_props, current, connection_points,
rudders, thrusters, waves) to hold all hydrodynamic data for the VLCC
VLCC_L350_B63_T230 (L=350m, B=63m, T=23m).

- Auto-seed at startup: reads vessel1.json into all tables when DB is empty
- GET /vessels/:id/config endpoint returns full physics config for simulation
- Refactored vessels route to use service + repository layer pattern
- Expanded @ymir/types with VesselConfigDTO and all sub-component schemas
- Simulation worker fetches vessel config on init, passes to WASM loadConfig()

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 02:06:56 -03:00
vinihcrosaandClaude Sonnet 4.6 3630507efa chore: remove build artifacts from tracking, update .gitignore
- Add dist/, *.profraw, .wasm-stage/ to .gitignore
- Remove apps/api/dist/, apps/web/dist/, packages/types/dist/ from git
  (generated on build, should not be versioned)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 00:41:24 -03:00
vinihcrosaandClaude Sonnet 4.6 6295d540a4 feat: migrate to monorepo with WASM core, Fastify API, and React frontend
- Move C++ sources to core/ subdirectory (T05)
- Add pnpm workspaces + Turborepo pipeline (T06)
- Add Emscripten CMake target and build-wasm.sh (T07)
- Implement Embind bindings via YmirBindings.cpp (T08)
- Add packages/types with TypeBox schemas for VesselDTO, ScenarioDTO, SimulationStateDTO (T09)
- Create apps/api: Fastify v4 + Drizzle ORM + SQLite with vessels/scenarios CRUD (T10-T13)
- Create apps/web: Vite + React 18 + COOP/COEP headers (T14)
- Add simulation.worker.ts for WASM loop in Web Worker (T15)
- Add Zustand simulationStore (T16)
- Add TelemetryPanel component (T17)
- Verified: pnpm build 3/3 tasks, 21ms cached; ctest 211/211 pass (T18-T19)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 00:08:28 -03:00