feat: add Drizzle ORM, Supabase admin client, Swagger, Helmet, Pino logging, rate limiting

This commit is contained in:
Claude 2026-07-20 22:41:09 +02:00
parent ce5cf134ae
commit 3fe8d24179
9 changed files with 104 additions and 10 deletions

View file

@ -1,9 +1,27 @@
PORT=3000
NODE_ENV=development
PORT=3001
# Supabase (CEO-OS project, Coolify)
DATABASE_URL=postgresql://postgres:CHANGE_ME@supabase-db:5432/postgres
SUPABASE_URL=http://supabasekong-to6mg3yxqit4ac9nl0otnvav.152.53.112.35.sslip.io:8000
DATABASE_URL=
SUPABASE_URL=
SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY=
# Redis (ceo-os-redis, Coolify)
REDIS_URL=redis://default:CHANGE_ME@ceo-os-redis:6379/0
REDIS_URL=
APP_ENCRYPTION_KEY=
JWT_SECRET=
COOKIE_SECRET=
AI_GATEWAY_URL=
AI_GATEWAY_API_KEY=
N8N_BASE_URL=
N8N_WEBHOOK_SECRET=
SMTP_HOST=
SMTP_PORT=
SMTP_USER=
SMTP_PASSWORD=
SMTP_FROM=

View file

@ -10,4 +10,15 @@ cp .env.example .env
npm run start:dev
```
`GET /health` returneaza statusul serviciului.
`GET /health` returneaza statusul serviciului. `GET /docs` expune Swagger UI.
## Stack
NestJS, Drizzle ORM (`src/db`), Supabase Admin SDK (`src/supabase`), BullMQ/Redis, class-validator/Zod, Helmet, rate limiting (Throttler), logging Pino.
## Migratii
```bash
npm run db:generate
npm run db:migrate
```

8
drizzle.config.ts Normal file
View file

@ -0,0 +1,8 @@
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
schema: './src/db/schema.ts',
out: './drizzle',
dialect: 'postgresql',
dbCredentials: { url: process.env.DATABASE_URL! },
});

View file

@ -9,19 +9,37 @@
"start": "node dist/main",
"start:dev": "nest start --watch",
"lint": "eslint \"src/**/*.ts\"",
"test": "jest"
"test": "jest",
"db:generate": "drizzle-kit generate",
"db:migrate": "drizzle-kit migrate"
},
"dependencies": {
"@nestjs/bullmq": "^11.0.0",
"@nestjs/common": "^11.0.0",
"@nestjs/config": "^4.0.0",
"@nestjs/core": "^11.0.0",
"@nestjs/platform-express": "^11.0.0",
"@nestjs/swagger": "^8.0.0",
"@nestjs/throttler": "^6.2.0",
"@supabase/supabase-js": "^2.47.0",
"bullmq": "^5.28.0",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"drizzle-orm": "^0.36.0",
"helmet": "^8.0.0",
"ioredis": "^5.4.1",
"nestjs-pino": "^4.1.0",
"pg": "^8.13.0",
"pino-http": "^10.3.0",
"reflect-metadata": "^0.2.2",
"rxjs": "^7.8.1"
"rxjs": "^7.8.1",
"zod": "^3.23.8"
},
"devDependencies": {
"@nestjs/cli": "^11.0.0",
"@types/node": "^22.0.0",
"@types/pg": "^8.11.10",
"drizzle-kit": "^0.28.0",
"typescript": "^5.6.0"
}
}

View file

@ -1,9 +1,15 @@
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { ThrottlerModule } from '@nestjs/throttler';
import { LoggerModule } from 'nestjs-pino';
import { HealthController } from './health/health.controller';
@Module({
imports: [ConfigModule.forRoot({ isGlobal: true })],
imports: [
ConfigModule.forRoot({ isGlobal: true }),
LoggerModule.forRoot(),
ThrottlerModule.forRoot([{ ttl: 60000, limit: 100 }]),
],
controllers: [HealthController],
})
export class AppModule {}

7
src/db/client.ts Normal file
View file

@ -0,0 +1,7 @@
import { drizzle } from 'drizzle-orm/node-postgres';
import { Pool } from 'pg';
import * as schema from './schema';
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
export const db = drizzle(pool, { schema });

7
src/db/schema.ts Normal file
View file

@ -0,0 +1,7 @@
import { pgTable, uuid, text, timestamp } from 'drizzle-orm/pg-core';
export const organizations = pgTable('organizations', {
id: uuid('id').defaultRandom().primaryKey(),
name: text('name').notNull(),
createdAt: timestamp('created_at').defaultNow().notNull(),
});

View file

@ -1,11 +1,24 @@
import 'reflect-metadata';
import helmet from 'helmet';
import { NestFactory } from '@nestjs/core';
import { Logger } from 'nestjs-pino';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { AppModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const app = await NestFactory.create(AppModule, { bufferLogs: true });
app.useLogger(app.get(Logger));
app.use(helmet());
app.enableCors();
const port = process.env.PORT ?? 3000;
const config = new DocumentBuilder()
.setTitle('CEO OS API')
.setVersion('0.1.0')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('docs', app, document);
const port = process.env.PORT ?? 3001;
await app.listen(port);
}

View file

@ -0,0 +1,6 @@
import { createClient } from '@supabase/supabase-js';
export const supabaseAdmin = createClient(
process.env.SUPABASE_URL ?? '',
process.env.SUPABASE_SERVICE_ROLE_KEY ?? '',
);