Files
Webklar-Kundenbereich/server/routes/admin/websiteProjects.js
T
ClaudeandClaude Opus 5.5 3156bb790a Projekte: alle Mitarbeiter, private Repos, Archiv fuer Kunden ausgeblendet
Entscheidungen vom 04.10.2026:
- Projekt-Routen (website-projects, preview, gitea, services, analyse)
  fuer jeden Mitarbeiter (Label mitarbeiter oder admin); Kunden-,
  Mitarbeiter- und Finanz-Verwaltung bleiben nur fuer Admins
- Neue Repos aus der Vorlage werden privat angelegt
- Archivierte Projekte sieht der Kunde nicht mehr: Projektliste,
  Projektdetails, Preview-Zugang, Funktionen (Mitarbeiter-Ansicht schon)
- Projektliste des Kunden mit Limit (Appwrite liefert sonst nur 25)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-04 15:02:02 +00:00

127 lines
4.3 KiB
JavaScript

import { Router } from 'express'
import {
createProjectFromTemplate,
updateWebsiteProject,
archiveRepo,
} from '../../services/giteaAdmin.js'
import { assignProject, reconcileProject } from '../../services/projectAssignment.js'
import { completeAssignment } from '../../services/projectKindAssign.js'
import { requireAppwriteTeam } from '../../middleware/appwriteStaff.js'
const router = Router()
// Projekt-Aktionen: jeder Mitarbeiter (nicht nur Admins)
router.use(requireAppwriteTeam)
router.post('/create-from-template', async (req, res) => {
const { repoName, displayName, subdomain, customerId = '', ticketId = '', owner, kind = '' } = req.body || {}
if (!repoName && !displayName) {
return res.status(400).json({ error: 'repoName oder displayName ist erforderlich' })
}
try {
const result = await createProjectFromTemplate({
repoName,
displayName,
subdomain,
customerId,
ticketId,
owner,
kind,
staffName: req.appwriteUser?.name || req.appwriteUser?.email || '',
})
return res.status(201).json({ ok: true, ...result })
} catch (err) {
const status = err.status || 500
return res.status(status).json({ error: err.message || 'Projekt konnte nicht angelegt werden' })
}
})
// Projekt bearbeiten: Name / Subdomain / Typ -> synchronisiert Git + Preview + Appwrite
router.patch('/:id', async (req, res) => {
const { projectName, subdomain, projectType } = req.body || {}
try {
const result = await updateWebsiteProject(req.params.id, { projectName, subdomain, projectType })
return res.json({ ok: true, ...result })
} catch (err) {
const status = err.status || 500
return res.status(status).json({ error: err.message || 'Projekt konnte nicht aktualisiert werden' })
}
})
// Repository archivieren
router.post('/:id/archive', async (req, res) => {
try {
const result = await archiveRepo(req.params.id, true)
return res.json({ ok: true, ...result })
} catch (err) {
const status = err.status || 500
return res.status(status).json({ error: err.message || 'Projekt konnte nicht archiviert werden' })
}
})
// Repository reaktivieren
router.post('/:id/unarchive', async (req, res) => {
try {
const result = await archiveRepo(req.params.id, false)
return res.json({ ok: true, ...result })
} catch (err) {
const status = err.status || 500
return res.status(status).json({ error: err.message || 'Projekt konnte nicht reaktiviert werden' })
}
})
// Projekt einem Kunden/Ticket zuweisen -> stoesst Umzug nach GITEA_ORG + Nachtragen an
router.post('/:id/assign', async (req, res) => {
const { customerId, ticketId } = req.body || {}
if (!customerId && !ticketId) {
return res.status(400).json({ error: 'customerId oder ticketId erforderlich' })
}
try {
const result = await assignProject(req.params.id, {
customerId: String(customerId || ''),
ticketId: String(ticketId || ''),
})
return res.json({ ok: true, ...result })
} catch (err) {
if (err.status === 404) {
return res.status(404).json({ error: 'Projekt nicht gefunden' })
}
const status = err.status || 500
return res.status(status).json({ error: err.message })
}
})
// Zuordnen-Flow (WOMS): Art speichern, ggf. Ticket anlegen, Kunde/Ticket zuweisen, Preview
router.post('/:id/zuordnen', async (req, res) => {
const staffName = req.appwriteUser?.name || req.appwriteUser?.email || ''
try {
const result = await completeAssignment(req.params.id, req.body || {}, { staffName })
return res.json(result)
} catch (err) {
if (err.status === 409) {
return res.status(409).json({ error: 'bereits zugeordnet', kindSetBy: err.kindSetBy || '', kindSetAt: err.kindSetAt || '' })
}
const status = err.status || 500
return res.status(status).json({ error: err.message })
}
})
// Umzug + Pushes eines bereits zugewiesenen Projekts erneut nachtragen
router.post('/:id/pushes', async (req, res) => {
try {
const result = await reconcileProject(req.params.id)
return res.json({ ok: true, ...result })
} catch (err) {
if (err.status === 404) {
return res.status(404).json({ error: 'Projekt nicht gefunden' })
}
const status = err.status || 500
return res.status(status).json({ error: err.message })
}
})
export default router