diff --git a/apps/native/src/app/(tabs)/(settings)/index.tsx b/apps/native/src/app/(tabs)/(settings)/index.tsx
index 5aa0871..5cbd864 100644
--- a/apps/native/src/app/(tabs)/(settings)/index.tsx
+++ b/apps/native/src/app/(tabs)/(settings)/index.tsx
@@ -86,7 +86,7 @@ export default function SettingsScreen() {
hasPassword && !(authConfig.data?.passwordLoginDisabled ?? true);
const systemHealth = useQuery({
- ...orpc.system.health.queryOptions(),
+ ...orpc.admin.systemHealth.queryOptions(),
enabled: isAdmin,
});
diff --git a/apps/server/src/orpc/procedures/admin.ts b/apps/server/src/orpc/procedures/admin.ts
index 23e8cd1..01d188b 100644
--- a/apps/server/src/orpc/procedures/admin.ts
+++ b/apps/server/src/orpc/procedures/admin.ts
@@ -13,6 +13,7 @@ import {
purgeMetadataCache as purgeMetadataFn,
} from "@sofa/core/cache";
import { getSetting, setSetting } from "@sofa/core/settings";
+import { getSystemHealth } from "@sofa/core/system-health";
import { isTelemetryEnabled } from "@sofa/core/telemetry";
import {
getCachedUpdateCheck,
@@ -173,3 +174,11 @@ export const purgeMetadataCache = os.admin.purgeMetadataCache
export const purgeImageCache = os.admin.purgeImageCache
.use(admin)
.handler(async () => purgeImagesFn());
+
+// ─── System Health ───────────────────────────────────────────────
+
+export const systemHealth = os.admin.systemHealth
+ .use(admin)
+ .handler(async () => {
+ return await getSystemHealth();
+ });
diff --git a/apps/server/src/orpc/procedures/status.ts b/apps/server/src/orpc/procedures/status.ts
index 83a523e..ce78d7b 100644
--- a/apps/server/src/orpc/procedures/status.ts
+++ b/apps/server/src/orpc/procedures/status.ts
@@ -1,15 +1,8 @@
-import { getSystemHealth } from "@sofa/core/system-health";
-import { isTmdbConfigured } from "@sofa/tmdb/config";
import { os } from "../context";
-import { admin, authed } from "../middleware";
+import { authed } from "../middleware";
export const status = os.system.status.use(authed).handler(() => {
return {
- tmdbConfigured: isTmdbConfigured(),
publicApiUrl: process.env.PUBLIC_API_URL || "https://public-api.sofa.watch",
};
});
-
-export const health = os.system.health.use(admin).handler(async () => {
- return await getSystemHealth();
-});
diff --git a/apps/server/src/orpc/router.ts b/apps/server/src/orpc/router.ts
index eff6e0d..84d3efc 100644
--- a/apps/server/src/orpc/router.ts
+++ b/apps/server/src/orpc/router.ts
@@ -55,7 +55,6 @@ export const implementedRouter = {
publicInfo: system.publicInfo,
authConfig: system.authConfig,
status: status.status,
- health: status.health,
},
integrations: {
list: integrations.list,
@@ -81,6 +80,7 @@ export const implementedRouter = {
triggerJob: admin.triggerJob,
purgeMetadataCache: admin.purgeMetadataCache,
purgeImageCache: admin.purgeImageCache,
+ systemHealth: admin.systemHealth,
},
account: {
updateName: account.updateName,
diff --git a/apps/web/src/components/settings/danger-section.tsx b/apps/web/src/components/settings/danger-section.tsx
index d01223c..b8cf928 100644
--- a/apps/web/src/components/settings/danger-section.tsx
+++ b/apps/web/src/components/settings/danger-section.tsx
@@ -29,7 +29,7 @@ export function CacheSection() {
const queryClient = useQueryClient();
const invalidateHealth = () =>
- queryClient.invalidateQueries({ queryKey: orpc.system.health.key() });
+ queryClient.invalidateQueries({ queryKey: orpc.admin.systemHealth.key() });
const purgeMetadata = useMutation(
orpc.admin.purgeMetadataCache.mutationOptions({
diff --git a/apps/web/src/components/settings/system-health-section.tsx b/apps/web/src/components/settings/system-health-section.tsx
index 78fcd87..0d02e2d 100644
--- a/apps/web/src/components/settings/system-health-section.tsx
+++ b/apps/web/src/components/settings/system-health-section.tsx
@@ -130,11 +130,11 @@ function LiveTimeAgo({
export function SystemHealthCards() {
const queryClient = useQueryClient();
const { data, isPending, isFetching } = useQuery(
- orpc.system.health.queryOptions(),
+ orpc.admin.systemHealth.queryOptions(),
);
const isRefreshing = isFetching;
const refresh = () =>
- queryClient.invalidateQueries({ queryKey: orpc.system.health.key() });
+ queryClient.invalidateQueries({ queryKey: orpc.admin.systemHealth.key() });
if (isPending || !data) return ;
diff --git a/docs/content/docs/api/system/system.health.mdx b/docs/content/docs/api/admin/admin.systemHealth.mdx
similarity index 75%
rename from docs/content/docs/api/system/system.health.mdx
rename to docs/content/docs/api/admin/admin.systemHealth.mdx
index c7d918d..df7147d 100644
--- a/docs/content/docs/api/system/system.health.mdx
+++ b/docs/content/docs/api/admin/admin.systemHealth.mdx
@@ -9,11 +9,11 @@ _openapi:
contents:
- content: >-
Comprehensive health check covering database, TMDB connectivity, cron
- jobs, image cache, backups, and environment. Admin only.
+ jobs, image cache, backups, and environment.
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
-Comprehensive health check covering database, TMDB connectivity, cron jobs, image cache, backups, and environment. Admin only.
+Comprehensive health check covering database, TMDB connectivity, cron jobs, image cache, backups, and environment.
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/docs/content/docs/api/system/system.status.mdx b/docs/content/docs/api/system/system.status.mdx
index 1bbc40e..8eac90e 100644
--- a/docs/content/docs/api/system/system.status.mdx
+++ b/docs/content/docs/api/system/system.status.mdx
@@ -1,5 +1,5 @@
---
-title: Get system status
+title: Get internal system config
full: true
_openapi:
method: GET
@@ -8,12 +8,12 @@ _openapi:
headings: []
contents:
- content: >-
- Quick check of whether TMDB is configured. Does not require
+ Returns internal configuration such as the public API URL. Requires
authentication.
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
-Quick check of whether TMDB is configured. Does not require authentication.
+Returns internal configuration such as the public API URL. Requires authentication.
\ No newline at end of file
diff --git a/docs/public/openapi.json b/docs/public/openapi.json
index 4c481d5..9390882 100644
--- a/docs/public/openapi.json
+++ b/docs/public/openapi.json
@@ -4287,60 +4287,28 @@
"/system/status": {
"get": {
"operationId": "system.status",
- "summary": "Get system status",
- "description": "Quick check of whether TMDB is configured. Does not require authentication.",
+ "summary": "Get internal system config",
+ "description": "Returns internal configuration such as the public API URL. Requires authentication.",
"tags": [
"System"
],
"responses": {
"200": {
- "description": "TMDB configuration status",
+ "description": "Internal system configuration",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
- "tmdbConfigured": {
- "type": "boolean",
- "description": "Whether a TMDB API token is configured"
- },
"publicApiUrl": {
"type": "string",
"description": "Base URL of the centralized public API"
}
},
"required": [
- "tmdbConfigured",
"publicApiUrl"
],
- "description": "Quick TMDB configuration check"
- }
- }
- }
- }
- },
- "security": [
- {
- "session": []
- }
- ]
- }
- },
- "/system/health": {
- "get": {
- "operationId": "system.health",
- "summary": "Get system health report",
- "description": "Comprehensive health check covering database, TMDB connectivity, cron jobs, image cache, backups, and environment. Admin only.",
- "tags": [
- "System"
- ],
- "responses": {
- "200": {
- "description": "Full system health report",
- "content": {
- "application/json": {
- "schema": {
- "$ref": "#/components/schemas/SystemHealth"
+ "description": "Internal system configuration for authenticated clients"
}
}
}
@@ -5620,6 +5588,33 @@
]
}
},
+ "/admin/system-health": {
+ "get": {
+ "operationId": "admin.systemHealth",
+ "summary": "Get system health report",
+ "description": "Comprehensive health check covering database, TMDB connectivity, cron jobs, image cache, backups, and environment.",
+ "tags": [
+ "Admin"
+ ],
+ "responses": {
+ "200": {
+ "description": "Full system health report",
+ "content": {
+ "application/json": {
+ "schema": {
+ "$ref": "#/components/schemas/SystemHealth"
+ }
+ }
+ }
+ }
+ },
+ "security": [
+ {
+ "session": []
+ }
+ ]
+ }
+ },
"/account/name": {
"put": {
"operationId": "account.updateName",
@@ -5831,10 +5826,12 @@
},
"watchedAt": {
"type": "string",
+ "format": "date-time",
"description": "ISO 8601 timestamp"
},
"watchedOn": {
"type": "string",
+ "format": "date",
"description": "YYYY-MM-DD date-only"
}
},
@@ -5865,16 +5862,22 @@
"type": "number"
},
"seasonNumber": {
- "type": "number"
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 9007199254740991
},
"episodeNumber": {
- "type": "number"
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 9007199254740991
},
"watchedAt": {
- "type": "string"
+ "type": "string",
+ "format": "date-time"
},
"watchedOn": {
- "type": "string"
+ "type": "string",
+ "format": "date"
}
},
"required": [
@@ -5951,10 +5954,12 @@
"description": "Sofa 1-5 star rating"
},
"ratedAt": {
- "type": "string"
+ "type": "string",
+ "format": "date-time"
},
"ratedOn": {
- "type": "string"
+ "type": "string",
+ "format": "date"
}
},
"required": [
@@ -6087,10 +6092,12 @@
},
"watchedAt": {
"type": "string",
+ "format": "date-time",
"description": "ISO 8601 timestamp"
},
"watchedOn": {
"type": "string",
+ "format": "date",
"description": "YYYY-MM-DD date-only"
}
},
@@ -6121,16 +6128,22 @@
"type": "number"
},
"seasonNumber": {
- "type": "number"
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 9007199254740991
},
"episodeNumber": {
- "type": "number"
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 9007199254740991
},
"watchedAt": {
- "type": "string"
+ "type": "string",
+ "format": "date-time"
},
"watchedOn": {
- "type": "string"
+ "type": "string",
+ "format": "date"
}
},
"required": [
@@ -6207,10 +6220,12 @@
"description": "Sofa 1-5 star rating"
},
"ratedAt": {
- "type": "string"
+ "type": "string",
+ "format": "date-time"
},
"ratedOn": {
- "type": "string"
+ "type": "string",
+ "format": "date"
}
},
"required": [
@@ -6276,10 +6291,12 @@
},
"watchedAt": {
"type": "string",
+ "format": "date-time",
"description": "ISO 8601 timestamp"
},
"watchedOn": {
"type": "string",
+ "format": "date",
"description": "YYYY-MM-DD date-only"
}
},
@@ -6310,16 +6327,22 @@
"type": "number"
},
"seasonNumber": {
- "type": "number"
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 9007199254740991
},
"episodeNumber": {
- "type": "number"
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 9007199254740991
},
"watchedAt": {
- "type": "string"
+ "type": "string",
+ "format": "date-time"
},
"watchedOn": {
- "type": "string"
+ "type": "string",
+ "format": "date"
}
},
"required": [
@@ -6396,10 +6419,12 @@
"description": "Sofa 1-5 star rating"
},
"ratedAt": {
- "type": "string"
+ "type": "string",
+ "format": "date-time"
},
"ratedOn": {
- "type": "string"
+ "type": "string",
+ "format": "date"
}
},
"required": [
@@ -6532,10 +6557,12 @@
},
"watchedAt": {
"type": "string",
+ "format": "date-time",
"description": "ISO 8601 timestamp"
},
"watchedOn": {
"type": "string",
+ "format": "date",
"description": "YYYY-MM-DD date-only"
}
},
@@ -6566,16 +6593,22 @@
"type": "number"
},
"seasonNumber": {
- "type": "number"
+ "type": "integer",
+ "minimum": 0,
+ "maximum": 9007199254740991
},
"episodeNumber": {
- "type": "number"
+ "type": "integer",
+ "minimum": 1,
+ "maximum": 9007199254740991
},
"watchedAt": {
- "type": "string"
+ "type": "string",
+ "format": "date-time"
},
"watchedOn": {
- "type": "string"
+ "type": "string",
+ "format": "date"
}
},
"required": [
@@ -6652,10 +6685,12 @@
"description": "Sofa 1-5 star rating"
},
"ratedAt": {
- "type": "string"
+ "type": "string",
+ "format": "date-time"
},
"ratedOn": {
- "type": "string"
+ "type": "string",
+ "format": "date"
}
},
"required": [
@@ -7145,7 +7180,8 @@
"type": {
"enum": [
"progress",
- "complete"
+ "complete",
+ "timeout"
]
},
"job": {
diff --git a/packages/api/src/contract.ts b/packages/api/src/contract.ts
index 64676f8..40316fa 100644
--- a/packages/api/src/contract.ts
+++ b/packages/api/src/contract.ts
@@ -406,23 +406,12 @@ export const contract = {
method: "GET",
path: "/system/status",
tags: ["System"],
- summary: "Get system status",
+ summary: "Get internal system config",
description:
- "Quick check of whether TMDB is configured. Does not require authentication.",
- successDescription: "TMDB configuration status",
+ "Returns internal configuration such as the public API URL. Requires authentication.",
+ successDescription: "Internal system configuration",
})
.output(SystemStatusOutput),
- health: oc
- .route({
- method: "GET",
- path: "/system/health",
- tags: ["System"],
- summary: "Get system health report",
- description:
- "Comprehensive health check covering database, TMDB connectivity, cron jobs, image cache, backups, and environment. Admin only.",
- successDescription: "Full system health report",
- })
- .output(SystemHealthOutput),
},
integrations: {
list: oc
@@ -653,6 +642,17 @@ export const contract = {
})
.input(z.void())
.output(PurgeImageCacheOutput),
+ systemHealth: oc
+ .route({
+ method: "GET",
+ path: "/admin/system-health",
+ tags: ["Admin"],
+ summary: "Get system health report",
+ description:
+ "Comprehensive health check covering database, TMDB connectivity, cron jobs, image cache, backups, and environment.",
+ successDescription: "Full system health report",
+ })
+ .output(SystemHealthOutput),
},
account: {
updateName: oc
diff --git a/packages/api/src/schemas.ts b/packages/api/src/schemas.ts
index 12b1a4e..f5f66bd 100644
--- a/packages/api/src/schemas.ts
+++ b/packages/api/src/schemas.ts
@@ -884,12 +884,11 @@ export const SystemHealthSchema = z
export const SystemStatusOutput = z
.object({
- tmdbConfigured: z
- .boolean()
- .describe("Whether a TMDB API token is configured"),
publicApiUrl: z.string().describe("Base URL of the centralized public API"),
})
- .meta({ description: "Quick TMDB configuration check" });
+ .meta({
+ description: "Internal system configuration for authenticated clients",
+ });
export const SystemHealthOutput = SystemHealthSchema;