Set up PostgreSQL database configuration and enhance application structure

- Added .env.example with database connection details and JWT configuration.
- Introduced docker-compose.yml for PostgreSQL service setup with health checks.
- Created drizzle.config.ts for database schema and migration management.
- Updated nest-cli.json to include Swagger plugin configuration for API documentation.
- Enhanced package.json with new database-related scripts and dependencies.
- Implemented initial database migrations for user and token management.
- Configured application bootstrap process to load environment variables and set up Swagger.
- Added shared application configuration in configure-app.ts for consistent setup.
- Included unit tests for application configuration and Swagger setup.
This commit is contained in:
shancheas
2026-08-21 15:00:19 +07:00
parent 7f37985d22
commit d01fd6e2ef
54 changed files with 4378 additions and 87 deletions
+93
View File
@@ -0,0 +1,93 @@
import { Body, Controller, Get, HttpCode, Post } from '@nestjs/common';
import {
ApiBadRequestResponse,
ApiBearerAuth,
ApiConflictResponse,
ApiCreatedResponse,
ApiNoContentResponse,
ApiOkResponse,
ApiOperation,
ApiTags,
ApiTooManyRequestsResponse,
ApiUnauthorizedResponse,
} from '@nestjs/swagger';
import { Throttle } from '@nestjs/throttler';
import type { AuthUser } from '../../common/auth/auth-user';
import { CurrentUser } from '../../common/decorators/current-user.decorator';
import { Public } from '../../common/decorators/public.decorator';
import { BEARER_AUTH_NAME } from '../../common/swagger/setup-swagger';
import { AuthService } from './auth.service';
import {
LoginDto,
MeResponseDto,
RefreshTokenDto,
RegisterDto,
TokenPairDto,
} from './dto/auth.dto';
@ApiTags('auth')
@Controller('auth')
export class AuthController {
constructor(private readonly authService: AuthService) {}
@Public()
@Throttle({ default: { limit: 5, ttl: 60_000 } })
@Post('register')
@ApiOperation({ summary: 'Register a new user' })
@ApiCreatedResponse({ type: TokenPairDto })
@ApiBadRequestResponse({ description: 'Validation failed' })
@ApiConflictResponse({ description: 'Username already registered' })
@ApiTooManyRequestsResponse({ description: 'Rate limit exceeded' })
register(@Body() dto: RegisterDto): Promise<TokenPairDto> {
return this.authService.register(dto.username, dto.password);
}
@Public()
@Throttle({ default: { limit: 5, ttl: 60_000 } })
@Post('login')
@HttpCode(200)
@ApiOperation({ summary: 'Log in with username and password' })
@ApiOkResponse({ type: TokenPairDto })
@ApiBadRequestResponse({ description: 'Validation failed' })
@ApiUnauthorizedResponse({ description: 'Invalid credentials' })
@ApiTooManyRequestsResponse({ description: 'Rate limit exceeded' })
login(@Body() dto: LoginDto): Promise<TokenPairDto> {
return this.authService.login(dto.username, dto.password);
}
@Public()
@Throttle({ default: { limit: 10, ttl: 60_000 } })
@Post('refresh')
@HttpCode(200)
@ApiOperation({
summary: 'Rotate refresh token and issue a new access token',
})
@ApiOkResponse({ type: TokenPairDto })
@ApiBadRequestResponse({ description: 'Validation failed' })
@ApiUnauthorizedResponse({ description: 'Invalid refresh token' })
@ApiTooManyRequestsResponse({ description: 'Rate limit exceeded' })
refresh(@Body() dto: RefreshTokenDto): Promise<TokenPairDto> {
return this.authService.refresh(dto.refreshToken);
}
@Public()
@Throttle({ default: { limit: 10, ttl: 60_000 } })
@Post('revoke')
@HttpCode(204)
@ApiOperation({ summary: 'Revoke a refresh token session' })
@ApiNoContentResponse({ description: 'Session revoked (or already invalid)' })
@ApiBadRequestResponse({ description: 'Validation failed' })
@ApiTooManyRequestsResponse({ description: 'Rate limit exceeded' })
async revoke(@Body() dto: RefreshTokenDto): Promise<void> {
await this.authService.revoke(dto.refreshToken);
}
@Get('me')
@ApiBearerAuth(BEARER_AUTH_NAME)
@ApiOperation({ summary: 'Get the current authenticated user' })
@ApiOkResponse({ type: MeResponseDto })
@ApiUnauthorizedResponse({ description: 'Missing or invalid access token' })
me(@CurrentUser() user: AuthUser): MeResponseDto {
return { id: user.id, username: user.username };
}
}