AI Implementation feature(820): Project Scaffold and Platform Foundations (#1)

This commit was merged in pull request #1.
This commit is contained in:
2026-07-21 14:23:53 +00:00
parent e55c9cda56
commit 03bcb6b156
131 changed files with 23657 additions and 0 deletions
@@ -0,0 +1,89 @@
import {
Body,
Controller,
Get,
Post,
Req,
Res,
HttpCode,
HttpStatus,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBody } from '@nestjs/swagger';
import { Request, Response } from 'express';
import { ConfigService } from '@nestjs/config';
import { ZodValidationPipe } from '../../common/pipes/zod-validation.pipe';
import { Public } from '../../common/decorators/public.decorator';
import { LoginDtoSchema, RefreshDtoSchema } from './dto/auth.dto';
import { AuthService } from './auth.service';
import { CsrfMiddleware } from '../../common/middleware/csrf.middleware';
import { setRefreshCookie, clearRefreshCookie } from './cookie';
@ApiTags('auth')
@Controller('api/v1/auth')
export class AuthController {
constructor(
private readonly auth: AuthService,
private readonly csrf: CsrfMiddleware,
private readonly config: ConfigService,
) {}
@Public()
@Post('login')
@ApiOperation({ summary: 'Login with username and password' })
@ApiBody({ schema: { example: { username: 'admin', password: 'SuperSecret123!' } } })
@ApiResponse({ status: 200, description: 'Login successful' })
async login(
@Body(new ZodValidationPipe(LoginDtoSchema)) body: { username: string; password: string },
@Req() req: Request,
@Res({ passthrough: true }) res: Response,
) {
const ip = (req.ip || req.socket.remoteAddress || 'unknown') as string;
const session = await this.auth.login(body, ip);
setRefreshCookie(res, session.refreshToken, this.config);
return {
accessToken: session.accessToken,
expiresIn: session.expiresIn,
user: session.user,
};
}
@Public()
@Post('refresh')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: 'Rotate the refresh token' })
async refresh(
@Req() req: Request,
@Res({ passthrough: true }) res: Response,
@Body(new ZodValidationPipe(RefreshDtoSchema)) body: { refreshToken?: string },
) {
const fromCookie = (req.cookies?.['rt'] as string | undefined) ?? '';
const token = body.refreshToken ?? fromCookie;
if (!token) return { message: 'No refresh token' };
const session = await this.auth.refresh(token);
setRefreshCookie(res, session.refreshToken, this.config);
return {
accessToken: session.accessToken,
expiresIn: session.expiresIn,
user: session.user,
};
}
@Public()
@Post('logout')
@HttpCode(HttpStatus.NO_CONTENT)
@ApiOperation({ summary: 'Invalidate the current refresh token' })
async logout(@Req() req: Request, @Res({ passthrough: true }) res: Response): Promise<void> {
const token = (req.cookies?.['rt'] as string | undefined) ?? '';
await this.auth.logout(token || undefined);
clearRefreshCookie(res);
}
@Public()
@Get('csrf')
@ApiOperation({ summary: 'Issue a CSRF token (sets csrf cookie, returns token)' })
@ApiResponse({ status: 200, schema: { example: { csrfToken: '...' } } })
csrfEndpoint(@Req() req: Request, @Res({ passthrough: true }) res: Response): { csrfToken: string } {
const token = this.csrf.setOrGetCsrfToken(req, res);
return { csrfToken: token };
}
}