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>
48 lines
1.5 KiB
TypeScript
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
|
|
}
|
|
})
|