import { Body, Controller, Get, Post, Query, UseGuards } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; import { ConfigService } from '@nestjs/config'; import { SyncService } from './sync.service'; import { SyncSecretGuard } from './sync-secret.guard'; import { IngestEntriesDto } from './dto/ingest-entries.dto'; import { Roles } from '../common/roles.decorator'; import { RolesGuard } from '../common/roles.guard'; import { Role } from '../common/role.enum'; @Controller('sync') export class SyncController { constructor( private readonly sync: SyncService, private readonly config: ConfigService, ) {} /// Peer pushes its new entries to us. @Post('ingest') @UseGuards(SyncSecretGuard) async ingest(@Body() dto: IngestEntriesDto) { await this.sync.applyIncoming(dto.entries as never); return { applied: dto.entries.length }; } /// Peer pulls our new entries since their last known sequence. @Get('export') @UseGuards(SyncSecretGuard) async export(@Query('since') since: string) { const entries = await this.sync.getEntriesSince(Number(since) || 0); return { entries }; } /// Manual on-demand push+pull against the configured peer (Leitungsteam-only). @Post('trigger') @UseGuards(AuthGuard(['authentik', 'team']), RolesGuard) @Roles(Role.LEITUNGSTEAM) async trigger() { const peerUrl = this.config.getOrThrow('SYNC_PEER_URL'); const peerSecret = this.config.getOrThrow('SYNC_SHARED_SECRET'); const pushed = await this.sync.pushToPeer(peerUrl, peerSecret); const pulled = await this.sync.pullFromPeer(peerUrl, peerSecret); return { ...pushed, ...pulled }; } }