{"openapi":"3.0.0","info":{"title":"Webgune API","version":"1.0.0","description":"API publique webgune. Authentification par clé API (`Authorization: Bearer wgk_...`, scopes `ressource:read|write|*`) ou par session cookie pour le dashboard. Chaque réponse d'erreur suit le format `{ error, code? }`. Voir /docs/reference-api et /docs/cles-api pour le guide complet."},"servers":[{"url":"/api/v1","description":"Surface publique versionnée, stable pour les intégrations tierces"}],"security":[{"ApiKey":[]}],"components":{"securitySchemes":{"ApiKey":{"type":"http","scheme":"bearer","bearerFormat":"wgk_...","description":"Clé API créée depuis /dashboard/developers/api-keys, envoyée en en-tête `Authorization: Bearer wgk_...`. Chaque clé est limitée par des scopes `ressource:read|write|*` — voir /docs/cles-api."}},"schemas":{"Project":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"ownerId":{"type":"string"},"billingMode":{"type":"string","enum":["account","dedicated"]},"k8sNamespace":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","name","description","ownerId","billingMode","k8sNamespace","createdAt","updatedAt"]},"Service":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"projectId":{"type":"string"},"status":{"type":"string"},"serviceKind":{"type":"string"},"sourceType":{"type":"string","nullable":true},"branch":{"type":"string","nullable":true},"buildType":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","name","projectId","status","serviceKind","sourceType","branch","buildType","createdAt","updatedAt"]},"Deployment":{"type":"object","properties":{"id":{"type":"string"},"serviceId":{"type":"string"},"status":{"type":"string"},"commitSha":{"type":"string","nullable":true},"commitMessage":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","serviceId","status","commitSha","commitMessage","createdAt"]},"Domain":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tld":{"type":"string"},"fullDomain":{"type":"string"},"status":{"type":"string"},"ownerId":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","tld","fullDomain","status","ownerId","createdAt"]},"DnsRecord":{"type":"object","properties":{"type":{"type":"string","enum":["A","AAAA","CNAME","ALIAS","TXT","MX","SRV","CAA"]},"name":{"type":"string","minLength":1,"maxLength":255},"value":{"type":"string","minLength":1,"maxLength":512},"ttl":{"type":"integer","minimum":300,"maximum":86400,"default":3600},"priority":{"type":"integer","minimum":0,"maximum":65535}},"required":["type","name","value"]},"ApiKeySummary":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"keyPrefix":{"type":"string","description":"Préfixe affiché dans l'UI, ex. wgk_ab12cd34 — jamais la clé complète"},"scopes":{"type":"array","items":{"type":"string"}},"allowActingAs":{"type":"boolean"},"rateLimitPerMinute":{"type":"number"},"lastUsedAt":{"type":"string","nullable":true,"format":"date-time"},"expiresAt":{"type":"string","nullable":true,"format":"date-time"},"revokedAt":{"type":"string","nullable":true,"format":"date-time"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","keyPrefix","scopes","allowActingAs","rateLimitPerMinute","lastUsedAt","expiresAt","revokedAt","createdAt"]},"ApiKeyAuditLogEntry":{"type":"object","properties":{"id":{"type":"string"},"method":{"type":"string"},"path":{"type":"string"},"statusCode":{"type":"number"},"durationMs":{"type":"number","nullable":true},"actingAsUserId":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"}},"required":["id","method","path","statusCode","durationMs","actingAsUserId","createdAt"]},"MetricAlertRule":{"type":"object","properties":{"id":{"type":"string"},"userId":{"type":"string"},"serviceId":{"type":"string","nullable":true},"metric":{"type":"string","enum":["cpu","memory","disk","network"]},"thresholdValue":{"type":"number"},"windowSeconds":{"type":"number"},"isEnabled":{"type":"boolean"},"cooldownMinutes":{"type":"number"},"lastTriggeredAt":{"type":"string","nullable":true,"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","userId","serviceId","metric","thresholdValue","windowSeconds","isEnabled","cooldownMinutes","lastTriggeredAt","createdAt","updatedAt"]},"DashboardStats":{"type":"object","properties":{"totalServices":{"type":"number"},"serviceLimit":{"type":"number"},"cpu":{"type":"object","properties":{"used":{"type":"number"},"limit":{"type":"number"}},"required":["used","limit"]},"memory":{"type":"object","properties":{"used":{"type":"number"},"limit":{"type":"number"}},"required":["used","limit"]},"overload":{"type":"object","properties":{"active":{"type":"boolean"},"metrics":{"type":"array","items":{"type":"string"}}},"required":["active","metrics"]}}}},"parameters":{}},"paths":{"/projects":{"get":{"tags":["Projets"],"summary":"Lister les projets accessibles (propriétaire ou membre)","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Projets avec leurs services","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Project"}}}}}}},"post":{"tags":["Projets"],"summary":"Créer un projet","security":[{"ApiKey":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"description":{"type":"string","maxLength":500,"default":""},"billingMode":{"type":"string","enum":["account","dedicated"],"default":"account"}},"required":["name"]}}}},"responses":{"201":{"description":"Projet créé","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"403":{"description":"Aucun abonnement actif"}}}},"/projects/{id}":{"get":{"tags":["Projets"],"summary":"Détail d'un projet (services, membres, canvas)","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Projet","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}},"404":{"description":"Projet introuvable ou inaccessible"}}},"put":{"tags":["Projets"],"summary":"Renommer / modifier la description d'un projet","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"description":{"type":"string","maxLength":500}}}}}},"responses":{"200":{"description":"Projet mis à jour","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Project"}}}}}},"delete":{"tags":["Projets"],"summary":"Supprimer un projet (et son namespace K8s)","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Projet supprimé"},"403":{"description":"Rôle insuffisant"},"404":{"description":"Projet introuvable"}}}},"/services/project/{projectId}":{"get":{"tags":["Services"],"summary":"Lister les services d'un projet","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"projectId","in":"path"}],"responses":{"200":{"description":"Services du projet","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Service"}}}}}}}},"/services/{id}":{"get":{"tags":["Services"],"summary":"Détail d'un service (enrichi du statut K8s live)","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Service","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Service"}}}},"404":{"description":"Introuvable"}}},"delete":{"tags":["Services"],"summary":"Supprimer un service (et ses ressources K8s)","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Service supprimé"},"404":{"description":"Introuvable"}}}},"/services":{"post":{"tags":["Services"],"summary":"Créer un service (GitHub, upload, Docker ou base de données managée)","security":[{"ApiKey":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"project_id":{"type":"string","format":"uuid"},"service_type":{"type":"string","enum":["web"],"default":"web"},"service_kind":{"type":"string","enum":["web","bot","worker"],"default":"web"},"bot_runtime":{"type":"string","enum":["js","py"]},"shard_count":{"type":"integer","minimum":2,"maximum":32},"environment":{"type":"string","enum":["prod","preprod","dev"],"default":"prod"},"deploy_trigger":{"type":"string","enum":["push","release","both"],"default":"push"},"deploy_mode":{"type":"string","enum":["github","git","gitlab","upload","docker","database"],"default":"github"},"git_repo_url":{"type":"string","maxLength":500},"database_type":{"type":"string","enum":["postgres","mysql","mariadb","mongodb","redis"]},"database_password":{"type":"string","minLength":8,"maxLength":128},"database_user":{"type":"string","minLength":1,"maxLength":64},"build_type":{"type":"string","enum":["nixpacks","dockerfile","railpack"],"default":"nixpacks"},"tech_stack":{"type":"string","enum":["nodejs","static"],"default":"nodejs"},"github_repo":{"type":"string"},"github_owner":{"type":"string"},"branch":{"type":"string","default":"main"},"docker_image":{"type":"string"},"port":{"type":"integer","minimum":1,"maximum":65535,"default":3000},"env_vars":{"type":"object","additionalProperties":{"type":"string"},"default":{}}},"required":["name","project_id"]}}}},"responses":{"201":{"description":"Service créé","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Service"}}}},"400":{"description":"Payload invalide"}}}},"/services/{id}/redeploy":{"post":{"tags":["Services"],"summary":"Redéployer (nouveau build depuis la source configurée)","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"noCache":{"type":"boolean"}},"default":{}}}}},"responses":{"200":{"description":"Build déclenché"},"404":{"description":"Introuvable"}}}},"/services/{id}/logs":{"get":{"tags":["Services"],"summary":"Logs runtime récents du service","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Lignes de log"}}}},"/services/{id}/metrics":{"get":{"tags":["Services"],"summary":"CPU/mémoire instantanés du service","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Snapshot cpu/memory","content":{"application/json":{"schema":{"type":"object","properties":{"cpu":{"type":"number"},"memory":{"type":"number"}},"required":["cpu","memory"]}}}}}}},"/services/{id}/env":{"get":{"tags":["Services"],"summary":"Variables d'environnement du service","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Variables (clé/valeur)","content":{"application/json":{"schema":{"type":"object","properties":{"vars":{"type":"object","additionalProperties":{"type":"string"}}},"required":["vars"]}}}}}},"put":{"tags":["Services"],"summary":"Remplacer les variables d'environnement (redémarrage automatique)","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"vars":{"type":"object","additionalProperties":{"type":"string","maxLength":65536}}},"required":["vars"]}}}},"responses":{"200":{"description":"Variables mises à jour"},"400":{"description":"Corps invalide (vars : nom → texte)"}}}},"/services/{id}/scale":{"put":{"tags":["Services"],"summary":"Fixer le nombre de réplicas (désactive l'autoscaling)","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"replicas":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^-?\\d+$"}]}},"required":["replicas"]}}}},"responses":{"200":{"description":"Réplicas mis à jour"},"400":{"description":"replicas invalide (0–20)"}}}},"/services/{id}/port":{"put":{"tags":["Services"],"summary":"Changer le port du conteneur (redémarrage automatique)","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"port":{"anyOf":[{"type":"number"},{"type":"string","pattern":"^-?\\d+$"}]}},"required":["port"]}}}},"responses":{"200":{"description":"Port mis à jour"},"400":{"description":"Port invalide (1–65535)"}}}},"/services/{id}/command":{"put":{"tags":["Services"],"summary":"Remplacer la commande de démarrage (vide ou null = commande de l'image)","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"command":{"type":"string","nullable":true,"maxLength":4096}}}}}},"responses":{"200":{"description":"Commande mise à jour, redémarrage en cours"}}}},"/services/{id}/domains":{"post":{"tags":["Services"],"summary":"Rattacher un domaine personnalisé au service","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"host":{"type":"string","maxLength":253},"ssl":{"type":"boolean"},"redirectTo":{"type":"string","nullable":true,"maxLength":2048}},"required":["host"]}}}},"responses":{"200":{"description":"Route créée, avec l'état DNS du domaine"},"400":{"description":"Domaine invalide ou service privé"}}}},"/services/{id}/deployments":{"get":{"tags":["Services"],"summary":"Historique des déploiements du service","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Déploiements, plus récents en premier","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Deployment"}}}}}}}},"/services/{id}/deployments/{deploymentId}/rollback":{"post":{"tags":["Services"],"summary":"Revenir à un déploiement antérieur","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string"},"required":true,"name":"deploymentId","in":"path"}],"responses":{"200":{"description":"Rollback déclenché"},"404":{"description":"Déploiement introuvable"}}}},"/domains/check":{"post":{"tags":["Domaines"],"summary":"Vérifier la disponibilité d'un domaine (prix réels Dynadot)","security":[{"ApiKey":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"}},"required":["domain"]}}}},"responses":{"200":{"description":"Résultat de disponibilité + prix"}}}},"/domains":{"get":{"tags":["Domaines"],"summary":"Lister mes domaines","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Domaines du compte","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Domain"}}}}}}}},"/domains/register":{"post":{"tags":["Domaines"],"summary":"Enregistrer un domaine disponible","security":[{"ApiKey":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"}},"required":["domain"]}}}},"responses":{"201":{"description":"Domaine enregistré","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"}}}},"409":{"description":"Domaine déjà enregistré chez webgune"}}}},"/domains/{id}":{"get":{"tags":["Domaines"],"summary":"Détail d'un domaine","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Domaine","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"}}}},"404":{"description":"Introuvable"}}},"delete":{"tags":["Domaines"],"summary":"Supprimer un domaine","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Domaine supprimé"},"404":{"description":"Introuvable"}}}},"/domains/{id}/dns":{"get":{"tags":["Domaines"],"summary":"Lister les enregistrements DNS","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Enregistrements DNS","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/DnsRecord"}}}}}}},"post":{"tags":["Domaines"],"summary":"Ajouter un enregistrement DNS","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DnsRecord"}}}},"responses":{"201":{"description":"Enregistrement ajouté"},"400":{"description":"Enregistrement invalide"}}}},"/domains/{id}/dns/{idx}":{"delete":{"tags":["Domaines"],"summary":"Supprimer un enregistrement DNS par index","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string"},"required":true,"name":"idx","in":"path"}],"responses":{"200":{"description":"Enregistrement supprimé"},"404":{"description":"Introuvable"}}}},"/api-keys":{"get":{"tags":["Clés API"],"summary":"Lister les clés API du compte","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Liste des clés (jamais le secret en clair)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeySummary"}}}}}}},"post":{"tags":["Clés API"],"summary":"Créer une nouvelle clé API","security":[{"ApiKey":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":2,"maxLength":120},"scopes":{"type":"array","items":{"type":"string","pattern":"^(\\*|[a-z][a-z-]*:(read|write|\\*))$"},"minItems":1},"allowActingAs":{"type":"boolean","default":false},"rateLimitPerMinute":{"type":"integer","minimum":1,"maximum":6000,"default":60},"expiresAt":{"type":"string","format":"date-time"}},"required":["name","scopes"]}}}},"responses":{"201":{"description":"Clé créée — `rawKey` n'est renvoyée qu'ici, une seule fois","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ApiKeySummary"},{"type":"object","properties":{"rawKey":{"type":"string"}},"required":["rawKey"]}]}}}},"400":{"description":"Scopes invalides"},"403":{"description":"allowActingAs demandé sans être propriétaire d'organisation"}}}},"/api-keys/{id}":{"delete":{"tags":["Clés API"],"summary":"Révoquer une clé API","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Clé révoquée"},"404":{"description":"Clé introuvable"}}}},"/api-keys/{id}/audit-log":{"get":{"tags":["Clés API"],"summary":"Journal d'audit d'une clé (100 dernières requêtes)","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Entrées d'audit, plus récentes en premier","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyAuditLogEntry"}}}}},"404":{"description":"Clé introuvable"}}}},"/agency/organization":{"get":{"tags":["Agence"],"summary":"Mon organisation (réservé aux propriétaires d'organisation)","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Organisation"},"403":{"description":"Réservé aux agences"}}}},"/agency/sub-clients":{"get":{"tags":["Agence"],"summary":"Lister les sous-clients de mon organisation","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Sous-clients"}}}},"/agency/overview":{"get":{"tags":["Agence"],"summary":"Vue d'ensemble (compteurs projets/services par sous-client)","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Agrégats"}}}},"/alerts":{"get":{"tags":["Alertes"],"summary":"Lister mes règles d'alerte (optionnellement filtrées par service)","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":false,"name":"serviceId","in":"query"}],"responses":{"200":{"description":"Règles","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MetricAlertRule"}}}}}}},"post":{"tags":["Alertes"],"summary":"Créer une règle d'alerte sur une métrique (cpu, memory, disk, network)","security":[{"ApiKey":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"serviceId":{"type":"string","format":"uuid"},"metric":{"type":"string","enum":["cpu","memory","disk","network"]},"thresholdValue":{"type":"number","minimum":0,"exclusiveMinimum":true},"windowSeconds":{"type":"integer","minimum":30,"maximum":3600,"default":60},"cooldownMinutes":{"type":"integer","minimum":5,"maximum":1440,"default":30},"isEnabled":{"type":"boolean","default":true}},"required":["metric","thresholdValue"]}}}},"responses":{"201":{"description":"Règle créée","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MetricAlertRule"}}}},"404":{"description":"Service introuvable"}}}},"/alerts/{id}":{"put":{"tags":["Alertes"],"summary":"Modifier une règle d'alerte","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"thresholdValue":{"type":"number","minimum":0,"exclusiveMinimum":true},"windowSeconds":{"type":"integer","minimum":30,"maximum":3600},"cooldownMinutes":{"type":"integer","minimum":5,"maximum":1440},"isEnabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Règle mise à jour"},"404":{"description":"Règle introuvable"}}},"delete":{"tags":["Alertes"],"summary":"Supprimer une règle d'alerte","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Règle supprimée"},"404":{"description":"Règle introuvable"}}}},"/alerts/{id}/events":{"get":{"tags":["Alertes"],"summary":"Historique des déclenchements d'une règle (100 derniers)","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Événements, plus récents en premier"},"404":{"description":"Règle introuvable"}}}},"/billing/plans":{"get":{"tags":["Facturation"],"summary":"Lister les plans disponibles","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Plans actifs (compte et projet dédié)"}}}},"/billing/subscription":{"get":{"tags":["Facturation"],"summary":"Abonnement actif (compte ou d'un projet via ?projectId=)","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":false,"name":"projectId","in":"query"}],"responses":{"200":{"description":"Abonnement actif, ou null"}}}},"/billing/invoices":{"get":{"tags":["Facturation"],"summary":"Lister mes factures","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Factures du compte"}}}},"/dashboard/stats":{"get":{"tags":["Dashboard"],"summary":"Statistiques agrégées du compte (services, CPU/mémoire vs limites du plan)","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Compteurs d'usage courant + limites du plan actif","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DashboardStats"}}}}}}},"/dashboard/deployment-history":{"get":{"tags":["Dashboard"],"summary":"Historique des déploiements (30 derniers jours, agrégé par jour)","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Séries temporelles succès/échecs par jour"}}}},"/dashboard/overview":{"get":{"tags":["Dashboard"],"summary":"Accueil du dashboard en un appel : projets, stats, historique, abonnement, domaines, indicateurs, trafic 24 h","security":[{"ApiKey":[]}],"responses":{"200":{"description":"Chaque bloc vaut null s'il est momentanément indisponible ; `pending` liste ceux encore en calcul (à redemander dans un instant)"}}}},"/dashboard/services/{id}/metrics/history":{"get":{"tags":["Dashboard"],"summary":"Historique d'une métrique (cpu, memory, disk, network) pour un service","security":[{"ApiKey":[]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","enum":["cpu","memory","disk","network"]},"required":true,"name":"metric","in":"query"},{"schema":{"type":"string","enum":["1h","6h","24h","7d","14d"]},"required":false,"name":"range","in":"query"}],"responses":{"200":{"description":"Points {t, v} sur la plage demandée","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"t":{"type":"number"},"v":{"type":"number"}},"required":["t","v"]}}}}},"400":{"description":"metric invalide"},"404":{"description":"Service introuvable"}}}}}}