migrate to ci and postgress
This commit is contained in:
@ -1,6 +0,0 @@
|
|||||||
node_modules
|
|
||||||
npm-debug.log
|
|
||||||
dist
|
|
||||||
.env
|
|
||||||
.git
|
|
||||||
.gitignore
|
|
||||||
56
.drone.yml
Normal file
56
.drone.yml
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
kind: pipeline
|
||||||
|
type: kubernetes
|
||||||
|
name: ci
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: prepare
|
||||||
|
image: alpine:3.19
|
||||||
|
environment:
|
||||||
|
GITEA_TOKEN:
|
||||||
|
from_secret: GITEA_TOKEN
|
||||||
|
commands:
|
||||||
|
- apk add --no-cache git bash yq
|
||||||
|
- git clone --depth 1 https://token:$GITEA_TOKEN@git.vigdorov.ru/vigdorov/ci-templates.git .ci
|
||||||
|
- chmod +x .ci/scripts/*.sh
|
||||||
|
- bash .ci/scripts/prepare.sh
|
||||||
|
|
||||||
|
- name: build
|
||||||
|
image: gcr.io/kaniko-project/executor:v1.23.2-debug
|
||||||
|
depends_on: [prepare]
|
||||||
|
environment:
|
||||||
|
HARBOR_USER:
|
||||||
|
from_secret: HARBOR_USER
|
||||||
|
HARBOR_PASSWORD:
|
||||||
|
from_secret: HARBOR_PASSWORD
|
||||||
|
commands:
|
||||||
|
- /busybox/sh .ci/scripts/build.sh
|
||||||
|
|
||||||
|
- name: deploy
|
||||||
|
image: alpine:3.19
|
||||||
|
depends_on: [build]
|
||||||
|
environment:
|
||||||
|
KUBE_CONFIG:
|
||||||
|
from_secret: KUBE_CONFIG
|
||||||
|
commands:
|
||||||
|
- apk add --no-cache bash yq kubectl helm
|
||||||
|
- bash .ci/scripts/deploy.sh
|
||||||
|
|
||||||
|
- name: notify
|
||||||
|
image: appleboy/drone-telegram
|
||||||
|
depends_on: [deploy]
|
||||||
|
settings:
|
||||||
|
token:
|
||||||
|
from_secret: TELEGRAM_TOKEN
|
||||||
|
to:
|
||||||
|
from_secret: TELEGRAM_CHAT_ID
|
||||||
|
format: markdown
|
||||||
|
message: >
|
||||||
|
{{#success build.status}}✅{{else}}❌{{/success}} **{{repo.name}}**
|
||||||
|
Branch: `{{commit.branch}}`
|
||||||
|
{{commit.message}}
|
||||||
|
when:
|
||||||
|
status: [success, failure]
|
||||||
|
|
||||||
|
trigger:
|
||||||
|
branch: [master, develop]
|
||||||
|
event: [push, custom]
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -54,3 +54,5 @@ pids
|
|||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
.serena
|
||||||
|
.claude
|
||||||
|
|||||||
25
CLAUDE.md
25
CLAUDE.md
@ -8,19 +8,27 @@
|
|||||||
|
|
||||||
## Стек
|
## Стек
|
||||||
|
|
||||||
- **Framework:** NestJS
|
- **Framework:** NestJS 11
|
||||||
- **Language:** TypeScript
|
- **Language:** TypeScript
|
||||||
- **Runtime:** Node.js
|
- **Runtime:** Node.js
|
||||||
|
- **Database:** PostgreSQL (shared-db) + TypeORM
|
||||||
|
- **CI/CD:** Drone CI + ci-templates
|
||||||
|
|
||||||
## Структура
|
## Структура
|
||||||
|
|
||||||
```
|
```
|
||||||
src/
|
src/
|
||||||
├── main.ts # Точка входа
|
├── main.ts # Точка входа
|
||||||
├── app.module.ts # Корневой модуль
|
├── app.module.ts # Корневой модуль (ConfigModule + TypeORM)
|
||||||
├── app.controller.ts # REST контроллер
|
├── app.controller.ts # REST контроллер
|
||||||
├── app.service.ts # Бизнес-логика
|
├── app.service.ts # Бизнес-логика (TypeORM Repository)
|
||||||
├── schemas.ts # Валидация данных
|
├── entities/
|
||||||
|
│ ├── user.entity.ts # Entity: users
|
||||||
|
│ └── storage.entity.ts # Entity: storages
|
||||||
|
├── health/
|
||||||
|
│ ├── health.module.ts # Health check модуль
|
||||||
|
│ └── health.controller.ts # GET /health
|
||||||
|
├── schemas.ts # Swagger DTO
|
||||||
├── types.ts # TypeScript типы
|
├── types.ts # TypeScript типы
|
||||||
├── consts.ts # Константы
|
├── consts.ts # Константы
|
||||||
└── api.responses.ts # Форматы ответов API
|
└── api.responses.ts # Форматы ответов API
|
||||||
@ -37,6 +45,13 @@ npm run start:prod # Production запуск
|
|||||||
|
|
||||||
## Деплой
|
## Деплой
|
||||||
|
|
||||||
- **Dockerfile:** есть
|
- **CI/CD:** Drone CI через ci-templates (service.yaml + .drone.yml)
|
||||||
- **Namespace:** backend-for-learning
|
- **Namespace:** backend-for-learning
|
||||||
- **URL:** https://simple-storage.vigdorov.ru
|
- **URL:** https://simple-storage.vigdorov.ru
|
||||||
|
- **Health:** GET /health
|
||||||
|
|
||||||
|
## Локальная разработка
|
||||||
|
|
||||||
|
Переменные окружения в `.env.local`:
|
||||||
|
- `DATABASE_HOST` — хост PostgreSQL (localhost для dev через NodePort :30432)
|
||||||
|
- `DATABASE_PORT`, `DATABASE_USER`, `DATABASE_PASSWORD`, `DATABASE_NAME`
|
||||||
|
|||||||
23
Dockerfile
23
Dockerfile
@ -1,23 +0,0 @@
|
|||||||
# Этап сборки
|
|
||||||
FROM node:18-alpine AS build
|
|
||||||
WORKDIR /app
|
|
||||||
COPY package*.json ./
|
|
||||||
RUN npm ci
|
|
||||||
COPY . .
|
|
||||||
RUN npm run build
|
|
||||||
|
|
||||||
# Этап продакшна
|
|
||||||
FROM node:18-alpine
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=build /app/package*.json ./
|
|
||||||
COPY --from=build /app/dist ./dist
|
|
||||||
RUN npm ci --only=production
|
|
||||||
|
|
||||||
# Переменные окружения
|
|
||||||
ENV NODE_ENV production
|
|
||||||
|
|
||||||
# Пользователь без привилегий для безопасности
|
|
||||||
USER node
|
|
||||||
|
|
||||||
EXPOSE 3000
|
|
||||||
CMD ["node", "dist/main"]
|
|
||||||
1066
package-lock.json
generated
1066
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -24,11 +24,14 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nestjs/common": "^11.0.1",
|
"@nestjs/common": "^11.0.1",
|
||||||
"@nestjs/core": "^11.0.1",
|
"@nestjs/core": "^11.0.1",
|
||||||
"@nestjs/mongoose": "^11.0.1",
|
"@nestjs/config": "^4.0.0",
|
||||||
"@nestjs/platform-express": "^11.0.1",
|
"@nestjs/platform-express": "^11.0.1",
|
||||||
"@nestjs/swagger": "^11.0.6",
|
"@nestjs/swagger": "^11.0.6",
|
||||||
"mongoose": "^8.11.0",
|
"@nestjs/terminus": "^11.0.0",
|
||||||
|
"@nestjs/typeorm": "^11.0.0",
|
||||||
|
"pg": "^8.13.1",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
|
"typeorm": "^0.3.20",
|
||||||
"rxjs": "^7.8.1",
|
"rxjs": "^7.8.1",
|
||||||
"uuid": "^11.1.0"
|
"uuid": "^11.1.0"
|
||||||
},
|
},
|
||||||
|
|||||||
24
service.yaml
Normal file
24
service.yaml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
service:
|
||||||
|
name: simple-storage
|
||||||
|
type: api
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
namespace: backend-for-learning
|
||||||
|
domain: simple-storage.vigdorov.ru
|
||||||
|
|
||||||
|
infrastructure:
|
||||||
|
postgres: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
- name: DATABASE_HOST
|
||||||
|
value: "simple-storage-postgres"
|
||||||
|
- name: DATABASE_PORT
|
||||||
|
value: "5432"
|
||||||
|
- name: DATABASE_USER
|
||||||
|
value: "simple_storage_user"
|
||||||
|
- name: DATABASE_PASSWORD
|
||||||
|
value: "S1mpl3_St0r@g3_DB_2025!"
|
||||||
|
- name: DATABASE_NAME
|
||||||
|
value: "simple_storage_db"
|
||||||
|
- name: CORS_ORIGIN
|
||||||
|
value: "*"
|
||||||
@ -1,31 +1,34 @@
|
|||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { AppController } from './app.controller';
|
import { AppController } from './app.controller';
|
||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
import { MongooseModule } from '@nestjs/mongoose';
|
import { UserEntity } from './entities/user.entity';
|
||||||
import { DB_STORAGES, DB_USERS, MONGO_URL } from './consts';
|
import { StorageEntity } from './entities/storage.entity';
|
||||||
import {
|
import { HealthModule } from './health/health.module';
|
||||||
StorageDocument,
|
|
||||||
StorageScheme,
|
|
||||||
UserDocument,
|
|
||||||
UserScheme,
|
|
||||||
} from './schemas';
|
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
MongooseModule.forRoot(`${MONGO_URL}/${DB_USERS}`, {
|
ConfigModule.forRoot({
|
||||||
connectionName: DB_USERS,
|
isGlobal: true,
|
||||||
|
envFilePath: ['.env.local', '.env'],
|
||||||
}),
|
}),
|
||||||
MongooseModule.forRoot(`${MONGO_URL}/${DB_STORAGES}`, {
|
TypeOrmModule.forRootAsync({
|
||||||
connectionName: DB_STORAGES,
|
imports: [ConfigModule],
|
||||||
|
inject: [ConfigService],
|
||||||
|
useFactory: (configService: ConfigService) => ({
|
||||||
|
type: 'postgres',
|
||||||
|
host: configService.get('DATABASE_HOST', 'localhost'),
|
||||||
|
port: configService.get('DATABASE_PORT', 5432),
|
||||||
|
username: configService.get('DATABASE_USER', 'postgres'),
|
||||||
|
password: configService.get('DATABASE_PASSWORD', 'postgres'),
|
||||||
|
database: configService.get('DATABASE_NAME', 'simple_storage_db'),
|
||||||
|
entities: [UserEntity, StorageEntity],
|
||||||
|
synchronize: true,
|
||||||
}),
|
}),
|
||||||
MongooseModule.forFeature(
|
}),
|
||||||
[{ name: UserDocument.name, schema: UserScheme }],
|
TypeOrmModule.forFeature([UserEntity, StorageEntity]),
|
||||||
DB_USERS,
|
HealthModule,
|
||||||
),
|
|
||||||
MongooseModule.forFeature(
|
|
||||||
[{ name: StorageDocument.name, schema: StorageScheme }],
|
|
||||||
DB_STORAGES,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
controllers: [AppController],
|
controllers: [AppController],
|
||||||
providers: [AppService],
|
providers: [AppService],
|
||||||
|
|||||||
@ -3,9 +3,11 @@ import {
|
|||||||
Injectable,
|
Injectable,
|
||||||
NotAcceptableException,
|
NotAcceptableException,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { InjectModel } from '@nestjs/mongoose';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { StorageDocument, UserDocument } from './schemas';
|
import { Repository } from 'typeorm';
|
||||||
import { Model } from 'mongoose';
|
import { v4 } from 'uuid';
|
||||||
|
import { UserEntity } from './entities/user.entity';
|
||||||
|
import { StorageEntity } from './entities/storage.entity';
|
||||||
import {
|
import {
|
||||||
User,
|
User,
|
||||||
Storage,
|
Storage,
|
||||||
@ -13,21 +15,18 @@ import {
|
|||||||
StorageUpdate,
|
StorageUpdate,
|
||||||
StorageList,
|
StorageList,
|
||||||
} from './types';
|
} from './types';
|
||||||
import { v4 } from 'uuid';
|
|
||||||
import { DB_STORAGES, DB_USERS } from './consts';
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AppService {
|
export class AppService {
|
||||||
constructor(
|
constructor(
|
||||||
@InjectModel(UserDocument.name, DB_USERS)
|
@InjectRepository(UserEntity)
|
||||||
private userModel: Model<UserDocument>,
|
private userRepository: Repository<UserEntity>,
|
||||||
@InjectModel(StorageDocument.name, DB_STORAGES)
|
@InjectRepository(StorageEntity)
|
||||||
private storageModel: Model<StorageDocument>,
|
private storageRepository: Repository<StorageEntity>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async checkRequest(token?: string): Promise<User> {
|
async checkRequest(token?: string): Promise<User> {
|
||||||
const userList = await this.userModel.find().exec();
|
const searchUser = await this.userRepository.findOne({ where: { token } });
|
||||||
const searchUser = userList.find((user) => user.token === token);
|
|
||||||
if (searchUser) {
|
if (searchUser) {
|
||||||
return {
|
return {
|
||||||
login: searchUser.login,
|
login: searchUser.login,
|
||||||
@ -38,37 +37,36 @@ export class AppService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async authUser(login: string): Promise<string> {
|
async authUser(login: string): Promise<string> {
|
||||||
const userList = await this.userModel.find().exec();
|
const searchUser = await this.userRepository.findOne({ where: { login } });
|
||||||
const searchUser = userList.find((user) => user.login === login);
|
|
||||||
if (searchUser) {
|
if (searchUser) {
|
||||||
return searchUser.token;
|
return searchUser.token;
|
||||||
}
|
}
|
||||||
const Model = this.userModel;
|
const newUser = await this.userRepository.save({
|
||||||
const userModel = new Model({
|
|
||||||
login,
|
login,
|
||||||
token: v4(),
|
token: v4(),
|
||||||
});
|
});
|
||||||
const newUser = await userModel.save();
|
|
||||||
return newUser.token;
|
return newUser.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getStorageList(login: string): Promise<StorageList> {
|
async getStorageList(login: string): Promise<StorageList> {
|
||||||
const storageList = await this.storageModel.find().exec();
|
const storageList = await this.storageRepository.find({
|
||||||
const preparedList = storageList.map(({ _id, user, storageName }) => ({
|
where: { user: login },
|
||||||
id: _id as string,
|
});
|
||||||
|
return storageList.map(({ id, user, storageName }) => ({
|
||||||
|
id,
|
||||||
user,
|
user,
|
||||||
storageName,
|
storageName,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return preparedList.filter(({ user }) => user === login);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getStorageById(login: string, id: string): Promise<Storage> {
|
async getStorageById(login: string, id: string): Promise<Storage> {
|
||||||
const searchStorage = await this.storageModel.findById(id);
|
const searchStorage = await this.storageRepository.findOne({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
if (searchStorage && searchStorage.user === login) {
|
if (searchStorage && searchStorage.user === login) {
|
||||||
return {
|
return {
|
||||||
data: searchStorage.data,
|
data: searchStorage.data,
|
||||||
id: searchStorage._id as string,
|
id: searchStorage.id,
|
||||||
storageName: searchStorage.storageName,
|
storageName: searchStorage.storageName,
|
||||||
user: searchStorage.user,
|
user: searchStorage.user,
|
||||||
};
|
};
|
||||||
@ -77,25 +75,19 @@ export class AppService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async addStorage(login: string, storage: StorageCreate): Promise<Storage> {
|
async addStorage(login: string, storage: StorageCreate): Promise<Storage> {
|
||||||
const Model = this.storageModel;
|
if (!storage.data || !storage.storageName) {
|
||||||
const storageModel = new Model({
|
throw new BadRequestException('data и storageName обязательны');
|
||||||
|
}
|
||||||
|
const newStorage = await this.storageRepository.save({
|
||||||
data: storage.data,
|
data: storage.data,
|
||||||
storageName: storage.storageName,
|
storageName: storage.storageName,
|
||||||
user: login,
|
user: login,
|
||||||
});
|
});
|
||||||
try {
|
|
||||||
await storageModel.validate();
|
|
||||||
} catch (e) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
||||||
throw new BadRequestException(e.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
const newStorage = await storageModel.save();
|
|
||||||
return {
|
return {
|
||||||
data: newStorage.data,
|
data: newStorage.data,
|
||||||
user: newStorage.user,
|
user: newStorage.user,
|
||||||
storageName: newStorage.storageName,
|
storageName: newStorage.storageName,
|
||||||
id: newStorage._id as string,
|
id: newStorage.id,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,7 +96,9 @@ export class AppService {
|
|||||||
id: string,
|
id: string,
|
||||||
storage: StorageUpdate,
|
storage: StorageUpdate,
|
||||||
): Promise<Storage> {
|
): Promise<Storage> {
|
||||||
const searchStorage = await this.storageModel.findById(id);
|
const searchStorage = await this.storageRepository.findOne({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
|
|
||||||
if (!searchStorage || searchStorage.user !== login) {
|
if (!searchStorage || searchStorage.user !== login) {
|
||||||
throw new BadRequestException(`Storage с id - "${id}" не найден`);
|
throw new BadRequestException(`Storage с id - "${id}" не найден`);
|
||||||
@ -112,7 +106,7 @@ export class AppService {
|
|||||||
|
|
||||||
const updatedStorageName = storage.storageName ?? searchStorage.storageName;
|
const updatedStorageName = storage.storageName ?? searchStorage.storageName;
|
||||||
|
|
||||||
await searchStorage.updateOne({
|
await this.storageRepository.update(id, {
|
||||||
data: storage.data,
|
data: storage.data,
|
||||||
storageName: updatedStorageName,
|
storageName: updatedStorageName,
|
||||||
});
|
});
|
||||||
@ -121,24 +115,25 @@ export class AppService {
|
|||||||
data: storage.data,
|
data: storage.data,
|
||||||
user: searchStorage.user,
|
user: searchStorage.user,
|
||||||
storageName: updatedStorageName,
|
storageName: updatedStorageName,
|
||||||
id: searchStorage._id as string,
|
id: searchStorage.id,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async deleteStorageById(login: string, id: string): Promise<Storage> {
|
async deleteStorageById(login: string, id: string): Promise<Storage> {
|
||||||
const searchStorage = await this.storageModel.findById(id);
|
const searchStorage = await this.storageRepository.findOne({
|
||||||
|
where: { id },
|
||||||
|
});
|
||||||
if (!searchStorage || searchStorage.user !== login) {
|
if (!searchStorage || searchStorage.user !== login) {
|
||||||
throw new BadRequestException(`Storage с id - "${id}" не найден`);
|
throw new BadRequestException(`Storage с id - "${id}" не найден`);
|
||||||
}
|
}
|
||||||
const Model = this.storageModel;
|
|
||||||
|
|
||||||
await Model.findByIdAndDelete(id);
|
await this.storageRepository.delete(id);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: searchStorage.data,
|
data: searchStorage.data,
|
||||||
user: searchStorage.user,
|
user: searchStorage.user,
|
||||||
storageName: searchStorage.storageName,
|
storageName: searchStorage.storageName,
|
||||||
id: searchStorage._id as string,
|
id: searchStorage.id,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,3 @@
|
|||||||
// Подключение к MongoDB
|
|
||||||
export const MONGO_URL = process.env.MONGODB_URI || 'mongodb://localhost:27017';
|
|
||||||
|
|
||||||
// Имя базы данных для пользователей и хранилищ
|
|
||||||
export const DB_USERS = process.env.DB_USERS || 'storage-back-users';
|
|
||||||
export const DB_STORAGES = process.env.DB_STORAGES || 'storage-back-storages';
|
|
||||||
|
|
||||||
// Порт приложения
|
// Порт приложения
|
||||||
export const APP_PORT = parseInt(process.env.APP_PORT || '3000', 10);
|
export const APP_PORT = parseInt(process.env.APP_PORT || '3000', 10);
|
||||||
|
|
||||||
|
|||||||
16
src/entities/storage.entity.ts
Normal file
16
src/entities/storage.entity.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('storages')
|
||||||
|
export class StorageEntity {
|
||||||
|
@PrimaryGeneratedColumn('uuid')
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Column({ type: 'jsonb' })
|
||||||
|
data: object;
|
||||||
|
|
||||||
|
@Column({ type: 'varchar' })
|
||||||
|
storageName: string;
|
||||||
|
|
||||||
|
@Column({ type: 'varchar' })
|
||||||
|
user: string;
|
||||||
|
}
|
||||||
13
src/entities/user.entity.ts
Normal file
13
src/entities/user.entity.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity('users')
|
||||||
|
export class UserEntity {
|
||||||
|
@PrimaryGeneratedColumn('uuid')
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Column({ type: 'varchar', unique: true })
|
||||||
|
login: string;
|
||||||
|
|
||||||
|
@Column({ type: 'varchar' })
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
20
src/health/health.controller.ts
Normal file
20
src/health/health.controller.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { Controller, Get } from '@nestjs/common';
|
||||||
|
import {
|
||||||
|
HealthCheckService,
|
||||||
|
HealthCheck,
|
||||||
|
TypeOrmHealthIndicator,
|
||||||
|
} from '@nestjs/terminus';
|
||||||
|
|
||||||
|
@Controller('health')
|
||||||
|
export class HealthController {
|
||||||
|
constructor(
|
||||||
|
private health: HealthCheckService,
|
||||||
|
private db: TypeOrmHealthIndicator,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
@HealthCheck()
|
||||||
|
check() {
|
||||||
|
return this.health.check([() => this.db.pingCheck('database')]);
|
||||||
|
}
|
||||||
|
}
|
||||||
9
src/health/health.module.ts
Normal file
9
src/health/health.module.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { TerminusModule } from '@nestjs/terminus';
|
||||||
|
import { HealthController } from './health.controller';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [TerminusModule],
|
||||||
|
controllers: [HealthController],
|
||||||
|
})
|
||||||
|
export class HealthModule {}
|
||||||
@ -1,6 +1,4 @@
|
|||||||
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { Document } from 'mongoose';
|
|
||||||
import { Storage, StorageCreate } from './types';
|
import { Storage, StorageCreate } from './types';
|
||||||
|
|
||||||
export class AuthRequest {
|
export class AuthRequest {
|
||||||
@ -8,45 +6,6 @@ export class AuthRequest {
|
|||||||
login: string;
|
login: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Schema()
|
|
||||||
export class UserDocument extends Document {
|
|
||||||
@Prop({
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
login: string;
|
|
||||||
|
|
||||||
@Prop({
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
token: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Schema()
|
|
||||||
export class StorageDocument extends Document {
|
|
||||||
@Prop({
|
|
||||||
type: Object,
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
data: object;
|
|
||||||
|
|
||||||
@Prop({
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
storageName: string;
|
|
||||||
|
|
||||||
@Prop({
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
})
|
|
||||||
user: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const StorageScheme = SchemaFactory.createForClass(StorageDocument);
|
|
||||||
export const UserScheme = SchemaFactory.createForClass(UserDocument);
|
|
||||||
|
|
||||||
export class StorageResponse implements Storage {
|
export class StorageResponse implements Storage {
|
||||||
@ApiProperty()
|
@ApiProperty()
|
||||||
data: object;
|
data: object;
|
||||||
|
|||||||
Reference in New Issue
Block a user