diff --git a/.dockerignore b/.dockerignore index 3345d9e..b2b49bc 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,11 @@ .env node_modules/ .vscode/ -client/ \ No newline at end of file +Dockerfile +.dockerignore +npm-debug.log +dist +.env.example +package-lock_copy.json +package_copy.json +docker.env.example \ No newline at end of file diff --git a/.husky/install.mjs b/.husky/install.mjs new file mode 100644 index 0000000..1fee59f --- /dev/null +++ b/.husky/install.mjs @@ -0,0 +1,5 @@ +if (process.env.NODE_ENV === 'production' || process.env.CI === 'true') { + process.exit(0) +} +const husky = (await import('husky')).default +console.log(husky()) diff --git a/Dockerfile b/Dockerfile index 06289b3..108e696 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,34 +1,50 @@ -FROM node:18 as builder +# LOCAL +FROM node:20-alpine AS dev -# Create app dir -WORKDIR /app +WORKDIR /usr/src/app -COPY package*.json ./ -COPY prisma ./prisma/ - -RUN npm install -D @swc/cli @swc/core -RUN npm install - -COPY . . - -RUN npm run build - -# Stage 2 -FROM node:18 - -WORKDIR /app - -RUN npm i pm2 -g - -COPY --from=builder /app/package*.json ./ -COPY --from=builder /app/prisma ./prisma/ -COPY --from=builder /app/dist ./dist/ -COPY --from=builder /app/docker.env ./ - -RUN mv docker.env .env +COPY --chown=node:node package*.json ./ +COPY --chown=node:node prisma ./prisma/ RUN npm ci -EXPOSE 8080 +COPY --chown=node:node . . -CMD ["npm", "run", "prod:start"] \ No newline at end of file +USER node + +# BUILD +FROM node:20-alpine AS build + +WORKDIR /usr/src/app + +COPY --chown=node:node package*.json ./ +COPY --chown=node:node --from=dev /usr/src/app/node_modules ./node_modules +COPY --chown=node:node --from=dev /usr/src/app/prisma ./prisma/ +COPY --chown=node:node .husky ./.husky +COPY --chown=node:node tsconfig.json tsconfig.build.json ./ +COPY --chown=node:node docker.env ./.env +COPY --chown=node:node . . + +RUN npm install husky -g + +RUN npm run prisma:generate + +RUN npm run build + +ENV NODE_ENV production + +RUN npm ci --only=production && npm cache clean --force + +USER node + +# PROD +FROM node:20-alpine as production + +COPY --chown=node:node --from=build /usr/src/app/node_modules ./node_modules +COPY --chown=node:node --from=build /usr/src/app/dist ./dist +COPY --chown=node:node --from=build /usr/src/app/prisma ./prisma +COPY --chown=node:node --from=build /usr/src/app/.husky ./.husky +COPY --chown=node:node --from=build /usr/src/app/.env ./ +COPY --chown=node:node --from=build /usr/src/app/package*.json ./ + +CMD ["npm", "run" , "prod"] diff --git a/docker-compose.yml b/docker-compose.yml index 7504ad1..00897c5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,21 +9,6 @@ networks: driver: bridge services: - api: - container_name: api - restart: unless-stopped - build: - context: . - dockerfile: Dockerfile - ports: - - 8080:8080 - depends_on: - - postgres - - redis - - localstack - env_file: - - docker.env - postgres: image: postgres:alpine restart: unless-stopped @@ -58,6 +43,21 @@ services: volumes: - redis:/data + api: + container_name: api + restart: unless-stopped + build: + context: . + dockerfile: Dockerfile + ports: + - 3000:3000 + depends_on: + - postgres + - redis + - minio + env_file: + - docker.env + volumes: postgres: name: backend-db diff --git a/docker.env.example b/docker.env.example index 431e733..8ae0f3f 100644 --- a/docker.env.example +++ b/docker.env.example @@ -7,7 +7,7 @@ POSTGRES_USER= POSTGRES_PASSWORD= DB_HOST=postgres -DATABASE_URL=postgresql://:@${DB_HOST}:/${POSTGRES_DB}?schema= +DATABASE_URL=postgresql://:@${DB_HOST}:/${POSTGRES_DB}?schema= # Redis REDIS_HOST=redis diff --git a/package-lock.json b/package-lock.json index 38b2e10..a09f8ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -33,6 +33,7 @@ "passport": "^0.7.0", "passport-jwt": "^4.0.1", "passport-local": "^1.0.0", + "prisma": "^5.8.1", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", "sharp": "^0.33.2" @@ -57,9 +58,9 @@ "eslint": "^8.42.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.0.0", + "husky": "^9.0.7", "jest": "^29.5.0", "prettier": "^3.0.0", - "prisma": "^5.8.1", "source-map-support": "^0.5.21", "supertest": "^6.3.3", "ts-jest": "^29.1.0", @@ -3852,14 +3853,12 @@ "node_modules/@prisma/debug": { "version": "5.9.0", "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.9.0.tgz", - "integrity": "sha512-3Uhj5YSPqaIfzJQ6JQzCNBXeBTy0x803fGIoo2tvP/KIEd+o4o49JxCQtKtP8aeef5iNh5Nn9Z25wDrdLjS80A==", - "devOptional": true + "integrity": "sha512-3Uhj5YSPqaIfzJQ6JQzCNBXeBTy0x803fGIoo2tvP/KIEd+o4o49JxCQtKtP8aeef5iNh5Nn9Z25wDrdLjS80A==" }, "node_modules/@prisma/engines": { "version": "5.9.0", "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.9.0.tgz", "integrity": "sha512-BH1fpXbMH09TwfZH5FVMJwRp6afEhKzqwebbCLdaEkJDuhxA//iwbILLqGFtGTgZbdBNUOThIK+UC3++5kWMTg==", - "devOptional": true, "hasInstallScript": true, "dependencies": { "@prisma/debug": "5.9.0", @@ -3871,14 +3870,12 @@ "node_modules/@prisma/engines-version": { "version": "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64", "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64.tgz", - "integrity": "sha512-HFl7275yF0FWbdcNvcSRbbu9JCBSLMcurYwvWc8WGDnpu7APxQo2ONtZrUggU3WxLxUJ2uBX+0GOFIcJeVeOOQ==", - "devOptional": true + "integrity": "sha512-HFl7275yF0FWbdcNvcSRbbu9JCBSLMcurYwvWc8WGDnpu7APxQo2ONtZrUggU3WxLxUJ2uBX+0GOFIcJeVeOOQ==" }, "node_modules/@prisma/fetch-engine": { "version": "5.9.0", "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.9.0.tgz", "integrity": "sha512-NL8Vm8Vl2d6NOSkkPGN5TTTz4s6cyCleXOzqtOFWzfKFJ4wtN2Shu7llOT+ykf6nDzh1lCN2JHUt1S6FGFZGig==", - "devOptional": true, "dependencies": { "@prisma/debug": "5.9.0", "@prisma/engines-version": "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64", @@ -3889,7 +3886,6 @@ "version": "5.9.0", "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.9.0.tgz", "integrity": "sha512-8CatX+E6eZxcOjJZe5hF8EXxdb5GsQTA/u7pdmUJSxGLacW9K3r5vDdgV8s22PubObQQ6979/rkCMItbCrG4Yg==", - "devOptional": true, "dependencies": { "@prisma/debug": "5.9.0" } @@ -8808,6 +8804,21 @@ "node": ">=10.17.0" } }, + "node_modules/husky": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.0.7.tgz", + "integrity": "sha512-vWdusw+y12DUEeoZqW1kplOFqk3tedGV8qlga8/SF6a3lOiWLqGZZQvfWvY0fQYdfiRi/u1DFNpudTSV9l1aCg==", + "dev": true, + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -11472,7 +11483,6 @@ "version": "5.9.0", "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.9.0.tgz", "integrity": "sha512-0UcOofjNuAnd227JMaPqZvP01dsUXw9EXB9iC8fyoZtfv7zkQ0ozxyjY1g+vcjFPOnNLICMnLHx+lM5BJZYqOQ==", - "devOptional": true, "hasInstallScript": true, "dependencies": { "@prisma/engines": "5.9.0" diff --git a/package.json b/package.json index b64bed1..0930386 100644 --- a/package.json +++ b/package.json @@ -12,14 +12,15 @@ "docker:build": "docker build -t api . && docker compose up -d", "docker:db": "docker compose -f docker-compose.db.yml up -d", "docker:seed": "docker exec -it api npm run prisma:seed", + "migrate:deploy": "prisma migrate deploy", "migrate:dev": "prisma migrate dev", "migrate:dev:create": "prisma migrate dev --create-only", "migrate:reset": "prisma migrate reset", "prisma:generate": "npx prisma generate", "prisma:seed": "prisma db seed", "prisma:studio": "npx prisma studio", - "prepare": "husky install", - "prod": "node dist/main", + "prepare": "husky .husky/install", + "prod": "npm run migrate:deploy && node dist/main", "start": "nest start", "test": "jest", "test:cov": "jest --coverage", @@ -52,6 +53,7 @@ "passport": "^0.7.0", "passport-jwt": "^4.0.1", "passport-local": "^1.0.0", + "prisma": "^5.8.1", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", "sharp": "^0.33.2" @@ -76,9 +78,9 @@ "eslint": "^8.42.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.0.0", + "husky": "^9.0.7", "jest": "^29.5.0", "prettier": "^3.0.0", - "prisma": "^5.8.1", "source-map-support": "^0.5.21", "supertest": "^6.3.3", "ts-jest": "^29.1.0", @@ -106,4 +108,4 @@ "coverageDirectory": "../coverage", "testEnvironment": "node" } -} +} \ No newline at end of file diff --git a/src/users/s3.service.ts b/src/users/s3.service.ts index 7b20f7b..1c51e0a 100644 --- a/src/users/s3.service.ts +++ b/src/users/s3.service.ts @@ -8,7 +8,7 @@ export class S3Service { constructor(@InjectS3() private readonly s3: S3) {} /** - * Returns the image url if the upload to minio as successful. Otherwise returns `false`. + * Returns the image url if the upload to minio was successful. */ async uploadImageToMinio(userID: string, buffer: Buffer): Promise { const compressedBuffer = await sharp(buffer)