Files
AOS/src/app/api/aos/instances/[id]/graph-status/route.ts
T
Z User 32a8b01845 fix: instance detail crash + add play/stop/redeploy/remove actions
Fixes:
1. useFetch: add credentials:'same-origin' — cookie wasn't being sent
   with API calls, causing 401 → React error boundary → 'Etwas ist schiefgelaufen'
2. Instance detail Sheet now loads correctly (cookie sent with request)

New instance actions (UI + API):
- Redeploy: triggers Dokploy application.redeploy (rebuilds from latest commit)
- Stop: triggers Dokploy application.stop (pauses container)
- Start: triggers Dokploy application.start (resumes container)
- Remove: existing delete (SlideCommit confirmation)

Dokploy deploy fix:
- deployApplication now calls markRunning before deploy
- This ensures Dokploy creates a deployment job

ActionsRow redesigned:
- demo_active/active: [Redeploy] [Stop] [Demo +7d] [Remove]
- grace: [Start] [Remove]
- failed: [Retry] [Remove]
- provisioning/deleting/deleted: no actions
2026-10-29 16:29:28 +00:00

76 lines
2.5 KiB
TypeScript
Executable File

import { NextResponse } from 'next/server'
import { db } from '@/lib/db'
export const dynamic = 'force-dynamic'
// POST /api/aos/instances/[id]/graph-status
// Called by the graph build worker after it finishes (success or failure).
// Body: { status: 'ok' | 'error', stats?: {...}, error?: '...' }
//
// This is the callback endpoint that completes the graph build lifecycle:
// 1. AOS queues build (graphify.build.queued)
// 2. Worker picks up, calls POST /graph-build, gets the command
// 3. Worker executes graphify CLI
// 4. Worker calls this endpoint to report success/failure
// 5. AOS records graphify.build.ok / graphify.build.error
export async function POST(req: Request, { params }: { params: Promise<{ id: string }> }) {
try {
const { id } = await params
const body = await req.json().catch(() => ({}))
const status = body.status === 'ok' ? 'ok' : 'error'
const instance = await db.instance.findUnique({ where: { id } })
if (!instance) {
return NextResponse.json({ error: 'instance not found' }, { status: 404 })
}
if (status === 'ok') {
await db.instanceEvent.create({
data: {
instanceId: id,
type: 'graphify.build.ok',
step: 'graphify',
result: 'ok',
details: JSON.stringify({
stats: body.stats ?? null,
graphPath: body.graphPath ?? null,
builtAt: new Date().toISOString(),
}),
},
})
await db.auditLog.create({
data: {
actor: 'graphify-worker',
action: 'graphify.build.ok',
entity: 'Instance',
entityId: id,
after: JSON.stringify({ stats: body.stats }),
hash: 'sha256:' + Math.random().toString(36).slice(2),
},
})
return NextResponse.json({ ok: true, status: 'ok' })
} else {
await db.instanceEvent.create({
data: {
instanceId: id,
type: 'graphify.build.error',
step: 'graphify',
result: 'error',
details: JSON.stringify({ error: body.error ?? 'unknown build error' }),
},
})
await db.instance.update({
where: { id },
data: {
lastError: `graphify build failed: ${body.error ?? 'unknown'}`,
lastErrorAt: new Date(),
},
})
return NextResponse.json({ ok: false, status: 'error', error: body.error })
}
} catch (err) {
const msg = err instanceof Error ? err.message : 'internal server error'
return NextResponse.json({ error: msg }, { status: 500 })
}
}