From e48938040b995c759225c73e47bae19e08091b13 Mon Sep 17 00:00:00 2001 From: Eric Cabrel TIOGO Date: Thu, 23 May 2024 17:55:45 +0200 Subject: [PATCH] chore(backend): build the docker image --- apps/backend/.dockerignore | 211 +++++++++++++++++++++++++++++++++++++ apps/backend/CHANGELOG.md | 13 +++ apps/backend/Dockerfile | 64 +++++++++++ apps/backend/README.md | 149 ++++++++++++++------------ apps/backend/deploy.sh | 30 ++++++ apps/backend/env.d.ts | 28 +++++ apps/backend/package.json | 4 +- apps/backend/src/main.ts | 7 -- 8 files changed, 432 insertions(+), 74 deletions(-) create mode 100644 apps/backend/.dockerignore create mode 100644 apps/backend/CHANGELOG.md create mode 100644 apps/backend/Dockerfile create mode 100755 apps/backend/deploy.sh create mode 100644 apps/backend/env.d.ts diff --git a/apps/backend/.dockerignore b/apps/backend/.dockerignore new file mode 100644 index 00000000..660dc985 --- /dev/null +++ b/apps/backend/.dockerignore @@ -0,0 +1,211 @@ +### JetBrains template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Node template +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + diff --git a/apps/backend/CHANGELOG.md b/apps/backend/CHANGELOG.md new file mode 100644 index 00000000..4a8399e0 --- /dev/null +++ b/apps/backend/CHANGELOG.md @@ -0,0 +1,13 @@ +# @snipcode/backend + +## 1.1.0 + +### Minor Changes + +- 43e67ac: Merge the database schema and the application business rules into a single package + +### Patch Changes + +- Updated dependencies [43e67ac] + - @snipcode/domain@1.1.0 + - @snipcode/embed@1.1.4 diff --git a/apps/backend/Dockerfile b/apps/backend/Dockerfile new file mode 100644 index 00000000..fe7f251c --- /dev/null +++ b/apps/backend/Dockerfile @@ -0,0 +1,64 @@ +FROM node:20-buster as builder + +RUN mkdir app + +WORKDIR /app + +COPY . . + +RUN corepack enable && yarn set version berry + +RUN yarn install + +RUN npx prisma generate --schema=./packages/domain/prisma/schema.prisma + +RUN yarn build --filter=...@snipcode/backend + + +FROM node:20-alpine as schema-builder + +WORKDIR /app + +COPY --chown=node:node --from=builder /app/packages/domain/prisma/schema.prisma ./app/prisma/ + +# Generate the Prisma query engine for Node Alpine +RUN npx prisma generate --schema=./app/prisma/schema.prisma && \ + rm ./node_modules/.prisma/client/libquery_engine-rhel-openssl-1.0.x.so.node +# https://www.prisma.io/docs/orm/reference/prisma-schema-reference#binarytargets-options + +FROM node:20-alpine AS runner + +ARG APP_VERSION="1.0.0" + +ENV NODE_ENV=production +ENV APP_VERSION=${APP_VERSION} + +WORKDIR /app + +RUN corepack enable && yarn set version berry + +COPY --chown=node:node --from=builder /app/package.json . +COPY --chown=node:node --from=builder /app/.yarnrc.yml . + +COPY --chown=node:node --from=builder /app/apps/backend/dist/src ./apps/backend/src +COPY --chown=node:node --from=builder /app/apps/backend/package.json ./apps/backend + +COPY --chown=node:node --from=builder /app/packages/domain/package.json ./packages/domain/package.json +COPY --chown=node:node --from=builder /app/packages/domain/dist ./packages/domain/dist + +COPY --chown=node:node --from=builder /app/packages/utils/package.json ./packages/utils/package.json +COPY --chown=node:node --from=builder /app/packages/utils/dist ./packages/utils/dist + +COPY --chown=node:node --from=builder /app/packages/embed/package.json ./packages/embed/package.json +COPY --chown=node:node --from=builder /app/packages/embed/dist ./packages/embed/dist + +COPY --chown=node:node --from=builder /app/packages/logger/package.json ./packages/logger/package.json +COPY --chown=node:node --from=builder /app/packages/logger/dist ./packages/logger/dist + +RUN yarn workspaces focus --all --production && yarn cache clean --all + +COPY --chown=node:node --from=schema-builder /app/node_modules/.prisma/client ./node_modules/.prisma/client + +EXPOSE 7501 + +CMD ["node", "apps/backend/src/main.js"] diff --git a/apps/backend/README.md b/apps/backend/README.md index 83729419..7708f3a2 100644 --- a/apps/backend/README.md +++ b/apps/backend/README.md @@ -1,73 +1,92 @@ -

