Files
shiftcraft/server/api/schedules/solve.post.ts
Clanker 36e0946ee4 feat: complete ShiftCraft — AI-powered shift scheduling SaaS
Complete implementation including:
- Landing page with hero, features, how-it-works, pricing
- Employee management (CRUD with soft delete)
- AI constraint parser (Anthropic Claude API)
- German labor law templates (ArbZG §3, §5, §9)
- HiGHS ILP solver for optimal fair schedules
- Schedule calendar result view (employee × date grid)
- Shift framework configuration (periods + shifts)
- Subscription tiers: Free / Pro / Business
- PocketBase setup script with collection creation + seed data
- .env.example with all required variables documented

Pages: employees, constraints (list/new/templates), schedules (list/new/[id]),
       settings (organization/shifts/billing), dashboard

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-18 07:47:31 +02:00

48 lines
1.5 KiB
TypeScript

import { getPBAdminClient } from '~/server/utils/pb-admin'
import { solveSchedule } from '~/server/utils/solver'
import type { SolveInput } from '~/shared/types/schedule'
export default defineEventHandler(async (event) => {
const body = await readBody(event)
const { run_id } = body
if (!run_id) throw createError({ statusCode: 400, message: 'run_id required' })
const pb = await getPBAdminClient()
// Fetch the schedule run
const run = await pb.collection('schedule_runs').getOne(run_id)
// Update status to solving
await pb.collection('schedule_runs').update(run_id, { status: 'solving' })
try {
const input: SolveInput = {
organization_id: run.org_id as string,
period_start: run.period_start as string,
period_end: run.period_end as string,
framework: run.framework_snapshot as SolveInput['framework'],
employees: run.employees_snapshot as SolveInput['employees'],
constraints: (run.constraints_snapshot as SolveInput['constraints']) || [],
}
const result = await solveSchedule(input)
await pb.collection('schedule_runs').update(run_id, {
status: result.status,
result: result.assignments,
objective_value: result.objective_value,
solver_duration_ms: result.duration_ms,
infeasibility_hints: result.infeasibility_hints || [],
})
return result
} catch (err) {
await pb.collection('schedule_runs').update(run_id, {
status: 'error',
infeasibility_hints: [{ description: String(err) }],
})
throw err
}
})