
Goable è un'API REST B2B multi-tenant che restituisce punteggi di idoneità (0–100) per attività outdoor nelle quattro famiglie — acqua (kitesurf, surf, windsurf, vela, sub), neve (sci alpinismo, freeride, snowboard), aria (parapendio, deltaplano) e terra (trekking, trail running, arrampicata) — sulla base di previsioni meteorologiche in tempo reale e fisica multi-dominio. La piattaforma copre un monorepo Turborepo con quattro applicazioni (apps/api, apps/admin, apps/website, apps/worker-lambda), 23 package condivisi e una pipeline di calibrazione ML in Python, unificati sotto TypeScript Node 22 ESM con pnpm 10 workspaces.
apps/api — Hono 4.6, porta 4000)@goable-io/physics, @goable-io/scoring, @goable-io/intelligence, @goable-io/decision-agent, @goable-io/counterfactual, @goable-io/drift-monitor) iniettato nel composition root.@goable-io/physics): 21 namespace — wind, wave, tide, astronomy, bathymetry, atmosphere, thermal, comfort, swell, visibility, snow, lightning, precipitation, airQuality, marine, hydrology, alpine, coastal, time, surface. Matematica pura, nessun I/O, ogni modulo porta un header con citazione.src/routes/ (varianti score pubbliche, intelligence, proiezioni, osservazioni, admin calibration/drift/verification/decision, billing); 33 file di use case sotto src/usecases/. Le route non devono contenere logica di business — validate → chiama un use case → errorResponse(). Utility condivise: lib/httpErrors.ts (errorResponse + ErrorCodes), lib/schemas.ts (GeoPointSchema, TimeWindowStringSchema), middleware/planGate.ts (requirePlanAtLeast, requireScope, requireAuth).src/compose.ts (46 K LOC). Drizzle + Postgres per 20+ tipi di entità; Redis per sessione/rate-limit (finestra giornaliera per piano: free=100, starter=1 k, pro=10 k, scale=∞); DynamoDB KV cache (peer dep opzionale); fallback in-memory per lo sviluppo.lightning_proximity ≥ 0.85 o AQI category = hazardous → verdict=unsafe, indipendentemente dal profilo.@hono/zod-openapi per la generazione dello schema; Scalar UI servita a /docs. L'SDK è generato dallo stesso schema via openapi-typescript.infra/migrations/ (PostGIS geography(POINT, 4326), tipi custom tstzrange, tabelle pseudonimo con Row-Level Security). I binding Drizzle in @goable-io/tenants rispecchiano le migrazioni ma non generano lo schema.apps/admin — Next.js 16, porta 4001)ops/ (staff interno — tutti i tenant, calibration, drift, verification, audit, provider-skill, recommendation-runs) e portal/ (cliente — impostazioni, chiavi API, usage, outcomes, webhook, billing), entrambi protetti da cookie JWT HS256 (goable_console_session, TTL 8h) via jose server-side. Il server della console si autentica all'API tramite header X-Goable-Key.src/features/: ogni cartella esporta via index.ts e isola server/dal.ts (tutte le chiamate API), server/keys.ts (chiavi TanStack Query), server/schemas.ts (Zod) e ui/ (componenti React). Nessun import diretto tra feature./api), nuqs 2 per lo stato filtri/paginazione persistito nell'URL.@tanstack/react-form con field path type-safe + validatori Zod esposti via shadcn FormMessage. Toast via Sonner 2.apps/website — Next.js 16, porta 4002)/catalog (browser dei profili attività), /score (demo interattiva), /explain, /decision, /recommend, /adaptation, /forecast-verification, /sustainability-index, /underwriting, /spc-charter, /provider-skill, /personalize, /spot-discovery, /docs (27 route annidate), /research, /science, più routing dinamico /legal/[doc]./sealect (verticale acqua), /spc-charter (neve / syndicate Lloyd's), /partner-with-us.@gsap/react 2.1 per parallax hero, pill tab e transizioni. Embla Carousel 8.6 per caroselli di card.react-markdown + remark-gfm per le pagine doc; @goable-io/sdk (workspace) usato nelle demo interattive per chiamare l'API live.@goable-io/profiles-catalog (repo esterno goable-io/profiles-catalog, CC BY 4.0, v2.3.4 su npm): 18+ profili attività base in YAML su quattro categorie, con varianti regionali e per spot. Aggiungere un'attività è una PR su quel repo, non una modifica a questo monorepo. Lo schema Zod è byte-identico tra i due repo — packages/profiles/test/schemaSync.test.ts verifica l'hash in CI.@goable-io/sdk (v0.2.0, pubblicato su npm): client TypeScript zero-dependency per tutti gli endpoint pubblici — score, scoreSeries, scoreMulti, scoreHistorical, scorePortfolio, explainCounterfactual, decision, deleteUserData, explain, briefing, projections, quote, health. Funziona su Node ≥18 e browser. Errori tipizzati: GoableApiError (422 + array Zod issues), GoableNetworkError (timeout/parse). Config: apiKey, baseUrl, timeoutMs, override fetch.packages/calibration/): cron settimanale di calibrazione L3 (.github/workflows/calibration-weekly.yml) — ensemble triple-method (sklearn isotonic, GaussianProcess, statsmodels Logit × 500 bootstrap) + Heckman IPW + gate Brier Skill Score. Genera diff YAML curve + PR body per la review degli operatori.apps/worker-lambda): eventi webhook Stripe via SQS → use case processStripeWebhookEvent → aggiornamento usage tenant su Drizzle. Bundle con esbuild (ESM, Node 22), deploy via Terraform.infra/terraform/): moduli bootstrap + per-environment (env/prod/) per l'infrastruttura AWS.calibration-weekly.yml, drift-daily.yml (scan CUSUM alle 04:00 UTC), decision-agent-nightly.yml (warm-start retrain MLP alle 03:00 UTC)./v1/health/ready (condizionato all'idratazione skill-lookup); graceful shutdown su SIGTERM (budget 10s per le richieste in volo).@goable-io/emails — template React Email (@react-email/components, @react-email/render).@goable-io/sdk 0.2.0 (client API zero-dep), @goable-io/profiles-catalog 2.3.4 (profili YAML pubblici), @hono/zod-openapi (route OpenAPI-first), drizzle-orm 0.38 (Postgres type-safe), @tanstack/react-query 5 + react-table 8 + react-form 1.28 (data layer admin), maplibre-gl 5 + react-map-gl 8 (UI geospaziale), pdfkit 0.18 (generazione PDF SPC charter), recharts 3 (dashboard admin), jose 5.9 (JWT HS256 session crypto), pino 9.5 (logging strutturato), vitest 2.1 (test unitari + integrazione), stripe 22 (API) + 17 (Lambda)src/, doppi apici, no semicoloni, trailing comma, organize-imports)app.request() — nessun server HTTP reale; pattern makeMockProvider(samples) per i mock meteo; RUN_PG_INTEGRATION=1 abilita i test di integrazione Drizzle; pnpm turbo lint typecheck test deve rimanere verde prima di ogni commitsdk-release.yml)Realizzato per Goable