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
@@ -0,0 +1,50 @@
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import type {
AuthUser,
JwtAccessPayload,
} from '../../../common/auth/auth-user';
import { UsersService } from '../../users/users.service';
import { RevokedAccessTokensRepository } from '../revoked-access-tokens.repository';
@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
constructor(
config: ConfigService,
private readonly usersService: UsersService,
private readonly revokedAccessTokensRepository: RevokedAccessTokensRepository,
) {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKey: config.getOrThrow<string>('JWT_ACCESS_SECRET'),
algorithms: ['HS256'],
});
}
async validate(payload: JwtAccessPayload): Promise<AuthUser> {
if (payload.typ !== 'access' || !payload.sub || !payload.jti) {
throw new UnauthorizedException('Invalid access token');
}
const revoked = await this.revokedAccessTokensRepository.exists(
payload.jti,
);
if (revoked) {
throw new UnauthorizedException('Access token revoked');
}
const user = await this.usersService.findById(payload.sub);
if (!user) {
throw new UnauthorizedException('User not found');
}
return {
id: user.id,
username: user.username,
jti: payload.jti,
};
}
}