- Nest Logo -

- -[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 -[circleci-url]: https://circleci.com/gh/nestjs/nest - -

A progressive Node.js framework for building efficient and scalable server-side applications.

-

-NPM Version -Package License -NPM Downloads -CircleCI -Coverage -Discord -Backers on Open Collective -Sponsors on Open Collective - - Support us - -

- - -## Description - -[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. - -## Installation - -```bash -$ yarn install +# Snipcode Core + +This is the backend of Snipcode, containing the business logics related to . + +## Tech Stack +* Node.js +* TypeScript +* GraphQL +* MySQL +* Prisma + +## Prerequisites +Make sure you have this tools installed before running the project +* Node.js 20+ +* NPM or Yarn +* Docker +* AWS CLI v2 +* MySQL 8 on PlanetScale + +## Packages dependencies +We use Yarn workspace to create packages we can share with other applications. +These packages are located in the folder `packages`, so you might need to change the code of one or many packages to implement a feature. +Here are the packages used in this project: + +* [@snipcode/domain](../../packages/domain) +* [@snipcode/logger](../../packages/logger-old) +* [@snipcode/utils](../../packages/utils) + +## Set up the project +Delete the existing folders output from build commands +```shell +yarn clean ``` - -## Running the app - -```bash -# development -$ yarn run start - -# watch mode -$ yarn run start:dev - -# production mode -$ yarn run start:prod +Install node modules +````shell +yarn install +```` +Create configuration file from the template +```shell +cp .env.template .env + +# Edit configuration to match your local environment and save +nano .env ``` -## Test - +**Environment variables list** + +| Variable | Description | +|----------------------|--------------------------------------------------------------------------| +| NODE_ENV | Node.js environment (default: development) | +| HOST | Host name where the application is running (default: http://localhost) | +| PORT | Port number of the application (default: 7501) | +| ENABLE_INTROSPECTION | Enable/Disable GraphQL introspection (must `false` in production) | +| DATABASE_URL | URL of the database | +| ADMIN_PASSWORD | Password of the default admin user. | +| CONVERTKIT_API_KEY | ConvertKit API key | +| CONVERTKIT_FORM_ID | ConvertKit Form ID | +| CONVERTKIT_TAG_ID | ConvertKit Tag ID | +| REQUEST_TIMEOUT | Max duration of a request (default: 30 seconds) | +| GITHUB_CLIENT_ID | GitHub application client ID for authentication with GitHub | +| GITHUB_CLIENT_SECRET | GitHub application client secret for authentication with GitHub | +| WEB_APP_URL | URL of the frontend the application that communicates with this app | +| WEB_AUTH_SUCCESS_URL | Callback URL of the frontend application when the authentication succeed | +| WEB_AUTH_ERROR_URL | Callback URL of the frontend application when the authentication failed | +| SESSION_LIFETIME | The session's lifetime when a user authenticate (default: 90 days) | +| SENTRY_DSN | Sentry DSN | +| SENTRY_ENABLED | Enable/Disable Sentry | + +Start the application ```bash -# unit tests -$ yarn run test - -# e2e tests -$ yarn run test:e2e - -# test coverage -$ yarn run test:cov +yarn dev ``` +The application will be launched by [Nodemon](https://nodemon.com). -## Support - -Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). +Open [http://localhost:7501/graphql](http://localhost:7501/graphql) in your browser and use Apollo studio explorer to test your GraphQL queries and mutations. -## Stay in touch - -- Author - [Kamil Myƛliwiec](https://kamilmysliwiec.com) -- Website - [https://nestjs.com](https://nestjs.com/) -- Twitter - [@nestframework](https://twitter.com/nestframework) - -## License +## Running tests +Run the command below to run all the tests +```shell +yarn test +``` +To run a specific test file, append the filename after the command +```shell +yarn test controller.test.ts +``` -Nest is [MIT licensed](LICENSE). +## Lint the project +ESLint and Prettier are used to normalize the code style across the project. +Linting the code make sure there is no error +```shell +yarn lint +``` diff --git a/apps/backend/deploy.sh b/apps/backend/deploy.sh new file mode 100755 index 00000000..9c81b75f --- /dev/null +++ b/apps/backend/deploy.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +start=$(date +"%s") + +DOCKER_IMAGE_TAG=$IMAGE_TAG + +ssh -p ${SPORT} ${SUSER}@${SNAME} -i key.txt -t -t -o StrictHostKeyChecking=no << ENDSSH +cd snipcode + +docker pull $DOCKER_IMAGE_TAG + +API_CONTAINER_NAME=snipcode-core +if [ "$(docker ps -qa -f name=\$API_CONTAINER_NAME)" ]; then + if [ "$(docker ps -q -f name=\$API_CONTAINER_NAME)" ]; then + echo "[API] Container is running -> stopping it..." + docker stop \$API_CONTAINER_NAME; + fi + docker rm \$API_CONTAINER_NAME; +fi + +docker run -d -p 7501:7501 -v $(pwd)/logs:/app/logs --name snipcode-core --rm --env-file .env $DOCKER_IMAGE_TAG + +exit +ENDSSH + +end=$(date +"%s") + +diff=$(($end - $start)) + +echo "Deployed in : ${diff}s" diff --git a/apps/backend/env.d.ts b/apps/backend/env.d.ts new file mode 100644 index 00000000..b694eb34 --- /dev/null +++ b/apps/backend/env.d.ts @@ -0,0 +1,28 @@ +export type EnvironmentVariables = { + ADMIN_PASSWORD: string; + APP_VERSION: string; + CONVERTKIT_API_KEY: string; + CONVERTKIT_FORM_ID: string; + CONVERTKIT_TAG_ID: string; + DATABASE_URL: string; + ENABLE_INTROSPECTION: string; + GITHUB_CLIENT_ID: string; + GITHUB_CLIENT_SECRET: string; + HOST: string; + PORT: string; + REQUEST_TIMEOUT: string; + SENTRY_DSN: string; + SESSION_LIFETIME: string; + SNIPPET_RENDERER_URL: string; + WEB_APP_URL: string; + WEB_AUTH_ERROR_URL: string; + WEB_AUTH_SUCCESS_URL: string; +}; + +declare global { + namespace NodeJS { + type ProcessEnv = EnvironmentVariables; + } +} + +export {}; diff --git a/apps/backend/package.json b/apps/backend/package.json index ef48005d..891fa5a9 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -2,8 +2,8 @@ "name": "@snipcode/backend", "version": "1.1.0", "private": true, - "description": "Snipcode core backend", - "main": "dist/index.js", + "description": "Core backend of the application", + "main": "dist/src/main.js", "license": "AGPL-3.0", "scripts": { "build": "nest build", diff --git a/apps/backend/src/main.ts b/apps/backend/src/main.ts index 8254db4c..d952ba8f 100644 --- a/apps/backend/src/main.ts +++ b/apps/backend/src/main.ts @@ -16,13 +16,6 @@ const bootstrap = async () => { await app.listen(port, () => { logger.log(`Server ready at ${host}:${port}`); - const object = { - age: 23, - birthDate: new Date(), - name: 'marion', - }; - - logger.log(object); // logger.log(`Server ready at ${host}:${port}${graphqlServer.graphqlPath}`); }); };