{"openapi":"3.1.0","info":{"title":"SYSINFRA Status API","version":"1.0.0","description":"Public Status-API für SYSINFRA-Dienste. Aggregiert Probe-Daten von mehreren Vantage-Points (FSN/NBG/CH) plus Editorial-Inhalte (Incidents/Maintenance) aus dem Payload-CMS.","contact":{"name":"SYSINFRA","email":"support@sysinfra.ch","url":"https://sysinfra.ch"},"license":{"name":"Proprietary"}},"servers":[{"url":"https://api.sysinfra.ch","description":"Production"}],"paths":{"/v1/status":{"get":{"summary":"Aggregierter Status-Snapshot","description":"Liefert Service-Groups mit aktuellem Status, 90-Tage-Bars, aktive Incidents und bevorstehende Wartungen. ETag-fähig: bei If-None-Match → 304.","responses":{"200":{"description":"Aktueller Status","headers":{"ETag":{"description":"Stable revision-hash, wechselt nur bei inhaltlichen Änderungen.","schema":{"type":"string"}},"Cache-Control":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StatusSnapshot"}}}},"304":{"description":"Nicht modifiziert (ETag matched)"}}}},"/v1/status/rss":{"get":{"summary":"RSS-Feed mit Incidents + Wartungen","responses":{"200":{"description":"RSS 2.0","content":{"application/rss+xml":{"schema":{"type":"string"}}}}}}},"/v1/incidents":{"get":{"summary":"Liste aller Incidents (filterbar)","parameters":[{"name":"since","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"status","in":"query","schema":{"type":"string","enum":["investigating","identified","monitoring","resolved"]}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"Incident-Liste","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Incident"}}}}}}}}}},"/v1/maintenance":{"get":{"summary":"Liste der Wartungen","parameters":[{"name":"upcoming","in":"query","schema":{"type":"boolean"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}}],"responses":{"200":{"description":"Wartungen"}}}},"/v1/upstream":{"get":{"summary":"Upstream-Provider-Status (Hetzner, Cloudflare, M365, Swisscom)","responses":{"200":{"description":"Provider-Liste"}}}},"/v1/status/subscribe":{"post":{"summary":"Email für Status-Notifications abonnieren (Double-Opt-In)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"scope":{"type":"string","description":"'all' (default) oder Service-Group-ID","default":"all"}}}}}},"responses":{"200":{"description":"Bereits aktiv abonniert (kein Re-Send)"},"202":{"description":"DOI-Mail versendet"},"400":{"description":"Validation-Fehler"},"429":{"description":"Rate-Limit überschritten (5/min/IP)"},"502":{"description":"Mailversand fehlgeschlagen"}}}},"/v1/status/subscribe/confirm":{"post":{"summary":"Email-Abonnement bestätigen","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string"}}}}}},"responses":{"200":{"description":"Bestätigt"},"400":{"description":"Token ungültig/abgelaufen"}}}},"/v1/status/unsubscribe":{"post":{"summary":"Abonnement abbestellen","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["token"],"properties":{"token":{"type":"string"}}}}}},"responses":{"200":{"description":"Abbestellt"}}}}},"components":{"schemas":{"StatusSnapshot":{"type":"object","properties":{"version":{"type":"string","enum":["v1"]},"generatedAt":{"type":"string","format":"date-time"},"stale":{"type":"boolean"},"staleReason":{"type":["string","null"]},"overallStatus":{"type":"string","enum":["ok","degraded","down"]},"uptime90dPct":{"type":["number","null"],"description":"null wenn Coverage < 7 erfasste Tage"},"activeIncidents":{"type":"integer"},"scheduledMaintenanceCount":{"type":"integer"},"nextMaintenanceAt":{"type":["string","null"],"format":"date-time"},"incidents":{"type":"array","items":{"$ref":"#/components/schemas/Incident"}},"maintenanceWindows":{"type":"array","items":{"$ref":"#/components/schemas/MaintenanceWindow"}},"serviceGroups":{"type":"array","items":{"$ref":"#/components/schemas/ServiceGroup"}},"upstreamProviders":{"type":"array","items":{"$ref":"#/components/schemas/UpstreamProvider"}}}},"Incident":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"title":{"type":"string"},"severity":{"type":"string","enum":["minor","major","critical"]},"status":{"type":"string","enum":["investigating","identified","monitoring","resolved"]},"affectedServices":{"type":"array","items":{"type":"string"}},"customerImpact":{"type":"string"},"startedAt":{"type":"string","format":"date-time"},"resolvedAt":{"type":["string","null"],"format":"date-time"},"timeline":{"type":"array","items":{"type":"object"}},"postmortemUrl":{"type":["string","null"]}}},"MaintenanceWindow":{"type":"object","properties":{"id":{"type":"string"},"slug":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"affectedServices":{"type":"array","items":{"type":"string"}},"scheduledStart":{"type":"string","format":"date-time"},"scheduledEnd":{"type":"string","format":"date-time"},"expectedImpact":{"type":"string"},"status":{"type":"string","enum":["scheduled","in-progress","completed","canceled"]}}},"ServiceGroup":{"type":"object","properties":{"id":{"type":"string"},"displayName":{"type":"string"},"uptime90dPct":{"type":["number","null"],"description":"null wenn keine Service in der Gruppe genug Coverage hat"},"services":{"type":"array","items":{"$ref":"#/components/schemas/Service"}}}},"Service":{"type":"object","properties":{"id":{"type":"string"},"displayName":{"type":"string"},"description":{"type":"string"},"currentStatus":{"type":"string","enum":["ok","degraded","down","unknown"]},"uptime90dPct":{"type":["number","null"],"description":"null wenn coverageDays < 7 — UI zeigt \"—\""},"coverageDays":{"type":"integer","minimum":0,"maximum":90,"description":"Anzahl der Tage im 90d-Fenster mit Probe-Daten"},"bars90d":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string","format":"date"},"status":{"type":"string","enum":["ok","degraded","down","no_data"]},"uptimePct":{"type":["number","null"],"minimum":0,"maximum":100}}}},"byVantagePoint":{"type":"object"}}},"UpstreamProvider":{"type":"object","properties":{"id":{"type":"string"},"displayName":{"type":"string"},"status":{"type":"string","enum":["ok","degraded","down","unknown"]},"sourceUrl":{"type":"string"},"lastPolledAt":{"type":["string","null"],"format":"date-time"},"activeIncidents":{"type":"integer"}}}}}}