feat: add infrastructure foundation — scripts, schema key, new routes, model fields

- Add npm scripts for dev, migrate, seed, smoke
- Add key column to scrips table (unique short identifier)
- Register users and templates routes in server
- Set development: false in Bun.serve for production mode
- Add description and custom_fields to CreateTicketSchema
- Make owner_id nullable/optional for unassigned tickets
- Add migration for custom field key column

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Gjermund Høsøien Wiggen
2026-06-09 10:42:42 +02:00
parent 599ca75fc4
commit 9e884546f2
6 changed files with 34 additions and 2 deletions

View File

@@ -0,0 +1,10 @@
ALTER TABLE "custom_fields" ADD COLUMN "key" text;
--> statement-breakpoint
UPDATE "custom_fields"
SET "key" = trim(both '_' from regexp_replace(lower("name"), '[^a-z0-9]+', '_', 'g'));
--> statement-breakpoint
UPDATE "custom_fields" SET "key" = 'field_' || substring("id"::text, 1, 8) WHERE "key" IS NULL OR "key" = '';
--> statement-breakpoint
ALTER TABLE "custom_fields" ALTER COLUMN "key" SET NOT NULL;
--> statement-breakpoint
ALTER TABLE "custom_fields" ADD CONSTRAINT "custom_fields_key_unique" UNIQUE("key");

View File

@@ -15,6 +15,13 @@
"when": 1780867177929,
"tag": "0001_lovely_quentin_quire",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1780904200000,
"tag": "0002_short_custom_field_keys",
"breakpoints": true
}
]
}

View File

@@ -3,6 +3,13 @@
"module": "src/index.ts",
"type": "module",
"private": true,
"scripts": {
"dev:backend": "bun run src/index.ts",
"db:migrate": "bun run src/db/migrate.ts",
"db:seed": "bun run src/db/seed.ts",
"db:seed:reset": "bun run src/db/seed.ts --reset",
"smoke": "bun run scripts/smoke-test.ts"
},
"devDependencies": {
"@types/bun": "latest",
"@types/handlebars": "^4.1.0",

View File

@@ -83,6 +83,7 @@ export const scrips = pgTable('scrips', {
export const customFields = pgTable('custom_fields', {
id: uuid('id').primaryKey().defaultRandom(),
key: text('key').notNull().unique(),
name: text('name').notNull(),
field_type: text('field_type').notNull(),
values: jsonb('values'),

View File

@@ -10,6 +10,8 @@ import { createQueuesRouter } from './routes/queues.ts';
import { createScripsRouter } from './routes/scrips.ts';
import { createCustomFieldsRouter } from './routes/custom-fields.ts';
import { createLifecyclesRouter } from './routes/lifecycles.ts';
import { createUsersRouter } from './routes/users.ts';
import { createTemplatesRouter } from './routes/templates.ts';
let db: Db | null = null;
@@ -31,6 +33,8 @@ app.route('/queues', createQueuesRouter(getDb()));
app.route('/scrips', createScripsRouter(getDb()));
app.route('/custom-fields', createCustomFieldsRouter(getDb()));
app.route('/lifecycles', createLifecyclesRouter(getDb()));
app.route('/users', createUsersRouter(getDb()));
app.route('/templates', createTemplatesRouter(getDb()));
export default app;
export { app };
@@ -41,6 +45,7 @@ if (Bun.main === import.meta.path) {
fetch: app.fetch,
port: config.SERVER_PORT,
hostname: config.SERVER_HOST,
development: false,
});
console.log(`Server running at http://${config.SERVER_HOST}:${config.SERVER_PORT}`);
}

View File

@@ -7,12 +7,14 @@ export type Ticket = InferSelectModel<typeof tickets>;
export const CreateTicketSchema = z.object({
subject: z.string().min(1),
queue_id: z.string().uuid(),
description: z.string().trim().optional(),
custom_fields: z.record(z.string(), z.string()).optional(),
});
export const UpdateTicketSchema = z.object({
subject: z.string().min(1).optional(),
status: z.string().min(1).optional(),
owner_id: z.string().uuid().optional(),
owner_id: z.string().uuid().nullable().optional(),
});
export const CommentSchema = z.object({