refactor(automation): trim the branch to reduce risk

Adoption is low, and the app must not be put at risk fixing that. A measured
look at the diff showed the risk was concentrated in exactly two places: the
timer's hot path and a new file-writing route. Everything that actually makes
automations discoverable — recipes, a panel that explains itself, one-step
creation, Test buttons that report — is client-only settings-panel code with
zero server churn. This cuts the two pieces that weren't, and simplifies two
more that only existed to serve them.

Removed entirely: templates. Newest, riskiest, and the least connected to the
adoption problem — it helps someone who already uses automations share them,
not someone who has never tried the feature. It was also the source of two of
the bugs found in review.

Removed: the websocket broadcast behind "last fired". reportFired ran inside
triggerAutomations, called from onClock every second and from onUpdate. A new
protocol message pushed to every connected client, including stage displays,
up to once a second per automation, is real new traffic on the busiest code
path in the app for a feature still trying to prove it's worth using. The log
line stays: it's additive, throttled, nowhere near the hot path once written,
and answers the same question — did this run — without a new message.

Trimmed: the demo goes from two automations tied together by necessity — a
danger-time message and a second automation whose only job was undoing the
first on finish — to one, attached by an event-level trigger instead of a
global one. Same two discovery wins, an automation visibly fires on Play and
per-event triggers are found by opening an event, with no message mutation
and nothing to keep in sync. That pairing was also the first thing review
found broken.

Trimmed: the delete dialog no longer deletes blocking triggers and restores
them if the automation still won't delete. That rollback was the other
multi-request destructive sequence review found a bug in. It now confirms,
names what's blocking, and says to remove global triggers from the Global
Triggers list first — a single always-safe request the user already has.

What stays: one-step creation (lifecycles picked on the automation form), the
recipe library, and the panel legibility work — none of it touches the server
or the runtime.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LpbLJVVT26tzWkduck1M9H
This commit is contained in:
Claude
2026-08-08 21:12:26 +00:00
parent cdde054b14
commit ed39f86a81
21 changed files with 40 additions and 725 deletions
-20
View File
@@ -4,23 +4,3 @@ export interface QuickStartData {
project: Pick<DatabaseModel['project'], 'title'>;
settings: Pick<DatabaseModel['settings'], 'timeFormat' | 'language'>;
}
/**
* Sections of a project that can be cloned on their own into a template project:
* a small project holding, say, only automations, which can be shared and then
* applied to another project with a partial load
*/
export const templateSections = [
'project',
'rundowns',
'customFields',
'viewSettings',
'urlPresets',
'automation',
] as const satisfies ReadonlyArray<keyof DatabaseModel>;
export type TemplateSection = (typeof templateSections)[number];
export function isTemplateSection(value: string): value is TemplateSection {
return (templateSections as ReadonlyArray<string>).includes(value);
}
+1 -13
View File
@@ -1,5 +1,4 @@
import type { Client } from '../../definitions/Clients.type.js';
import type { TimerLifeCycle } from '../../definitions/core/TimerLifecycle.type.js';
import type { Log } from '../../definitions/runtime/Logger.type.js';
import type { RuntimeStore } from '../../definitions/runtime/RuntimeStore.type.js';
import type { MaybeNumber } from '../../utils/utils.type.js';
@@ -18,7 +17,6 @@ export enum MessageTag {
Log = 'log',
RuntimeData = 'runtime-data',
Refetch = 'refetch',
AutomationFired = 'automation-fired',
}
// CLIENT TO SERVER
@@ -38,15 +36,6 @@ type ListClientPacket = {
};
type RuntimePacket = { tag: MessageTag.RuntimeData; payload: Partial<RuntimeStore> };
/**
* Reports that an automation ran, so clients can show it is alive.
* Coalesced server side: high frequency lifecycles do not send one of these per fire.
*/
type AutomationFiredPacket = {
tag: MessageTag.AutomationFired;
payload: { automationId: string; cycle: TimerLifeCycle };
};
type RefetchPacket = {
tag: MessageTag.Refetch;
payload: {
@@ -69,5 +58,4 @@ export type WsPacketToClient =
| LogPacket
| ListClientPacket
| RuntimePacket
| RefetchPacket
| AutomationFiredPacket;
| RefetchPacket;
+1 -2
View File
@@ -66,8 +66,7 @@ export type {
} from './definitions/core/CustomFields.type.js';
// SERVER RESPONSES
export type { QuickStartData, TemplateSection } from './api/db/db.type.js';
export { templateSections, isTemplateSection } from './api/db/db.type.js';
export type { QuickStartData } from './api/db/db.type.js';
export type {
AuthenticationStatus,
NetworkInterface,