rubis/apps/api/package.json
ordinarthur f33b2dd319
All checks were successful
Build & Deploy Web / build-and-deploy (push) Successful in 1m9s
Build & Deploy API / build-and-deploy (push) Successful in 2m2s
feat(observability): Sentry monitoring API + Web (ADR-024)
Intégration Sentry SaaS pour error monitoring + replay sur les 2 apps.

API (apps/api) :
- start/sentry.ts : init au plus tôt dans bin/server.ts (avant Ignitor)
  pour capturer les erreurs de bootstrap. No-op si SENTRY_DSN_API absent.
- app/exceptions/handler.ts:report : captureException sur les 5xx avec
  tags { url, method, status } et user.id (PII minimisée). 4xx filtrés
  par beforeSend dans start/sentry.ts (validation, auth invalide = bruit).
- start/env.ts : SENTRY_DSN_API + APP_VERSION optionnels.
- bin/server.ts : import #start/sentry en 1er.
- @sentry/node + @sentry/profiling-node ajoutés au package.json.

Web (apps/web) :
- src/lib/sentry.ts : init au plus tôt dans main.tsx, BrowserTracing +
  Replay (0% session, 100% sur erreur — économie quota free tier).
  maskAllText + blockAllMedia pour privacy par défaut.
- src/lib/auth.ts : Sentry.setUser({ id }) au login, setUser(null) au
  logout (corrélation cross-stack des erreurs front avec un user).
