diff --git a/backend/.gitignore b/backend/.gitignore index 4b56acf..05c2f75 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -54,3 +54,5 @@ pids # Diagnostic reports (https://nodejs.org/api/report.html) report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +prisma/generated diff --git a/backend/package.json b/backend/package.json index 1ff73af..4f79cd8 100644 --- a/backend/package.json +++ b/backend/package.json @@ -17,12 +17,18 @@ "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" + "test:e2e": "jest --config ./test/jest-e2e.json", + "db:push": "prisma db push", + "db:view": "prisma studio", + "db:generate": "prisma generate" }, "dependencies": { "@nestjs/common": "^11.0.1", "@nestjs/core": "^11.0.1", + "@nestjs/mapped-types": "*", "@nestjs/platform-express": "^11.0.1", + "@prisma/client": "^6.10.1", + "prisma": "^6.10.1", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1" }, diff --git a/backend/prisma/schema.prisma b/backend/prisma/schema.prisma new file mode 100644 index 0000000..a45b912 --- /dev/null +++ b/backend/prisma/schema.prisma @@ -0,0 +1,23 @@ +generator client { + provider = "prisma-client-js" + output = "./generated" +} + +datasource db { + provider = "postgresql" + url = env("POSTGRES_URI") +} + +model User { + id String @id @default(uuid()) + email String @unique + password String + name String @unique + displayName String @map("display_name") + avatar String? + bio String? + createdAt DateTime @default(now()) @map("created_at") + updatedAt DateTime @updatedAt @map("updated_at") + + @@map("users") +} diff --git a/backend/src/app.controller.spec.ts b/backend/src/app.controller.spec.ts deleted file mode 100644 index d22f389..0000000 --- a/backend/src/app.controller.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { AppController } from './app.controller'; -import { AppService } from './app.service'; - -describe('AppController', () => { - let appController: AppController; - - beforeEach(async () => { - const app: TestingModule = await Test.createTestingModule({ - controllers: [AppController], - providers: [AppService], - }).compile(); - - appController = app.get(AppController); - }); - - describe('root', () => { - it('should return "Hello World!"', () => { - expect(appController.getHello()).toBe('Hello World!'); - }); - }); -}); diff --git a/backend/src/app.controller.ts b/backend/src/app.controller.ts deleted file mode 100644 index cce879e..0000000 --- a/backend/src/app.controller.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Controller, Get } from '@nestjs/common'; -import { AppService } from './app.service'; - -@Controller() -export class AppController { - constructor(private readonly appService: AppService) {} - - @Get() - getHello(): string { - return this.appService.getHello(); - } -} diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts deleted file mode 100644 index 8662803..0000000 --- a/backend/src/app.module.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Module } from '@nestjs/common'; -import { AppController } from './app.controller'; -import { AppService } from './app.service'; - -@Module({ - imports: [], - controllers: [AppController], - providers: [AppService], -}) -export class AppModule {} diff --git a/backend/src/app.service.ts b/backend/src/app.service.ts deleted file mode 100644 index 927d7cc..0000000 --- a/backend/src/app.service.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Injectable } from '@nestjs/common'; - -@Injectable() -export class AppService { - getHello(): string { - return 'Hello World!'; - } -} diff --git a/backend/src/core/core.module.ts b/backend/src/core/core.module.ts new file mode 100644 index 0000000..a7a6e70 --- /dev/null +++ b/backend/src/core/core.module.ts @@ -0,0 +1,7 @@ +import { Module } from '@nestjs/common'; +import { PrismaModule } from './prisma/prisma.module'; + +@Module({ + imports: [PrismaModule], +}) +export class CoreModule {} diff --git a/backend/src/core/prisma/prisma.module.ts b/backend/src/core/prisma/prisma.module.ts new file mode 100644 index 0000000..d80c9f3 --- /dev/null +++ b/backend/src/core/prisma/prisma.module.ts @@ -0,0 +1,9 @@ +import { Global, Module } from '@nestjs/common'; +import { PrismaService } from './prisma.service'; + +@Global() +@Module({ + providers: [PrismaService], + exports: [PrismaService] +}) +export class PrismaModule {} diff --git a/backend/src/core/prisma/prisma.service.ts b/backend/src/core/prisma/prisma.service.ts new file mode 100644 index 0000000..79c28d6 --- /dev/null +++ b/backend/src/core/prisma/prisma.service.ts @@ -0,0 +1,13 @@ +import { PrismaClient } from '@/prisma/generated'; +import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common'; + +@Injectable() +export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy { + async onModuleInit() { + await this.$connect(); + } + + async onModuleDestroy() { + await this.$disconnect(); + } +} diff --git a/backend/src/main.ts b/backend/src/main.ts index f76bc8d..96b83de 100644 --- a/backend/src/main.ts +++ b/backend/src/main.ts @@ -1,8 +1,8 @@ +import { CoreModule } from '@/src/core/core.module'; import { NestFactory } from '@nestjs/core'; -import { AppModule } from './app.module'; async function bootstrap() { - const app = await NestFactory.create(AppModule); + const app = await NestFactory.create(CoreModule); await app.listen(process.env.PORT ?? 3000); } bootstrap(); diff --git a/backend/test/app.e2e-spec.ts b/backend/test/app.e2e-spec.ts deleted file mode 100644 index 4df6580..0000000 --- a/backend/test/app.e2e-spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Test, TestingModule } from '@nestjs/testing'; -import { INestApplication } from '@nestjs/common'; -import * as request from 'supertest'; -import { App } from 'supertest/types'; -import { AppModule } from './../src/app.module'; - -describe('AppController (e2e)', () => { - let app: INestApplication; - - beforeEach(async () => { - const moduleFixture: TestingModule = await Test.createTestingModule({ - imports: [AppModule], - }).compile(); - - app = moduleFixture.createNestApplication(); - await app.init(); - }); - - it('/ (GET)', () => { - return request(app.getHttpServer()) - .get('/') - .expect(200) - .expect('Hello World!'); - }); -}); diff --git a/backend/yarn.lock b/backend/yarn.lock index ca37354..738aadd 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -1027,6 +1027,11 @@ path-to-regexp "8.2.0" tslib "2.8.1" +"@nestjs/mapped-types@*": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-2.1.0.tgz#b9b536b7c3571567aa1d0223db8baa1a51505a19" + integrity sha512-W+n+rM69XsFdwORF11UqJahn4J3xi4g/ZEOlJNL6KoW5ygWSmBB2p0S2BZ4FQeS/NDH72e6xIcu35SfJnE8bXw== + "@nestjs/platform-express@^11.0.1": version "11.1.3" resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-11.1.3.tgz#bf470f2e270ca9daa930974476dd0d7d62879556" @@ -1101,6 +1106,54 @@ resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.7.tgz#eb5014dfd0b03e7f3ba2eeeff506eed89b028058" integrity sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg== +"@prisma/client@^6.10.1": + version "6.10.1" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-6.10.1.tgz#f5cf8731727ea833b53524f300458d0adbb5c58f" + integrity sha512-Re4pMlcUsQsUTAYMK7EJ4Bw2kg3WfZAAlr8GjORJaK4VOP6LxRQUQ1TuLnxcF42XqGkWQ36q5CQF1yVadANQ6w== + +"@prisma/config@6.10.1": + version "6.10.1" + resolved "https://registry.yarnpkg.com/@prisma/config/-/config-6.10.1.tgz#d67364aa330af3c5069009f987863806ce2acaad" + integrity sha512-kz4/bnqrOrzWo8KzYguN0cden4CzLJJ+2VSpKtF8utHS3l1JS0Lhv6BLwpOX6X9yNreTbZQZwewb+/BMPDCIYQ== + dependencies: + jiti "2.4.2" + +"@prisma/debug@6.10.1": + version "6.10.1" + resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-6.10.1.tgz#8d4b2219c27b09ba747148785e9f0b7efd1ae343" + integrity sha512-k2YT53cWxv9OLjW4zSYTZ6Z7j0gPfCzcr2Mj99qsuvlxr8WAKSZ2NcSR0zLf/mP4oxnYG842IMj3utTgcd7CaA== + +"@prisma/engines-version@6.10.1-1.9b628578b3b7cae625e8c927178f15a170e74a9c": + version "6.10.1-1.9b628578b3b7cae625e8c927178f15a170e74a9c" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-6.10.1-1.9b628578b3b7cae625e8c927178f15a170e74a9c.tgz#0251f10e7b04e0a5d05d15b9823da8bc4fff2a5c" + integrity sha512-ZJFTsEqapiTYVzXya6TUKYDFnSWCNegfUiG5ik9fleQva5Sk3DNyyUi7X1+0ZxWFHwHDr6BZV5Vm+iwP+LlciA== + +"@prisma/engines@6.10.1": + version "6.10.1" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-6.10.1.tgz#bd3b2d604498b756ecd7c76698cae9221f962805" + integrity sha512-Q07P5rS2iPwk2IQr/rUQJ42tHjpPyFcbiH7PXZlV81Ryr9NYIgdxcUrwgVOWVm5T7ap02C0dNd1dpnNcSWig8A== + dependencies: + "@prisma/debug" "6.10.1" + "@prisma/engines-version" "6.10.1-1.9b628578b3b7cae625e8c927178f15a170e74a9c" + "@prisma/fetch-engine" "6.10.1" + "@prisma/get-platform" "6.10.1" + +"@prisma/fetch-engine@6.10.1": + version "6.10.1" + resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-6.10.1.tgz#321aa7a94305c754d2da0cbb451b179b24edd37a" + integrity sha512-clmbG/Jgmrc/n6Y77QcBmAUlq9LrwI9Dbgy4pq5jeEARBpRCWJDJ7PWW1P8p0LfFU0i5fsyO7FqRzRB8mkdS4g== + dependencies: + "@prisma/debug" "6.10.1" + "@prisma/engines-version" "6.10.1-1.9b628578b3b7cae625e8c927178f15a170e74a9c" + "@prisma/get-platform" "6.10.1" + +"@prisma/get-platform@6.10.1": + version "6.10.1" + resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-6.10.1.tgz#28460715162754a7867c389b55485cbb18b75268" + integrity sha512-4CY5ndKylcsce9Mv+VWp5obbR2/86SHOLVV053pwIkhVtT9C9A83yqiqI/5kJM9T1v1u1qco/bYjDKycmei9HA== + dependencies: + "@prisma/debug" "6.10.1" + "@sec-ant/readable-stream@^0.4.1": version "0.4.1" resolved "https://registry.yarnpkg.com/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz#60de891bb126abfdc5410fdc6166aca065f10a0c" @@ -3986,6 +4039,11 @@ jest@^29.7.0: import-local "^3.0.2" jest-cli "^29.7.0" +jiti@2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-2.4.2.tgz#d19b7732ebb6116b06e2038da74a55366faef560" + integrity sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A== + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -4637,6 +4695,14 @@ pretty-format@^29.0.0, pretty-format@^29.7.0: ansi-styles "^5.0.0" react-is "^18.0.0" +prisma@^6.10.1: + version "6.10.1" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-6.10.1.tgz#2864034879c492359684193720e9e4b4a0bd20c9" + integrity sha512-khhlC/G49E4+uyA3T3H5PRBut486HD2bDqE2+rvkU0pwk9IAqGFacLFUyIx9Uw+W2eCtf6XGwsp+/strUwMNPw== + dependencies: + "@prisma/config" "6.10.1" + "@prisma/engines" "6.10.1" + prompts@^2.0.1: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"