feat(domains): add enable/disable toggle for domains

Add an `enabled` flag (default true) so a domain can be switched off
without deleting it, preserving its configuration.

- schema: new `enabled` column + migration; added to apiUpdateDomain
- traefik (applications): guard manageDomain so a disabled domain never
  exposes a router from any caller (create/update/forward-auth/toggle);
  applies instantly through the file provider
- compose: skip disabled domains when generating docker labels, so the
  change applies on the next deployment
- tRPC: new domain.toggleEnable procedure (permission-checked + audited),
  returns requiresRedeploy for compose domains
- UI: switch on the domain card (host row, variant E) and a Status column
  in the table view; disabled cards are dimmed; reuses the compose
  redeploy hint for the toast

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
This commit is contained in:
Vyacheslav Scherbinin
2026-07-13 18:12:29 +07:00
co-authored by Claude Opus 4.8
parent 898af1f74c
commit ee802cd54c
9 changed files with 8725 additions and 11 deletions
+2 -1
View File
@@ -161,7 +161,8 @@ export const addDomainToCompose = async (
result = randomized;
}
for (const domain of domains) {
// Disabled domains keep their config but must not produce any traefik labels.
for (const domain of domains.filter((d) => d.enabled)) {
const { serviceName, https } = domain;
if (!serviceName) {
throw new Error(`Domain "${domain.host}" is missing a service name`);
@@ -19,6 +19,15 @@ import { createPathMiddlewares, removePathMiddlewares } from "./middleware";
export const manageDomain = async (app: ApplicationNested, domain: Domain) => {
const { appName } = app;
// A disabled domain keeps its configuration in the database but must never
// expose a traefik router. Guarding here covers every caller (create, update,
// forward-auth, toggle) so a disabled domain can't be revived from any path.
if (!domain.enabled) {
await removeDomain(app, domain.uniqueConfigKey);
return;
}
let config: FileConfig;
if (app.serverId) {