ThreadCount Community edition

Uniform stock management for healthcare linen rooms. Licensed under the GNU AGPL v3.
This commit is contained in:
ThreadCount
2026-09-13 08:45:19 +10:00
commit 1bc2de655a
505 changed files with 56223 additions and 0 deletions
+29
View File
@@ -0,0 +1,29 @@
import type { Metadata } from "next";
import { headers } from "next/headers";
import { notFound } from "next/navigation";
/* The operations console lives under /ops and is served only on ops.threadcount.tech.
*
* proxy.ts already refuses /ops on every other hostname, but the proxy is not the only guard: a
* matcher change can silently remove its coverage, so the host is checked here again, from the
* request headers, before anything under this layout renders. Same comparison as the proxy —
* exact, lower-cased, port-stripped, never `includes`.
*
* Every page under here is dynamic. ISR is not keyed by host, so a cached ops page could be
* served on threadcount.tech; `force-dynamic` on the layout keeps the whole subtree out of the
* prerender cache. */
export const dynamic = "force-dynamic";
export const metadata: Metadata = {
title: { default: "ThreadCount ops", template: "%s — ThreadCount ops" },
robots: { index: false, follow: false },
};
const OPS_HOST = "ops.threadcount.tech";
export default async function OpsLayout({ children }: { children: React.ReactNode }) {
const h = await headers();
const host = (h.get("x-forwarded-host") ?? h.get("host") ?? "").split(":")[0].toLowerCase();
if (host !== OPS_HOST) notFound();
return <div className="tc-ops" role="main">{children}</div>;
}