From 3470d598f20c799c2bb85cf451fbc576b143d1ce Mon Sep 17 00:00:00 2001 From: rckrdmrd Date: Sun, 4 Jan 2026 07:14:31 -0600 Subject: [PATCH] Initial commit --- package.json | 84 +++++++++++++++++++++++++++++++++ service.descriptor.yml | 58 +++++++++++++++++++++++ src/app.module.ts | 32 +++++++++++++ src/config/index.ts | 23 +++++++++ src/main.ts | 36 ++++++++++++++ src/modules/auth/auth.module.ts | 19 ++++++++ src/shared/types/index.ts | 27 +++++++++++ tsconfig.json | 26 ++++++++++ 8 files changed, 305 insertions(+) create mode 100644 package.json create mode 100644 service.descriptor.yml create mode 100644 src/app.module.ts create mode 100644 src/config/index.ts create mode 100644 src/main.ts create mode 100644 src/modules/auth/auth.module.ts create mode 100644 src/shared/types/index.ts create mode 100644 tsconfig.json diff --git a/package.json b/package.json new file mode 100644 index 0000000..2622d64 --- /dev/null +++ b/package.json @@ -0,0 +1,84 @@ +{ + "name": "@inmobiliaria-analytics/backend", + "version": "0.1.0", + "description": "Inmobiliaria Analytics - Backend API", + "author": "Inmobiliaria Analytics Team", + "private": true, + "license": "UNLICENSED", + "scripts": { + "build": "nest build", + "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"", + "start": "nest start", + "start:dev": "nest start --watch", + "start:debug": "nest start --debug --watch", + "start:prod": "node dist/main", + "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", + "test": "jest", + "test:watch": "jest --watch", + "test:cov": "jest --coverage", + "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand", + "test:e2e": "jest --config ./test/jest-e2e.json", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@nestjs/common": "^10.3.0", + "@nestjs/config": "^3.1.1", + "@nestjs/core": "^10.3.0", + "@nestjs/jwt": "^10.2.0", + "@nestjs/passport": "^10.0.3", + "@nestjs/platform-express": "^10.3.0", + "@nestjs/typeorm": "^10.0.1", + "bcrypt": "^5.1.1", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.1", + "passport": "^0.7.0", + "passport-jwt": "^4.0.1", + "passport-local": "^1.0.0", + "pg": "^8.11.3", + "reflect-metadata": "^0.2.1", + "rxjs": "^7.8.1", + "typeorm": "^0.3.19" + }, + "devDependencies": { + "@nestjs/cli": "^10.3.0", + "@nestjs/schematics": "^10.1.0", + "@nestjs/testing": "^10.3.0", + "@types/bcrypt": "^5.0.2", + "@types/express": "^4.17.21", + "@types/jest": "^29.5.11", + "@types/node": "^20.10.6", + "@types/passport-jwt": "^4.0.0", + "@types/passport-local": "^1.0.38", + "@typescript-eslint/eslint-plugin": "^6.18.0", + "@typescript-eslint/parser": "^6.18.0", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.2", + "jest": "^29.7.0", + "prettier": "^3.1.1", + "source-map-support": "^0.5.21", + "supertest": "^6.3.4", + "ts-jest": "^29.1.1", + "ts-loader": "^9.5.1", + "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", + "typescript": "^5.3.3" + }, + "jest": { + "moduleFileExtensions": [ + "js", + "json", + "ts" + ], + "rootDir": "src", + "testRegex": ".*\\.spec\\.ts$", + "transform": { + "^.+\\.(t|j)s$": "ts-jest" + }, + "collectCoverageFrom": [ + "**/*.(t|j)s" + ], + "coverageDirectory": "../coverage", + "testEnvironment": "node" + } +} diff --git a/service.descriptor.yml b/service.descriptor.yml new file mode 100644 index 0000000..bea8924 --- /dev/null +++ b/service.descriptor.yml @@ -0,0 +1,58 @@ +# Service Descriptor - Inmobiliaria Analytics API +# Generado automáticamente durante migración + +service: + name: inmobiliaria-api + type: backend_api + framework: nestjs + runtime: node + version: "20" + description: "API de analytics inmobiliaria" + owner_agent: NEXUS-BACKEND + +repository: + name: workspace-v1 + path: projects/inmobiliaria-analytics/apps/backend + main_branch: main + +ports: + internal: 3100 + registry_ref: projects.inmobiliaria.services.api + protocol: http + +domains: + registry_ref: projects.inmobiliaria.domains + overrides: + local: api.inmobiliaria.localhost + +database: + registry_ref: databases.inmobiliaria + role: runtime + schemas: + - public + - properties + - analytics + +docker: + dockerfile: Dockerfile + context: . + networks: + - inmobiliaria_${ENV:-local} + - infra_shared + labels: + traefik: + enable: true + rule: "Host(`api.inmobiliaria.localhost`)" + +healthcheck: + path: /health + interval: 30s + timeout: 10s + retries: 3 + +metadata: + created: "2025-12-26" + updated: "2025-12-26" + maintainers: + - tech-leader + status: planned diff --git a/src/app.module.ts b/src/app.module.ts new file mode 100644 index 0000000..8d13052 --- /dev/null +++ b/src/app.module.ts @@ -0,0 +1,32 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { appConfig, databaseConfig, jwtConfig } from './config'; +import { AuthModule } from './modules/auth/auth.module'; + +@Module({ + imports: [ + ConfigModule.forRoot({ + isGlobal: true, + load: [appConfig, databaseConfig, jwtConfig], + }), + TypeOrmModule.forRootAsync({ + useFactory: (configService) => ({ + type: 'postgres', + host: configService.get('database.host'), + port: configService.get('database.port'), + username: configService.get('database.username'), + password: configService.get('database.password'), + database: configService.get('database.database'), + entities: [__dirname + '/**/*.entity{.ts,.js}'], + synchronize: configService.get('database.synchronize'), + logging: configService.get('database.logging'), + }), + inject: [ConfigModule], + }), + AuthModule, + ], + controllers: [], + providers: [], +}) +export class AppModule {} diff --git a/src/config/index.ts b/src/config/index.ts new file mode 100644 index 0000000..6307a1f --- /dev/null +++ b/src/config/index.ts @@ -0,0 +1,23 @@ +import { registerAs } from '@nestjs/config'; + +export const databaseConfig = registerAs('database', () => ({ + type: 'postgres', + host: process.env.DB_HOST || 'localhost', + port: parseInt(process.env.DB_PORT, 10) || 5432, + username: process.env.DB_USERNAME || 'postgres', + password: process.env.DB_PASSWORD || 'postgres', + database: process.env.DB_NAME || 'inmobiliaria_analytics', + synchronize: process.env.NODE_ENV !== 'production', + logging: process.env.NODE_ENV === 'development', +})); + +export const jwtConfig = registerAs('jwt', () => ({ + secret: process.env.JWT_SECRET || 'change-me-in-production', + expiresIn: process.env.JWT_EXPIRES_IN || '1d', +})); + +export const appConfig = registerAs('app', () => ({ + port: parseInt(process.env.PORT, 10) || 3000, + environment: process.env.NODE_ENV || 'development', + apiPrefix: process.env.API_PREFIX || 'api', +})); diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..9e508ce --- /dev/null +++ b/src/main.ts @@ -0,0 +1,36 @@ +import { NestFactory } from '@nestjs/core'; +import { ValidationPipe } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { AppModule } from './app.module'; + +async function bootstrap() { + const app = await NestFactory.create(AppModule); + const configService = app.get(ConfigService); + + // Global validation pipe + app.useGlobalPipes( + new ValidationPipe({ + whitelist: true, + forbidNonWhitelisted: true, + transform: true, + }), + ); + + // CORS configuration + app.enableCors({ + origin: process.env.CORS_ORIGIN || '*', + credentials: true, + }); + + // API prefix + const apiPrefix = configService.get('app.apiPrefix', 'api'); + app.setGlobalPrefix(apiPrefix); + + // Start server + const port = configService.get('app.port', 3000); + await app.listen(port); + + console.log(`Inmobiliaria Analytics API running on: http://localhost:${port}/${apiPrefix}`); +} + +bootstrap(); diff --git a/src/modules/auth/auth.module.ts b/src/modules/auth/auth.module.ts new file mode 100644 index 0000000..fe44ab6 --- /dev/null +++ b/src/modules/auth/auth.module.ts @@ -0,0 +1,19 @@ +import { Module } from '@nestjs/common'; + +/** + * Authentication module placeholder + * + * TODO: Implement authentication logic including: + * - User authentication service + * - JWT strategy + * - Local strategy + * - Auth controller + * - Auth guards + */ +@Module({ + imports: [], + controllers: [], + providers: [], + exports: [], +}) +export class AuthModule {} diff --git a/src/shared/types/index.ts b/src/shared/types/index.ts new file mode 100644 index 0000000..3114e8c --- /dev/null +++ b/src/shared/types/index.ts @@ -0,0 +1,27 @@ +/** + * Shared type definitions for Inmobiliaria Analytics + */ + +export interface ApiResponse { + success: boolean; + data?: T; + error?: string; + message?: string; +} + +export interface PaginatedResponse { + data: T[]; + total: number; + page: number; + limit: number; + totalPages: number; +} + +export interface JwtPayload { + sub: string; + email: string; + iat?: number; + exp?: number; +} + +export type Environment = 'development' | 'production' | 'test'; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..c86586b --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "module": "commonjs", + "declaration": true, + "removeComments": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "target": "ES2021", + "sourceMap": true, + "outDir": "./dist", + "baseUrl": "./", + "incremental": true, + "skipLibCheck": true, + "strictNullChecks": false, + "noImplicitAny": false, + "strictBindCallApply": false, + "forceConsistentCasingInFileNames": false, + "noFallthroughCasesInSwitch": false, + "paths": { + "@/*": ["src/*"] + } + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "test", "**/*spec.ts"] +}