Analyse: alle Beendigungswege schalten den Messdienst ab (Kunde/Projekt weg, Domain, Löschfrist, Widerruf Wechsel)

Messdienst: POST /a/admin/sites/:key/off setzt active=0 und offSince einmalig; Portal-Client stopSite.
analyse.js: endAnalyse als gemeinsamer Kern, endAnalyseForCustomer, analyseOnProjectChanged,
analyseDisabled (Sperre/Löschfrist) und täglicher Abgleich runAnalyseReconcile (Projekt/Kunde weg,
Domains nachziehen, K18-Wiederholung, Messdienst für off/disabled, fehlende Entfernen-Tickets nachholen).
Entfernen-Ticket je Abschaltung gekennzeichnet (kein Doppelticket, auch wenn das Speichern der ID scheiterte).
Hooks: Kunde löschen, updateWebsiteProject, withdrawOrder (Wechsel), siteFeatures.disable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Opus 5.5 committed 2026-10-01 18:50:36 +00:00
1 parent fbc40252a3
commit 78170567b4
17 files changed
+616 -70

No files matched your search

+31
View File
@@ -30,6 +30,10 @@ before(async () => {
{ repoFullName: 'knso/alt', projectName: 'alt', subdomain: 'alt' },
{ repoFullName: 'knso/synced-sub', projectName: 'synced-sub', status: 'synced', subdomain: 'synced-sub' },
{ repoFullName: 'knso/lead', projectName: 'lead', status: 'deployed', subdomain: 'lead' },
{ $id: 'wp_an', repoFullName: 'knso/alt', projectName: 'Analyse-Projekt', subdomain: 'analyseprojekt', isPublic: true, projectType: 'website' },
],
portalFeatures: [
{ $id: 'wp_an_feat', customerId: 'cx', projectId: 'wp_an', featureKey: 'analyse', state: 'active', enabled: true, siteKey: 'wpansitekey01234567' },
],
},
})
@@ -111,3 +115,30 @@ test('Repo-Liste hat eine Obergrenze', async () => {
assert.equal(repos.length, 2000)
assert.equal(capGitea.calls.filter((c) => c.path === '/api/v1/repos/search').length, 40)
})
test('updateWebsiteProject: neue Subdomain => putSite mit neuer Domain; nicht öffentlich => stopSite; Hook-Fehler ändert das Ergebnis nicht', async () => {
const { updateWebsiteProject } = await import('../server/services/giteaAdmin.js')
const { analyseDeps } = await import('../server/services/analyse.js')
const calls = []
const real = analyseDeps.client
analyseDeps.client = {
putSite: async (k, b) => calls.push(['put', k, b]),
stopSite: async (k) => calls.push(['stop', k]),
}
try {
const r1 = await updateWebsiteProject('wp_an', { subdomain: 'analyseneu', projectType: 'website' })
assert.equal(r1.subdomain, 'analyseneu')
assert.deepEqual(calls, [['put', 'wpansitekey01234567', { projectId: 'wp_an', domains: ['analyseneu.project.webklar.com'], active: true }]])
calls.length = 0
const r2 = await updateWebsiteProject('wp_an', { projectType: 'preview' })
assert.equal(r2.isPublic, false)
assert.deepEqual(calls, [['stop', 'wpansitekey01234567']])
const { updateDocument } = await import('../server/services/appwriteAdmin.js')
await updateDocument(config.collections.portalFeatures, 'wp_an_feat', { state: 'active', enabled: true })
analyseDeps.client = { putSite: async () => { throw new Error('weg') }, stopSite: async () => { throw new Error('weg') } }
const r3 = await updateWebsiteProject('wp_an', { subdomain: 'nochneu', projectType: 'website' })
assert.equal(r3.subdomain, 'nochneu')
} finally {
analyseDeps.client = real
}
})