TypeScript/Bun project scaffold

- Stack: Bun, Hono, Drizzle ORM, Zod, Handlebars, Pino
- Models: ticket, queue, transaction, scrip, template, custom_field, user, lifecycle
- Scrip engine: prepare/commit two-phase dispatch, template rendering, mock actions
- Lifecycle validator: state machine transition validation with wildcard support
- Routes: health, tickets (full CRUD + preview + transactions), queues, scrips, custom-fields, lifecycles
- Middleware: Pino logging, error handler
- Database: Drizzle ORM schema + initial migration (10 tables)
- Type-check: passes (tsc --noEmit, zero errors)
This commit is contained in:
Gjermund Høsøien Wiggen
2026-06-07 21:21:50 +02:00
parent 7be1810162
commit 1136227510
35 changed files with 2595 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
export interface LifecycleDefinition {
statuses: {
initial: string[];
active: string[];
inactive: string[];
};
transitions: Record<string, string[]>;
}
export interface ValidationResult {
valid: boolean;
error?: string;
}
export class LifecycleValidator {
validateTransition(
lifecycleDef: LifecycleDefinition,
fromStatus: string,
toStatus: string,
): ValidationResult {
const allStatuses = [
...lifecycleDef.statuses.initial,
...lifecycleDef.statuses.active,
...lifecycleDef.statuses.inactive,
];
if (!allStatuses.includes(toStatus)) {
return {
valid: false,
error: `Status "${toStatus}" is not defined in the lifecycle`,
};
}
// Check for allowed transitions
const allowedTransitions = this.getAllowedTransitions(lifecycleDef, fromStatus);
if (allowedTransitions.includes(toStatus)) {
return { valid: true };
}
// Also handle wildcard "*" -> any transition
const wildcardTransitions = this.getAllowedTransitions(lifecycleDef, '*');
if (wildcardTransitions.includes(toStatus)) {
return { valid: true };
}
return {
valid: false,
error: `Transition from "${fromStatus}" to "${toStatus}" is not allowed`,
};
}
isResolvedStatus(lifecycleDef: LifecycleDefinition, status: string): boolean {
return lifecycleDef.statuses.inactive.includes(status);
}
private getAllowedTransitions(
lifecycleDef: LifecycleDefinition,
fromStatus: string,
): string[] {
// Direct transition
if (lifecycleDef.transitions[fromStatus]) {
return lifecycleDef.transitions[fromStatus]!;
}
// Wildcard transitions
if (lifecycleDef.transitions['*']) {
return lifecycleDef.transitions['*']!;
}
return [];
}
}