diff --git a/services/platform-service/src/modules/scim/repository.ts b/services/platform-service/src/modules/scim/repository.ts index 3b264cbe..4500122f 100644 --- a/services/platform-service/src/modules/scim/repository.ts +++ b/services/platform-service/src/modules/scim/repository.ts @@ -91,3 +91,39 @@ export async function listEvents(connectorId: string): Promise { + const [users, groups, events] = await Promise.all([ + listUserSync(connectorId), + listGroupSync(connectorId), + listEvents(connectorId), + ]); + + return { + connectorId, + userCount: users.length, + groupCount: groups.length, + eventCount: events.length, + provisionedUsers: users.filter(u => u.status === 'provisioned').length, + failedUsers: users.filter(u => u.status === 'failed').length, + provisionedGroups: groups.filter(g => g.status === 'provisioned').length, + failedGroups: groups.filter(g => g.status === 'failed').length, + lastEventAt: events[0]?.createdAt ?? null, + }; +} + +export async function deleteConnector(id: string, orgId: string): Promise { + await connectorCollection().delete(id, orgId); +} diff --git a/services/platform-service/src/modules/scim/routes.ts b/services/platform-service/src/modules/scim/routes.ts index 05e21697..47a7eaeb 100644 --- a/services/platform-service/src/modules/scim/routes.ts +++ b/services/platform-service/src/modules/scim/routes.ts @@ -175,4 +175,46 @@ export async function scimRoutes(app: FastifyInstance) { }; return repo.createEvent(doc); }); + + // ── Connector stats ──────────────────────────────────── + app.get('/scim/connectors/:orgId/:id/stats', async req => { + requireAdmin(req); + const { orgId, id } = req.params as { orgId: string; id: string }; + await repo.getConnector(id, orgId); + return repo.getConnectorStats(id); + }); + + // ── Delete connector (paused only) ───────────────────── + app.delete('/scim/connectors/:orgId/:id', async req => { + requireAdmin(req); + const { orgId, id } = req.params as { orgId: string; id: string }; + const connector = await repo.getConnector(id, orgId); + if (connector.status === 'active') { + throw new BadRequestError('Pause the connector before deleting it'); + } + await repo.deleteConnector(id, orgId); + return { deleted: true }; + }); + + // ── Pause connector ──────────────────────────────────── + app.post('/scim/connectors/:orgId/:id/pause', async req => { + requireAdmin(req); + const { orgId, id } = req.params as { orgId: string; id: string }; + const connector = await repo.getConnector(id, orgId); + if (connector.status !== 'active') { + throw new BadRequestError(`Cannot pause connector with status '${connector.status}'`); + } + return repo.updateConnector(id, orgId, { status: 'paused' }); + }); + + // ── Resume connector ─────────────────────────────────── + app.post('/scim/connectors/:orgId/:id/resume', async req => { + requireAdmin(req); + const { orgId, id } = req.params as { orgId: string; id: string }; + const connector = await repo.getConnector(id, orgId); + if (connector.status !== 'paused') { + throw new BadRequestError(`Cannot resume connector with status '${connector.status}'`); + } + return repo.updateConnector(id, orgId, { status: 'active' }); + }); }