- src/main.tsx : ErrorBoundary autour de l'app avec FallbackError UX.
- vite.config.ts : @sentry/vite-plugin uploads les sourcemaps + les
  SUPPRIME du dist/ final (filesToDeleteAfterUpload) pour ne pas leak
  le code source via nginx en prod. Helper resolveAppVersion() pour
  injecter le sha git en dev (le shell n'étant pas évaluable dans .env).
- src/lib/env.ts : VITE_SENTRY_DSN_WEB + VITE_APP_VERSION optionnels.
- .env.development : VITE_SENTRY_DSN_WEB (préfixé correctement pour
  être exposé par Vite — l'ancienne SENTRY_DSN ne marchait pas).
- @sentry/react + @sentry/vite-plugin ajoutés au package.json.

CI Gitea :
- deploy-api.yml : kubectl set env APP_VERSION=${{ github.sha }}
  runtime → release Sentry trackable au commit pour l'API.
- deploy-web.yml : build-args VITE_SENTRY_DSN_WEB, VITE_APP_VERSION,
  SENTRY_AUTH_TOKEN, SENTRY_ORG injectés depuis les secrets Gitea.
- Dockerfile.web : ARG correspondants + propagation au stage build.

Privacy / sécurité (cf. ADR-024) :
- captureException tags : ctx.route?.pattern (pas l'URL réelle) →
  les codes OAuth (?code=...) et tokens de check-in n'apparaissent
  jamais dans les tags Sentry indexés.
- Sentry user context = user.id UUID seulement, pas d'email/nom.
- Sourcemaps en prod : uploadées à Sentry, supprimées du bundle.
- 4xx filtrées en amont (beforeSend) ET en aval (handler.ts:report).
- DSN public (by-design) commit-able, AUTH_TOKEN secret CI uniquement.

Sample rates (free tier 5K events / 50 replays par mois) :
- traces : 10% prod, 100% dev
- profiles : 100% (sampled par traces)
- replay session : 0% (économie quota)
- replay sur erreur : 100% (debug post-mortem)

Pré-requis runtime à configurer hors-repo :
- Secret K3s rubis-app-secrets : SENTRY_DSN_API
- Secrets Gitea Actions : SENTRY_DSN_WEB, SENTRY_AUTH_TOKEN, SENTRY_ORG

ADR-024 logué dans docs/decisions.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 13:38:12 +02:00

104 lines
3.1 KiB
JSON

{
"name": "@rubis/api",
"version": "0.1.0",
"private": true,
"type": "module",
"license": "MIT",
"exports": {
"./data": "./.adonisjs/client/data.d.ts",
"./registry": "./.adonisjs/client/registry/index.ts"
},
"scripts": {
"start": "node bin/server.js",
"build": "node ace build",
"dev": "node ace serve --hmr",
"test": "node ace test",
"lint": "eslint .",
"format": "prettier --write .",
"typecheck": "tsc --noEmit"
},
"imports": {
"#controllers/*": "./app/controllers/*.js",
"#exceptions/*": "./app/exceptions/*.js",
"#models/*": "./app/models/*.js",
"#mails/*": "./app/mails/*.js",
"#services/*": "./app/services/*.js",
"#jobs/*": "./app/jobs/*.js",
"#listeners/*": "./app/listeners/*.js",
"#events/*": "./app/events/*.js",
"#generated/*": "./.adonisjs/server/*.js",
"#middleware/*": "./app/middleware/*.js",
"#transformers/*": "./app/transformers/*.js",
"#validators/*": "./app/validators/*.js",
"#providers/*": "./providers/*.js",
"#policies/*": "./app/policies/*.js",
"#abilities/*": "./app/abilities/*.js",
"#database/*": "./database/*.js",
"#tests/*": "./tests/*.js",
"#start/*": "./start/*.js",
"#config/*": "./config/*.js"
},
"devDependencies": {
"@adonisjs/assembler": "^8.4.0",
"@adonisjs/eslint-config": "^3.0.0",
"@adonisjs/prettier-config": "^1.4.5",
"@adonisjs/tsconfig": "^2.0.0",
"@japa/assert": "^4.2.0",
"@japa/plugin-adonisjs": "^5.2.0",
"@japa/runner": "^5.3.0",
"@poppinss/ts-exec": "^1.4.4",
"@types/luxon": "^3.7.1",
"@types/node": "~25.6.0",
"@types/pg": "^8.20.0",
"@types/react": "^19.2.14",
"eslint": "^10.2.0",
"hot-hook": "^1.0.0",
"pino-pretty": "^13.1.3",
"prettier": "^3.8.2",
"tsx": "^4.21.0",
"typescript": "~6.0.2",
"youch": "^4.1.1"
},
"dependencies": {
"@adonisjs/ally": "^6.3.0",
"@adonisjs/auth": "^10.1.0",
"@adonisjs/bouncer": "^4.0.0",
"@adonisjs/core": "^7.3.1",
"@adonisjs/cors": "^3.0.0",
"@adonisjs/drive": "^4.0.0",
"@adonisjs/limiter": "^3.0.1",
"@adonisjs/lucid": "^22.4.2",
"@adonisjs/mail": "^10.2.0",
"@adonisjs/session": "^8.1.0",
"@adonisjs/shield": "^9.0.0",
"@adonisjs/static": "^2.0.1",
"@aws-sdk/client-s3": "^3.1043.0",
"@aws-sdk/s3-request-presigner": "^3.1043.0",
"@japa/api-client": "^3.2.1",
"@react-email/components": "^1.0.12",
"@react-email/render": "^2.0.8",
"@react-pdf/renderer": "^4.5.1",
"@sentry/node": "^10.52.0",
"@sentry/profiling-node": "^10.52.0",
"@tuyau/core": "^1.2.2",
"@vinejs/vine": "^4.3.1",
"better-sqlite3": "^12.9.0",
"bullmq": "^5.76.5",
"ioredis": "^5.10.1",
"luxon": "^3.7.2",
"pg": "^8.20.0",
"react": "^19.2.5",
"reflect-metadata": "^0.2.2",
"stripe": "^22.1.1"
},
"hotHook": {
"boundaries": [
"./app/controllers/**/*.ts",
"./app/middleware/*.ts",
"./app/transformers/**/*.ts",
"./app/validators/**/*.ts",
"./app/services/**/*.ts"
]
},
"prettier": "@adonisjs/prettier-config"
}