diff --git a/.circleci/config.yml b/.circleci/config.yml index fa1c7c57e96..a2848c8ed5a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,7 +12,7 @@ aliases: echo ' [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"' >> $BASH_ENV nvm install v18 nvm alias default v18 - echo 'export NODE_OPTIONS=--max-old-space-size=7000' >> $BASH_ENV + echo 'export NODE_OPTIONS=--max-old-space-size=12288' >> $BASH_ENV echo 'export NG_CLI_ANALYTICS=false' >> $BASH_ENV source $BASH_ENV nvm use v18 diff --git a/.deploy/api/Dockerfile b/.deploy/api/Dockerfile index 068893ac24d..b38ffdd8bf0 100644 --- a/.deploy/api/Dockerfile +++ b/.deploy/api/Dockerfile @@ -89,6 +89,7 @@ ARG APP_MAGIC_SIGN_URL ARG COMPANY_LINK ARG COMPANY_NAME ARG OTEL_ENABLED +ARG OTEL_PROVIDER ARG OTEL_EXPORTER_OTLP_HEADERS ARG OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ARG REDIS_ENABLED @@ -288,7 +289,7 @@ USER node:node ENV CI=true -ENV NODE_OPTIONS=${NODE_OPTIONS:-"--max-old-space-size=7000"} +ENV NODE_OPTIONS=${NODE_OPTIONS:-"--max-old-space-size=12288"} ENV NODE_ENV=${NODE_ENV:-production} ENV API_HOST=${API_HOST:-api} ENV API_PORT=${API_PORT:-3000} @@ -304,7 +305,7 @@ ENV DB_NAME=${DB_NAME:-postgres} ENV DB_PORT=${DB_PORT:-5432} ENV DB_USER=${DB_USER} ENV DB_PASS=${DB_PASS} -ENV DB_TYPE=${DB_TYPE:-sqlite} +ENV DB_TYPE=${DB_TYPE:-better-sqlite3} ENV DB_SSL_MODE=${DB_SSL_MODE} ENV DB_CA_CERT=${DB_CA_CERT} ENV DB_POOL_SIZE=${DB_POOL_SIZE} @@ -380,6 +381,7 @@ ENV APP_MAGIC_SIGN_URL=${APP_MAGIC_SIGN_URL} ENV COMPANY_LINK=${COMPANY_LINK} ENV COMPANY_NAME=${COMPANY_NAME} ENV OTEL_ENABLED=${OTEL_ENABLED} +ENV OTEL_PROVIDER=${OTEL_PROVIDER} ENV OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT} ENV OTEL_EXPORTER_OTLP_HEADERS=${OTEL_EXPORTER_OTLP_HEADERS} ENV REDIS_ENABLED=${REDIS_ENABLED} diff --git a/.deploy/k8s/k8s-manifest.civo.demo.yaml b/.deploy/k8s/k8s-manifest.civo.demo.yaml index 95498ee0261..c1ffde8dda4 100644 --- a/.deploy/k8s/k8s-manifest.civo.demo.yaml +++ b/.deploy/k8s/k8s-manifest.civo.demo.yaml @@ -77,6 +77,8 @@ spec: value: '$CLOUD_PROVIDER' - name: OTEL_ENABLED value: '$OTEL_ENABLED' + - name: OTEL_PROVIDER + value: '$OTEL_PROVIDER' - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT value: '$OTEL_EXPORTER_OTLP_TRACES_ENDPOINT' - name: OTEL_EXPORTER_OTLP_HEADERS diff --git a/.deploy/k8s/k8s-manifest.civo.prod.yaml b/.deploy/k8s/k8s-manifest.civo.prod.yaml index 58d5a724d29..cff7dad7b5c 100644 --- a/.deploy/k8s/k8s-manifest.civo.prod.yaml +++ b/.deploy/k8s/k8s-manifest.civo.prod.yaml @@ -187,6 +187,8 @@ spec: value: '$JITSU_SERVER_WRITE_KEY' - name: OTEL_ENABLED value: '$OTEL_ENABLED' + - name: OTEL_PROVIDER + value: '$OTEL_PROVIDER' - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT value: '$OTEL_EXPORTER_OTLP_TRACES_ENDPOINT' - name: OTEL_EXPORTER_OTLP_HEADERS diff --git a/.deploy/k8s/k8s-manifest.civo.stage.yaml b/.deploy/k8s/k8s-manifest.civo.stage.yaml index c30c02ed46b..cdf7ce5fc2b 100644 --- a/.deploy/k8s/k8s-manifest.civo.stage.yaml +++ b/.deploy/k8s/k8s-manifest.civo.stage.yaml @@ -181,6 +181,8 @@ spec: value: '$JITSU_SERVER_WRITE_KEY' - name: OTEL_ENABLED value: '$OTEL_ENABLED' + - name: OTEL_PROVIDER + value: '$OTEL_PROVIDER' - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT value: '$OTEL_EXPORTER_OTLP_TRACES_ENDPOINT' - name: OTEL_EXPORTER_OTLP_HEADERS diff --git a/.deploy/k8s/k8s-manifest.cw.demo.yaml b/.deploy/k8s/k8s-manifest.cw.demo.yaml index 5b8fb8e70d0..ce132612b6a 100644 --- a/.deploy/k8s/k8s-manifest.cw.demo.yaml +++ b/.deploy/k8s/k8s-manifest.cw.demo.yaml @@ -92,6 +92,8 @@ spec: value: '86400' - name: OTEL_ENABLED value: '$OTEL_ENABLED' + - name: OTEL_PROVIDER + value: '$OTEL_PROVIDER' - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT value: '$OTEL_EXPORTER_OTLP_TRACES_ENDPOINT' - name: OTEL_EXPORTER_OTLP_HEADERS diff --git a/.deploy/k8s/k8s-manifest.cw.prod.yaml b/.deploy/k8s/k8s-manifest.cw.prod.yaml index f587f9051b2..5dbcdad00ec 100644 --- a/.deploy/k8s/k8s-manifest.cw.prod.yaml +++ b/.deploy/k8s/k8s-manifest.cw.prod.yaml @@ -213,6 +213,8 @@ spec: value: '$JITSU_SERVER_WRITE_KEY' - name: OTEL_ENABLED value: '$OTEL_ENABLED' + - name: OTEL_PROVIDER + value: '$OTEL_PROVIDER' - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT value: '$OTEL_EXPORTER_OTLP_TRACES_ENDPOINT' - name: OTEL_EXPORTER_OTLP_HEADERS diff --git a/.deploy/k8s/k8s-manifest.cw.stage.yaml b/.deploy/k8s/k8s-manifest.cw.stage.yaml index 01bf90fd965..232b2249aa2 100644 --- a/.deploy/k8s/k8s-manifest.cw.stage.yaml +++ b/.deploy/k8s/k8s-manifest.cw.stage.yaml @@ -207,6 +207,8 @@ spec: value: '$JITSU_SERVER_WRITE_KEY' - name: OTEL_ENABLED value: '$OTEL_ENABLED' + - name: OTEL_PROVIDER + value: '$OTEL_PROVIDER' - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT value: '$OTEL_EXPORTER_OTLP_TRACES_ENDPOINT' - name: OTEL_EXPORTER_OTLP_HEADERS diff --git a/.deploy/k8s/k8s-manifest.demo.yaml b/.deploy/k8s/k8s-manifest.demo.yaml index 59f6ac26d5a..24694a7f8c7 100644 --- a/.deploy/k8s/k8s-manifest.demo.yaml +++ b/.deploy/k8s/k8s-manifest.demo.yaml @@ -95,6 +95,8 @@ spec: value: '86400' - name: OTEL_ENABLED value: '$OTEL_ENABLED' + - name: OTEL_PROVIDER + value: '$OTEL_PROVIDER' - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT value: '$OTEL_EXPORTER_OTLP_TRACES_ENDPOINT' - name: OTEL_EXPORTER_OTLP_HEADERS diff --git a/.deploy/k8s/k8s-manifest.prod.yaml b/.deploy/k8s/k8s-manifest.prod.yaml index 9483d5157dd..170c175cc60 100644 --- a/.deploy/k8s/k8s-manifest.prod.yaml +++ b/.deploy/k8s/k8s-manifest.prod.yaml @@ -211,6 +211,8 @@ spec: value: '$JITSU_SERVER_WRITE_KEY' - name: OTEL_ENABLED value: '$OTEL_ENABLED' + - name: OTEL_PROVIDER + value: '$OTEL_PROVIDER' - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT value: '$OTEL_EXPORTER_OTLP_TRACES_ENDPOINT' - name: OTEL_EXPORTER_OTLP_HEADERS diff --git a/.deploy/k8s/k8s-manifest.stage.yaml b/.deploy/k8s/k8s-manifest.stage.yaml index 298d8602b61..19a88963415 100644 --- a/.deploy/k8s/k8s-manifest.stage.yaml +++ b/.deploy/k8s/k8s-manifest.stage.yaml @@ -199,6 +199,8 @@ spec: value: '$JITSU_SERVER_WRITE_KEY' - name: OTEL_ENABLED value: '$OTEL_ENABLED' + - name: OTEL_PROVIDER + value: '$OTEL_PROVIDER' - name: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT value: '$OTEL_EXPORTER_OTLP_TRACES_ENDPOINT' - name: OTEL_EXPORTER_OTLP_HEADERS diff --git a/.deploy/ssh/with-cloudflare/demo/docker-compose.api.demo.cloudflare.pre.yml b/.deploy/ssh/with-cloudflare/demo/docker-compose.api.demo.cloudflare.pre.yml new file mode 100644 index 00000000000..6d37ca08ba4 --- /dev/null +++ b/.deploy/ssh/with-cloudflare/demo/docker-compose.api.demo.cloudflare.pre.yml @@ -0,0 +1,22 @@ +version: '3.8' + +services: + nginx: + image: nginx:latest + volumes: + - ./nginx.demo.pre.cloudflare.conf:/etc/nginx/nginx.conf:ro + - ./ingress.api.crt:/etc/nginx/ssl/fullchain.pem + - ./ingress.api.key:/etc/nginx/ssl/privkey.pem + restart: unless-stopped + ports: + - "80:80" + - "443:443" + networks: + - with-cloudflare_overlay +volumes: + certificates: {} + +networks: + with-cloudflare_overlay: + external: true + diff --git a/.deploy/ssh/with-cloudflare/demo/docker-compose.api.demo.template.yml b/.deploy/ssh/with-cloudflare/demo/docker-compose.api.demo.template.yml new file mode 100644 index 00000000000..be4de900105 --- /dev/null +++ b/.deploy/ssh/with-cloudflare/demo/docker-compose.api.demo.template.yml @@ -0,0 +1,122 @@ +version: '3.8' + +services: + api: + image: ghcr.io/ever-co/gauzy-api-demo:latest + deploy: + mode: replicated + replicas: 2 + environment: + API_HOST: '0.0.0.0' + DEMO: '${DEMO:-true}' + NODE_ENV: '${NODE_ENV:-development}' + ADMIN_PASSWORD_RESET: '${ADMIN_PASSWORD_RESET:-}' + API_BASE_URL: '${API_BASE_URL:-http://localhost:3000}' + CLIENT_BASE_URL: '${CLIENT_BASE_URL:-http://localhost:4200}' + DB_TYPE: '${DB_TYPE:-better-sqlite3}' + DB_URI: '${DB_URI:-}' + DB_HOST: '${DB_HOST:-}' + DB_USER: '${DB_USER:-}' + DB_PASS: '${DB_PASS:-}' + DB_NAME: '${DB_NAME:-}' + DB_PORT: '${DB_PORT:-}' + DB_CA_CERT: '${DB_CA_CERT:-}' + DB_SSL_MODE: '${DB_SSL_MODE:-}' + DB_POOL_SIZE: '${DB_POOL_SIZE:-}' + DB_POOL_SIZE_KNEX: '${DB_POOL_SIZE_KNEX:-}' + REDIS_ENABLED: '${REDIS_ENABLED:-}' + REDIS_URL: '${REDIS_URL:-}' + CLOUD_PROVIDER: 'DO' + SENTRY_DSN: '${SENTRY_DSN:-}' + SENTRY_TRACES_SAMPLE_RATE: '${SENTRY_TRACES_SAMPLE_RATE:-}' + SENTRY_PROFILE_SAMPLE_RATE: '${SENTRY_PROFILE_SAMPLE_RATE:-}' + SENTRY_HTTP_TRACING_ENABLED: '${SENTRY_HTTP_TRACING_ENABLED:-}' + SENTRY_POSTGRES_TRACKING_ENABLED: '${SENTRY_POSTGRES_TRACKING_ENABLED:-}' + SENTRY_PROFILING_ENABLED: '${SENTRY_PROFILING_ENABLED:-}' + AWS_ACCESS_KEY_ID: '${AWS_ACCESS_KEY_ID:-}' + AWS_SECRET_ACCESS_KEY: '${AWS_SECRET_ACCESS_KEY:-}' + AWS_REGION: '${AWS_REGION:-}' + AWS_S3_BUCKET: '${AWS_S3_BUCKET:-}' + WASABI_ACCESS_KEY_ID: '${WASABI_ACCESS_KEY_ID:-}' + WASABI_SECRET_ACCESS_KEY: '${WASABI_SECRET_ACCESS_KEY:-}' + WASABI_REGION: '${WASABI_REGION:-}' + WASABI_SERVICE_URL: '${WASABI_SERVICE_URL:-}' + WASABI_S3_BUCKET: '${WASABI_S3_BUCKET:-}' + EXPRESS_SESSION_SECRET: '${EXPRESS_SESSION_SECRET:-}' + JWT_SECRET: '${JWT_SECRET:-}' + JWT_REFRESH_TOKEN_SECRET: '${JWT_REFRESH_TOKEN_SECRET:-}' + JWT_REFRESH_TOKEN_EXPIRATION_TIME: '${JWT_REFRESH_TOKEN_EXPIRATION_TIME:-}' + CLOUDINARY_API_KEY: '${CLOUDINARY_API_KEY:-}' + CLOUDINARY_API_SECRET: '${CLOUDINARY_API_SECRET:-}' + CLOUDINARY_CLOUD_NAME: '${CLOUDINARY_CLOUD_NAME:-}' + MAIL_FROM_ADDRESS: '${MAIL_FROM_ADDRESS:-}' + MAIL_HOST: '${MAIL_HOST:-}' + MAIL_PORT: '${MAIL_PORT:-}' + MAIL_USERNAME: '${MAIL_USERNAME:-}' + MAIL_PASSWORD: '${MAIL_PASSWORD:-}' + ALLOW_SUPER_ADMIN_ROLE: '${ALLOW_SUPER_ADMIN_ROLE:-}' + GOOGLE_CLIENT_ID: '${GOOGLE_CLIENT_ID:-}' + GOOGLE_CLIENT_SECRET: '${GOOGLE_CLIENT_SECRET:-}' + GOOGLE_CALLBACK_URL: '${GOOGLE_CALLBACK_URL:-}' + FACEBOOK_CLIENT_ID: '${FACEBOOK_CLIENT_ID:-}' + FACEBOOK_CLIENT_SECRET: '${FACEBOOK_CLIENT_SECRET:-}' + FACEBOOK_GRAPH_VERSION: '${FACEBOOK_GRAPH_VERSION:-}' + FACEBOOK_CALLBACK_URL: '${FACEBOOK_CALLBACK_URL:-}' + INTEGRATED_USER_DEFAULT_PASS: '${INTEGRATED_USER_DEFAULT_PASS:-}' + UPWORK_REDIRECT_URL: '${UPWORK_REDIRECT_URL:-}' + FILE_PROVIDER: '${FILE_PROVIDER:-}' + GAUZY_AI_GRAPHQL_ENDPOINT: '${GAUZY_AI_GRAPHQL_ENDPOINT:-}' + GAUZY_AI_REST_ENDPOINT: '${GAUZY_AI_REST_ENDPOINT:-}' + UNLEASH_APP_NAME: '${UNLEASH_APP_NAME:-}' + UNLEASH_API_URL: '${UNLEASH_API_URL:-}' + UNLEASH_INSTANCE_ID: '${UNLEASH_INSTANCE_ID:-}' + UNLEASH_REFRESH_INTERVAL: '${UNLEASH_REFRESH_INTERVAL:-}' + UNLEASH_METRICS_INTERVAL: '${UNLEASH_METRICS_INTERVAL:-}' + UNLEASH_API_KEY: '${UNLEASH_API_KEY:-}' + PM2_MACHINE_NAME: '${PM2_MACHINE_NAME:-}' + PM2_SECRET_KEY: '${PM2_SECRET_KEY:-}' + PM2_PUBLIC_KEY: '${PM2_PUBLIC_KEY:-}' + JITSU_SERVER_URL: '${JITSU_SERVER_URL:-}' + JITSU_SERVER_WRITE_KEY: '${JITSU_SERVER_WRITE_KEY:-}' + OTEL_ENABLED: '${OTEL_ENABLED:-}' + OTEL_PROVIDER: '${OTEL_PROVIDER:-}' + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT:-}' + OTEL_EXPORTER_OTLP_HEADERS: '${OTEL_EXPORTER_OTLP_HEADERS:-}' + GAUZY_GITHUB_CLIENT_ID: '${GAUZY_GITHUB_CLIENT_ID:-}' + GAUZY_GITHUB_CLIENT_SECRET: '${GAUZY_GITHUB_CLIENT_SECRET:-}' + GAUZY_GITHUB_APP_PRIVATE_KEY: '${GAUZY_GITHUB_APP_PRIVATE_KEY:-}' + GAUZY_GITHUB_WEBHOOK_URL: '${GAUZY_GITHUB_WEBHOOK_URL:-}' + GAUZY_GITHUB_WEBHOOK_SECRET: '${GAUZY_GITHUB_WEBHOOK_SECRET:-}' + GAUZY_GITHUB_APP_NAME: '${GAUZY_GITHUB_APP_NAME:-}' + GAUZY_GITHUB_REDIRECT_URL: '${GAUZY_GITHUB_REDIRECT_URL:-}' + GAUZY_GITHUB_POST_INSTALL_URL: '${GAUZY_GITHUB_POST_INSTALL_URL:-}' + GAUZY_GITHUB_APP_ID: '${GAUZY_GITHUB_APP_ID:-}' + GAUZY_GITHUB_OAUTH_CLIENT_ID: '${GAUZY_GITHUB_OAUTH_CLIENT_ID:-}' + GAUZY_GITHUB_OAUTH_CLIENT_SECRET: '${GAUZY_GITHUB_OAUTH_CLIENT_SECRET:-}' + GAUZY_GITHUB_OAUTH_CALLBACK_URL: '${GAUZY_GITHUB_OAUTH_CALLBACK_URL:-}' + JITSU_BROWSER_URL: '${JITSU_BROWSER_URL:-}' + JITSU_BROWSER_WRITE_KEY: '${JITSU_BROWSER_WRITE_KEY:-}' + MAGIC_CODE_EXPIRATION_TIME: '${MAGIC_CODE_EXPIRATION_TIME:-}' + APP_NAME: '${APP_NAME:-}' + APP_LOGO: '${APP_LOGO:-}' + APP_SIGNATURE: '${APP_SIGNATURE:-}' + APP_LINK: '${APP_LINK:-}' + APP_EMAIL_CONFIRMATION_URL: '${APP_EMAIL_CONFIRMATION_URL:-}' + APP_MAGIC_SIGN_URL: '${APP_MAGIC_SIGN_URL:-}' + COMPANY_LINK: '${COMPANY_LINK:-}' + COMPANY_NAME: '${COMPANY_NAME:-}' + + entrypoint: './entrypoint.prod.sh' + command: ['node', 'main.js'] + restart: on-failure + ports: + - '3000' + networks: + - overlay + +volumes: + certificates: {} + +networks: + overlay: + driver: bridge diff --git a/.deploy/ssh/with-cloudflare/demo/nginx.demo.pre.cloudflare.conf b/.deploy/ssh/with-cloudflare/demo/nginx.demo.pre.cloudflare.conf new file mode 100644 index 00000000000..d27b009e72e --- /dev/null +++ b/.deploy/ssh/with-cloudflare/demo/nginx.demo.pre.cloudflare.conf @@ -0,0 +1,25 @@ +user nginx; +events { + worker_connections 1024; +} +http { + server { + listen 80; + server_name apidemodt.gauzy.co; + + location / { + return 301 https://$host$request_uri; + } + } + server { + listen 443 ssl; + server_name apidemodt.gauzy.co; + + ssl_certificate /etc/nginx/ssl/fullchain.pem; + ssl_certificate_key /etc/nginx/ssl/privkey.pem; + + location / { + proxy_pass http://api:3000; + } + } +} diff --git a/.deploy/ssh/with-cloudflare/prod/docker-compose.api.prod.cloudflare.pre.yml b/.deploy/ssh/with-cloudflare/prod/docker-compose.api.prod.cloudflare.pre.yml new file mode 100644 index 00000000000..36553610a90 --- /dev/null +++ b/.deploy/ssh/with-cloudflare/prod/docker-compose.api.prod.cloudflare.pre.yml @@ -0,0 +1,22 @@ +version: '3.8' + +services: + nginx: + image: nginx:latest + volumes: + - ./nginx.prod.pre.cloudflare.conf:/etc/nginx/nginx.conf:ro + - ./ingress.api.crt:/etc/nginx/ssl/fullchain.pem + - ./ingress.api.key:/etc/nginx/ssl/privkey.pem + restart: unless-stopped + ports: + - "80:80" + - "443:443" + networks: + - with-cloudflare_overlay +volumes: + certificates: {} + +networks: + with-cloudflare_overlay: + external: true + diff --git a/.deploy/ssh/with-cloudflare/prod/docker-compose.api.prod.template.yml b/.deploy/ssh/with-cloudflare/prod/docker-compose.api.prod.template.yml new file mode 100644 index 00000000000..aa259b864c5 --- /dev/null +++ b/.deploy/ssh/with-cloudflare/prod/docker-compose.api.prod.template.yml @@ -0,0 +1,122 @@ +version: '3.8' + +services: + api: + image: ghcr.io/ever-co/gauzy-api:latest + deploy: + mode: replicated + replicas: 2 + environment: + API_HOST: '0.0.0.0' + DEMO: '${DEMO}' + NODE_ENV: '${NODE_ENV}' + ADMIN_PASSWORD_RESET: '${ADMIN_PASSWORD_RESET}' + API_BASE_URL: '${API_BASE_URL}' + CLIENT_BASE_URL: '${CLIENT_BASE_URL}' + DB_TYPE: '${DB_TYPE}' + DB_URI: '${DB_URI}' + DB_HOST: '${DB_HOST}' + DB_USER: '${DB_USER}' + DB_PASS: '${DB_PASS}' + DB_NAME: '${DB_NAME}' + DB_PORT: '${DB_PORT}' + DB_CA_CERT: '${DB_CA_CERT}' + DB_SSL_MODE: '${DB_SSL_MODE}' + DB_POOL_SIZE: '${DB_POOL_SIZE}' + DB_POOL_SIZE_KNEX: '${DB_POOL_SIZE_KNEX}' + REDIS_ENABLED: '${REDIS_ENABLED}' + REDIS_URL: '${REDIS_URL}' + CLOUD_PROVIDER: 'DO' + SENTRY_DSN: '${SENTRY_DSN}' + SENTRY_TRACES_SAMPLE_RATE: '${SENTRY_TRACES_SAMPLE_RATE}' + SENTRY_PROFILE_SAMPLE_RATE: '${SENTRY_PROFILE_SAMPLE_RATE}' + SENTRY_HTTP_TRACING_ENABLED: '${SENTRY_HTTP_TRACING_ENABLED}' + SENTRY_POSTGRES_TRACKING_ENABLED: '${SENTRY_POSTGRES_TRACKING_ENABLED}' + SENTRY_PROFILING_ENABLED: '${SENTRY_PROFILING_ENABLED}' + AWS_ACCESS_KEY_ID: '${AWS_ACCESS_KEY_ID}' + AWS_SECRET_ACCESS_KEY: '${AWS_SECRET_ACCESS_KEY}' + AWS_REGION: '${AWS_REGION}' + AWS_S3_BUCKET: '${AWS_S3_BUCKET}' + WASABI_ACCESS_KEY_ID: '${WASABI_ACCESS_KEY_ID}' + WASABI_SECRET_ACCESS_KEY: '${WASABI_SECRET_ACCESS_KEY}' + WASABI_REGION: '${WASABI_REGION}' + WASABI_SERVICE_URL: '${WASABI_SERVICE_URL}' + WASABI_S3_BUCKET: '${WASABI_S3_BUCKET}' + EXPRESS_SESSION_SECRET: '${EXPRESS_SESSION_SECRET}' + JWT_SECRET: '${JWT_SECRET}' + JWT_REFRESH_TOKEN_SECRET: '${JWT_REFRESH_TOKEN_SECRET}' + JWT_REFRESH_TOKEN_EXPIRATION_TIME: '${JWT_REFRESH_TOKEN_EXPIRATION_TIME}' + CLOUDINARY_API_KEY: '${CLOUDINARY_API_KEY}' + CLOUDINARY_API_SECRET: '${CLOUDINARY_API_SECRET}' + CLOUDINARY_CLOUD_NAME: '${CLOUDINARY_CLOUD_NAME}' + MAIL_FROM_ADDRESS: '${MAIL_FROM_ADDRESS}' + MAIL_HOST: '${MAIL_HOST}' + MAIL_PORT: '${MAIL_PORT}' + MAIL_USERNAME: '${MAIL_USERNAME}' + MAIL_PASSWORD: '${MAIL_PASSWORD}' + ALLOW_SUPER_ADMIN_ROLE: '${ALLOW_SUPER_ADMIN_ROLE}' + GOOGLE_CLIENT_ID: '${GOOGLE_CLIENT_ID}' + GOOGLE_CLIENT_SECRET: '${GOOGLE_CLIENT_SECRET}' + GOOGLE_CALLBACK_URL: '${GOOGLE_CALLBACK_URL}' + FACEBOOK_CLIENT_ID: '${FACEBOOK_CLIENT_ID}' + FACEBOOK_CLIENT_SECRET: '${FACEBOOK_CLIENT_SECRET}' + FACEBOOK_GRAPH_VERSION: '${FACEBOOK_GRAPH_VERSION}' + FACEBOOK_CALLBACK_URL: '${FACEBOOK_CALLBACK_URL}' + INTEGRATED_USER_DEFAULT_PASS: '${INTEGRATED_USER_DEFAULT_PASS}' + UPWORK_REDIRECT_URL: '${UPWORK_REDIRECT_URL}' + FILE_PROVIDER: '${FILE_PROVIDER}' + GAUZY_AI_GRAPHQL_ENDPOINT: '${GAUZY_AI_GRAPHQL_ENDPOINT}' + GAUZY_AI_REST_ENDPOINT: '${GAUZY_AI_REST_ENDPOINT}' + UNLEASH_APP_NAME: '${UNLEASH_APP_NAME}' + UNLEASH_API_URL: '${UNLEASH_API_URL}' + UNLEASH_INSTANCE_ID: '${UNLEASH_INSTANCE_ID}' + UNLEASH_REFRESH_INTERVAL: '${UNLEASH_REFRESH_INTERVAL}' + UNLEASH_METRICS_INTERVAL: '${UNLEASH_METRICS_INTERVAL}' + UNLEASH_API_KEY: '${UNLEASH_API_KEY}' + PM2_MACHINE_NAME: '${PM2_MACHINE_NAME}' + PM2_SECRET_KEY: '${PM2_SECRET_KEY}' + PM2_PUBLIC_KEY: '${PM2_PUBLIC_KEY}' + JITSU_SERVER_URL: '${JITSU_SERVER_URL}' + JITSU_SERVER_WRITE_KEY: '${JITSU_SERVER_WRITE_KEY}' + OTEL_ENABLED: '${OTEL_ENABLED}' + OTEL_PROVIDER: '${OTEL_PROVIDER}' + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT}' + OTEL_EXPORTER_OTLP_HEADERS: '${OTEL_EXPORTER_OTLP_HEADERS}' + GAUZY_GITHUB_CLIENT_ID: '${GAUZY_GITHUB_CLIENT_ID}' + GAUZY_GITHUB_CLIENT_SECRET: '${GAUZY_GITHUB_CLIENT_SECRET}' + GAUZY_GITHUB_APP_PRIVATE_KEY: '${GAUZY_GITHUB_APP_PRIVATE_KEY}' + GAUZY_GITHUB_WEBHOOK_URL: '${GAUZY_GITHUB_WEBHOOK_URL}' + GAUZY_GITHUB_WEBHOOK_SECRET: '${GAUZY_GITHUB_WEBHOOK_SECRET}' + GAUZY_GITHUB_APP_NAME: '${GAUZY_GITHUB_APP_NAME}' + GAUZY_GITHUB_REDIRECT_URL: '${GAUZY_GITHUB_REDIRECT_URL}' + GAUZY_GITHUB_POST_INSTALL_URL: '${GAUZY_GITHUB_POST_INSTALL_URL}' + GAUZY_GITHUB_APP_ID: '${GAUZY_GITHUB_APP_ID}' + GAUZY_GITHUB_OAUTH_CLIENT_ID: '${GAUZY_GITHUB_OAUTH_CLIENT_ID}' + GAUZY_GITHUB_OAUTH_CLIENT_SECRET: '${GAUZY_GITHUB_OAUTH_CLIENT_SECRET}' + GAUZY_GITHUB_OAUTH_CALLBACK_URL: '${GAUZY_GITHUB_OAUTH_CALLBACK_URL}' + JITSU_BROWSER_URL: '${JITSU_BROWSER_URL}' + JITSU_BROWSER_WRITE_KEY: '${JITSU_BROWSER_WRITE_KEY}' + MAGIC_CODE_EXPIRATION_TIME: '${MAGIC_CODE_EXPIRATION_TIME}' + APP_NAME: '${APP_NAME}' + APP_LOGO: '${APP_LOGO}' + APP_SIGNATURE: '${APP_SIGNATURE}' + APP_LINK: '${APP_LINK}' + APP_EMAIL_CONFIRMATION_URL: '${APP_EMAIL_CONFIRMATION_URL}' + APP_MAGIC_SIGN_URL: '${APP_MAGIC_SIGN_URL}' + COMPANY_LINK: '${COMPANY_LINK}' + COMPANY_NAME: '${COMPANY_NAME}' + + entrypoint: './entrypoint.prod.sh' + command: ['node', 'main.js'] + restart: on-failure + ports: + - '3000' + networks: + - overlay + +volumes: + certificates: {} + +networks: + overlay: + driver: bridge diff --git a/.deploy/ssh/with-cloudflare/prod/nginx.prod.pre.cloudflare.conf b/.deploy/ssh/with-cloudflare/prod/nginx.prod.pre.cloudflare.conf new file mode 100644 index 00000000000..b18efd8ca44 --- /dev/null +++ b/.deploy/ssh/with-cloudflare/prod/nginx.prod.pre.cloudflare.conf @@ -0,0 +1,25 @@ +user nginx; +events { + worker_connections 1024; +} +http { + server { + listen 80; + server_name apidt.gauzy.co; + + location / { + return 301 https://$host$request_uri; + } + } + server { + listen 443 ssl; + server_name apidt.gauzy.co; + + ssl_certificate /etc/nginx/ssl/fullchain.pem; + ssl_certificate_key /etc/nginx/ssl/privkey.pem; + + location / { + proxy_pass http://api:3000; + } + } +} diff --git a/.deploy/ssh/with-cloudflare/stage/docker-compose.api.stage.cloudflare.pre.yml b/.deploy/ssh/with-cloudflare/stage/docker-compose.api.stage.cloudflare.pre.yml new file mode 100644 index 00000000000..44ce1eaa9ce --- /dev/null +++ b/.deploy/ssh/with-cloudflare/stage/docker-compose.api.stage.cloudflare.pre.yml @@ -0,0 +1,22 @@ +version: '3.8' + +services: + nginx: + image: nginx:latest + volumes: + - ./nginx.stage.pre.cloudflare.conf:/etc/nginx/nginx.conf:ro + - ./ingress.api.crt:/etc/nginx/ssl/fullchain.pem + - ./ingress.api.key:/etc/nginx/ssl/privkey.pem + restart: unless-stopped + ports: + - "80:80" + - "443:443" + networks: + - with-cloudflare_overlay +volumes: + certificates: {} + +networks: + with-cloudflare_overlay: + external: true + diff --git a/.deploy/ssh/with-cloudflare/stage/docker-compose.api.stage.template.yml b/.deploy/ssh/with-cloudflare/stage/docker-compose.api.stage.template.yml new file mode 100644 index 00000000000..4b3e71d3839 --- /dev/null +++ b/.deploy/ssh/with-cloudflare/stage/docker-compose.api.stage.template.yml @@ -0,0 +1,122 @@ +version: '3.8' + +services: + api: + image: ghcr.io/ever-co/gauzy-api-stage:latest + deploy: + mode: replicated + replicas: 2 + environment: + API_HOST: '0.0.0.0' + DEMO: '${DEMO}' + NODE_ENV: '${NODE_ENV}' + ADMIN_PASSWORD_RESET: '${ADMIN_PASSWORD_RESET}' + API_BASE_URL: '${API_BASE_URL}' + CLIENT_BASE_URL: '${CLIENT_BASE_URL}' + DB_TYPE: '${DB_TYPE}' + DB_URI: '${DB_URI}' + DB_HOST: '${DB_HOST}' + DB_USER: '${DB_USER}' + DB_PASS: '${DB_PASS}' + DB_NAME: '${DB_NAME}' + DB_PORT: '${DB_PORT}' + DB_CA_CERT: '${DB_CA_CERT}' + DB_SSL_MODE: '${DB_SSL_MODE}' + DB_POOL_SIZE: '${DB_POOL_SIZE}' + DB_POOL_SIZE_KNEX: '${DB_POOL_SIZE_KNEX}' + REDIS_ENABLED: '${REDIS_ENABLED}' + REDIS_URL: '${REDIS_URL}' + CLOUD_PROVIDER: 'DO' + SENTRY_DSN: '${SENTRY_DSN}' + SENTRY_TRACES_SAMPLE_RATE: '${SENTRY_TRACES_SAMPLE_RATE}' + SENTRY_PROFILE_SAMPLE_RATE: '${SENTRY_PROFILE_SAMPLE_RATE}' + SENTRY_HTTP_TRACING_ENABLED: '${SENTRY_HTTP_TRACING_ENABLED}' + SENTRY_POSTGRES_TRACKING_ENABLED: '${SENTRY_POSTGRES_TRACKING_ENABLED}' + SENTRY_PROFILING_ENABLED: '${SENTRY_PROFILING_ENABLED}' + AWS_ACCESS_KEY_ID: '${AWS_ACCESS_KEY_ID}' + AWS_SECRET_ACCESS_KEY: '${AWS_SECRET_ACCESS_KEY}' + AWS_REGION: '${AWS_REGION}' + AWS_S3_BUCKET: '${AWS_S3_BUCKET}' + WASABI_ACCESS_KEY_ID: '${WASABI_ACCESS_KEY_ID}' + WASABI_SECRET_ACCESS_KEY: '${WASABI_SECRET_ACCESS_KEY}' + WASABI_REGION: '${WASABI_REGION}' + WASABI_SERVICE_URL: '${WASABI_SERVICE_URL}' + WASABI_S3_BUCKET: '${WASABI_S3_BUCKET}' + EXPRESS_SESSION_SECRET: '${EXPRESS_SESSION_SECRET}' + JWT_SECRET: '${JWT_SECRET}' + JWT_REFRESH_TOKEN_SECRET: '${JWT_REFRESH_TOKEN_SECRET}' + JWT_REFRESH_TOKEN_EXPIRATION_TIME: '${JWT_REFRESH_TOKEN_EXPIRATION_TIME}' + CLOUDINARY_API_KEY: '${CLOUDINARY_API_KEY}' + CLOUDINARY_API_SECRET: '${CLOUDINARY_API_SECRET}' + CLOUDINARY_CLOUD_NAME: '${CLOUDINARY_CLOUD_NAME}' + MAIL_FROM_ADDRESS: '${MAIL_FROM_ADDRESS}' + MAIL_HOST: '${MAIL_HOST}' + MAIL_PORT: '${MAIL_PORT}' + MAIL_USERNAME: '${MAIL_USERNAME}' + MAIL_PASSWORD: '${MAIL_PASSWORD}' + ALLOW_SUPER_ADMIN_ROLE: '${ALLOW_SUPER_ADMIN_ROLE}' + GOOGLE_CLIENT_ID: '${GOOGLE_CLIENT_ID}' + GOOGLE_CLIENT_SECRET: '${GOOGLE_CLIENT_SECRET}' + GOOGLE_CALLBACK_URL: '${GOOGLE_CALLBACK_URL}' + FACEBOOK_CLIENT_ID: '${FACEBOOK_CLIENT_ID}' + FACEBOOK_CLIENT_SECRET: '${FACEBOOK_CLIENT_SECRET}' + FACEBOOK_GRAPH_VERSION: '${FACEBOOK_GRAPH_VERSION}' + FACEBOOK_CALLBACK_URL: '${FACEBOOK_CALLBACK_URL}' + INTEGRATED_USER_DEFAULT_PASS: '${INTEGRATED_USER_DEFAULT_PASS}' + UPWORK_REDIRECT_URL: '${UPWORK_REDIRECT_URL}' + FILE_PROVIDER: '${FILE_PROVIDER}' + GAUZY_AI_GRAPHQL_ENDPOINT: '${GAUZY_AI_GRAPHQL_ENDPOINT}' + GAUZY_AI_REST_ENDPOINT: '${GAUZY_AI_REST_ENDPOINT}' + UNLEASH_APP_NAME: '${UNLEASH_APP_NAME}' + UNLEASH_API_URL: '${UNLEASH_API_URL}' + UNLEASH_INSTANCE_ID: '${UNLEASH_INSTANCE_ID}' + UNLEASH_REFRESH_INTERVAL: '${UNLEASH_REFRESH_INTERVAL}' + UNLEASH_METRICS_INTERVAL: '${UNLEASH_METRICS_INTERVAL}' + UNLEASH_API_KEY: '${UNLEASH_API_KEY}' + PM2_MACHINE_NAME: '${PM2_MACHINE_NAME}' + PM2_SECRET_KEY: '${PM2_SECRET_KEY}' + PM2_PUBLIC_KEY: '${PM2_PUBLIC_KEY}' + JITSU_SERVER_URL: '${JITSU_SERVER_URL}' + JITSU_SERVER_WRITE_KEY: '${JITSU_SERVER_WRITE_KEY}' + OTEL_ENABLED: '${OTEL_ENABLED}' + OTEL_PROVIDER: '${OTEL_PROVIDER}' + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT}' + OTEL_EXPORTER_OTLP_HEADERS: '${OTEL_EXPORTER_OTLP_HEADERS}' + GAUZY_GITHUB_CLIENT_ID: '${GAUZY_GITHUB_CLIENT_ID}' + GAUZY_GITHUB_CLIENT_SECRET: '${GAUZY_GITHUB_CLIENT_SECRET}' + GAUZY_GITHUB_APP_PRIVATE_KEY: '${GAUZY_GITHUB_APP_PRIVATE_KEY}' + GAUZY_GITHUB_WEBHOOK_URL: '${GAUZY_GITHUB_WEBHOOK_URL}' + GAUZY_GITHUB_WEBHOOK_SECRET: '${GAUZY_GITHUB_WEBHOOK_SECRET}' + GAUZY_GITHUB_APP_NAME: '${GAUZY_GITHUB_APP_NAME}' + GAUZY_GITHUB_REDIRECT_URL: '${GAUZY_GITHUB_REDIRECT_URL}' + GAUZY_GITHUB_POST_INSTALL_URL: '${GAUZY_GITHUB_POST_INSTALL_URL}' + GAUZY_GITHUB_APP_ID: '${GAUZY_GITHUB_APP_ID}' + GAUZY_GITHUB_OAUTH_CLIENT_ID: '${GAUZY_GITHUB_OAUTH_CLIENT_ID}' + GAUZY_GITHUB_OAUTH_CLIENT_SECRET: '${GAUZY_GITHUB_OAUTH_CLIENT_SECRET}' + GAUZY_GITHUB_OAUTH_CALLBACK_URL: '${GAUZY_GITHUB_OAUTH_CALLBACK_URL}' + JITSU_BROWSER_URL: '${JITSU_BROWSER_URL}' + JITSU_BROWSER_WRITE_KEY: '${JITSU_BROWSER_WRITE_KEY}' + MAGIC_CODE_EXPIRATION_TIME: '${MAGIC_CODE_EXPIRATION_TIME}' + APP_NAME: '${APP_NAME}' + APP_LOGO: '${APP_LOGO}' + APP_SIGNATURE: '${APP_SIGNATURE}' + APP_LINK: '${APP_LINK}' + APP_EMAIL_CONFIRMATION_URL: '${APP_EMAIL_CONFIRMATION_URL}' + APP_MAGIC_SIGN_URL: '${APP_MAGIC_SIGN_URL}' + COMPANY_LINK: '${COMPANY_LINK}' + COMPANY_NAME: '${COMPANY_NAME}' + + entrypoint: './entrypoint.prod.sh' + command: ['node', 'main.js'] + restart: on-failure + ports: + - '3000' + networks: + - overlay + +volumes: + certificates: {} + +networks: + overlay: + driver: bridge diff --git a/.deploy/ssh/with-cloudflare/stage/nginx.stage.pre.cloudflare.conf b/.deploy/ssh/with-cloudflare/stage/nginx.stage.pre.cloudflare.conf new file mode 100644 index 00000000000..74aa59560c6 --- /dev/null +++ b/.deploy/ssh/with-cloudflare/stage/nginx.stage.pre.cloudflare.conf @@ -0,0 +1,25 @@ +user nginx; +events { + worker_connections 1024; +} +http { + server { + listen 80; + server_name apistagedt.gauzy.co; + + location / { + return 301 https://$host$request_uri; + } + } + server { + listen 443 ssl; + server_name apistagedt.gauzy.co; + + ssl_certificate /etc/nginx/ssl/fullchain.pem; + ssl_certificate_key /etc/nginx/ssl/privkey.pem; + + location / { + proxy_pass http://api:3000; + } + } +} diff --git a/.deploy/ssh/with-letsencrypt/demo/docker-compose.api.demo.letsencrypt.pre.yml b/.deploy/ssh/with-letsencrypt/demo/docker-compose.api.demo.letsencrypt.pre.yml new file mode 100644 index 00000000000..88acc0b30a7 --- /dev/null +++ b/.deploy/ssh/with-letsencrypt/demo/docker-compose.api.demo.letsencrypt.pre.yml @@ -0,0 +1,25 @@ +version: '3.8' + +services: + proxy: + image: jonasal/nginx-certbot:latest + restart: always + environment: + CERTBOT_EMAIL: 'ever@ever.co' + env_file: + - ./nginx-certbot.env + ports: + - '80:80' + - '443:443' + networks: + - demo_overlay + volumes: + - nginx_secrets:/etc/letsencrypt + - ./user_conf.d:/etc/nginx/user_conf.d +volumes: + nginx_secrets: {} + certificates: {} + +networks: + demo_overlay: + external: true diff --git a/.deploy/ssh/with-letsencrypt/demo/docker-compose.api.demo.template.yml b/.deploy/ssh/with-letsencrypt/demo/docker-compose.api.demo.template.yml new file mode 100644 index 00000000000..be4de900105 --- /dev/null +++ b/.deploy/ssh/with-letsencrypt/demo/docker-compose.api.demo.template.yml @@ -0,0 +1,122 @@ +version: '3.8' + +services: + api: + image: ghcr.io/ever-co/gauzy-api-demo:latest + deploy: + mode: replicated + replicas: 2 + environment: + API_HOST: '0.0.0.0' + DEMO: '${DEMO:-true}' + NODE_ENV: '${NODE_ENV:-development}' + ADMIN_PASSWORD_RESET: '${ADMIN_PASSWORD_RESET:-}' + API_BASE_URL: '${API_BASE_URL:-http://localhost:3000}' + CLIENT_BASE_URL: '${CLIENT_BASE_URL:-http://localhost:4200}' + DB_TYPE: '${DB_TYPE:-better-sqlite3}' + DB_URI: '${DB_URI:-}' + DB_HOST: '${DB_HOST:-}' + DB_USER: '${DB_USER:-}' + DB_PASS: '${DB_PASS:-}' + DB_NAME: '${DB_NAME:-}' + DB_PORT: '${DB_PORT:-}' + DB_CA_CERT: '${DB_CA_CERT:-}' + DB_SSL_MODE: '${DB_SSL_MODE:-}' + DB_POOL_SIZE: '${DB_POOL_SIZE:-}' + DB_POOL_SIZE_KNEX: '${DB_POOL_SIZE_KNEX:-}' + REDIS_ENABLED: '${REDIS_ENABLED:-}' + REDIS_URL: '${REDIS_URL:-}' + CLOUD_PROVIDER: 'DO' + SENTRY_DSN: '${SENTRY_DSN:-}' + SENTRY_TRACES_SAMPLE_RATE: '${SENTRY_TRACES_SAMPLE_RATE:-}' + SENTRY_PROFILE_SAMPLE_RATE: '${SENTRY_PROFILE_SAMPLE_RATE:-}' + SENTRY_HTTP_TRACING_ENABLED: '${SENTRY_HTTP_TRACING_ENABLED:-}' + SENTRY_POSTGRES_TRACKING_ENABLED: '${SENTRY_POSTGRES_TRACKING_ENABLED:-}' + SENTRY_PROFILING_ENABLED: '${SENTRY_PROFILING_ENABLED:-}' + AWS_ACCESS_KEY_ID: '${AWS_ACCESS_KEY_ID:-}' + AWS_SECRET_ACCESS_KEY: '${AWS_SECRET_ACCESS_KEY:-}' + AWS_REGION: '${AWS_REGION:-}' + AWS_S3_BUCKET: '${AWS_S3_BUCKET:-}' + WASABI_ACCESS_KEY_ID: '${WASABI_ACCESS_KEY_ID:-}' + WASABI_SECRET_ACCESS_KEY: '${WASABI_SECRET_ACCESS_KEY:-}' + WASABI_REGION: '${WASABI_REGION:-}' + WASABI_SERVICE_URL: '${WASABI_SERVICE_URL:-}' + WASABI_S3_BUCKET: '${WASABI_S3_BUCKET:-}' + EXPRESS_SESSION_SECRET: '${EXPRESS_SESSION_SECRET:-}' + JWT_SECRET: '${JWT_SECRET:-}' + JWT_REFRESH_TOKEN_SECRET: '${JWT_REFRESH_TOKEN_SECRET:-}' + JWT_REFRESH_TOKEN_EXPIRATION_TIME: '${JWT_REFRESH_TOKEN_EXPIRATION_TIME:-}' + CLOUDINARY_API_KEY: '${CLOUDINARY_API_KEY:-}' + CLOUDINARY_API_SECRET: '${CLOUDINARY_API_SECRET:-}' + CLOUDINARY_CLOUD_NAME: '${CLOUDINARY_CLOUD_NAME:-}' + MAIL_FROM_ADDRESS: '${MAIL_FROM_ADDRESS:-}' + MAIL_HOST: '${MAIL_HOST:-}' + MAIL_PORT: '${MAIL_PORT:-}' + MAIL_USERNAME: '${MAIL_USERNAME:-}' + MAIL_PASSWORD: '${MAIL_PASSWORD:-}' + ALLOW_SUPER_ADMIN_ROLE: '${ALLOW_SUPER_ADMIN_ROLE:-}' + GOOGLE_CLIENT_ID: '${GOOGLE_CLIENT_ID:-}' + GOOGLE_CLIENT_SECRET: '${GOOGLE_CLIENT_SECRET:-}' + GOOGLE_CALLBACK_URL: '${GOOGLE_CALLBACK_URL:-}' + FACEBOOK_CLIENT_ID: '${FACEBOOK_CLIENT_ID:-}' + FACEBOOK_CLIENT_SECRET: '${FACEBOOK_CLIENT_SECRET:-}' + FACEBOOK_GRAPH_VERSION: '${FACEBOOK_GRAPH_VERSION:-}' + FACEBOOK_CALLBACK_URL: '${FACEBOOK_CALLBACK_URL:-}' + INTEGRATED_USER_DEFAULT_PASS: '${INTEGRATED_USER_DEFAULT_PASS:-}' + UPWORK_REDIRECT_URL: '${UPWORK_REDIRECT_URL:-}' + FILE_PROVIDER: '${FILE_PROVIDER:-}' + GAUZY_AI_GRAPHQL_ENDPOINT: '${GAUZY_AI_GRAPHQL_ENDPOINT:-}' + GAUZY_AI_REST_ENDPOINT: '${GAUZY_AI_REST_ENDPOINT:-}' + UNLEASH_APP_NAME: '${UNLEASH_APP_NAME:-}' + UNLEASH_API_URL: '${UNLEASH_API_URL:-}' + UNLEASH_INSTANCE_ID: '${UNLEASH_INSTANCE_ID:-}' + UNLEASH_REFRESH_INTERVAL: '${UNLEASH_REFRESH_INTERVAL:-}' + UNLEASH_METRICS_INTERVAL: '${UNLEASH_METRICS_INTERVAL:-}' + UNLEASH_API_KEY: '${UNLEASH_API_KEY:-}' + PM2_MACHINE_NAME: '${PM2_MACHINE_NAME:-}' + PM2_SECRET_KEY: '${PM2_SECRET_KEY:-}' + PM2_PUBLIC_KEY: '${PM2_PUBLIC_KEY:-}' + JITSU_SERVER_URL: '${JITSU_SERVER_URL:-}' + JITSU_SERVER_WRITE_KEY: '${JITSU_SERVER_WRITE_KEY:-}' + OTEL_ENABLED: '${OTEL_ENABLED:-}' + OTEL_PROVIDER: '${OTEL_PROVIDER:-}' + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT:-}' + OTEL_EXPORTER_OTLP_HEADERS: '${OTEL_EXPORTER_OTLP_HEADERS:-}' + GAUZY_GITHUB_CLIENT_ID: '${GAUZY_GITHUB_CLIENT_ID:-}' + GAUZY_GITHUB_CLIENT_SECRET: '${GAUZY_GITHUB_CLIENT_SECRET:-}' + GAUZY_GITHUB_APP_PRIVATE_KEY: '${GAUZY_GITHUB_APP_PRIVATE_KEY:-}' + GAUZY_GITHUB_WEBHOOK_URL: '${GAUZY_GITHUB_WEBHOOK_URL:-}' + GAUZY_GITHUB_WEBHOOK_SECRET: '${GAUZY_GITHUB_WEBHOOK_SECRET:-}' + GAUZY_GITHUB_APP_NAME: '${GAUZY_GITHUB_APP_NAME:-}' + GAUZY_GITHUB_REDIRECT_URL: '${GAUZY_GITHUB_REDIRECT_URL:-}' + GAUZY_GITHUB_POST_INSTALL_URL: '${GAUZY_GITHUB_POST_INSTALL_URL:-}' + GAUZY_GITHUB_APP_ID: '${GAUZY_GITHUB_APP_ID:-}' + GAUZY_GITHUB_OAUTH_CLIENT_ID: '${GAUZY_GITHUB_OAUTH_CLIENT_ID:-}' + GAUZY_GITHUB_OAUTH_CLIENT_SECRET: '${GAUZY_GITHUB_OAUTH_CLIENT_SECRET:-}' + GAUZY_GITHUB_OAUTH_CALLBACK_URL: '${GAUZY_GITHUB_OAUTH_CALLBACK_URL:-}' + JITSU_BROWSER_URL: '${JITSU_BROWSER_URL:-}' + JITSU_BROWSER_WRITE_KEY: '${JITSU_BROWSER_WRITE_KEY:-}' + MAGIC_CODE_EXPIRATION_TIME: '${MAGIC_CODE_EXPIRATION_TIME:-}' + APP_NAME: '${APP_NAME:-}' + APP_LOGO: '${APP_LOGO:-}' + APP_SIGNATURE: '${APP_SIGNATURE:-}' + APP_LINK: '${APP_LINK:-}' + APP_EMAIL_CONFIRMATION_URL: '${APP_EMAIL_CONFIRMATION_URL:-}' + APP_MAGIC_SIGN_URL: '${APP_MAGIC_SIGN_URL:-}' + COMPANY_LINK: '${COMPANY_LINK:-}' + COMPANY_NAME: '${COMPANY_NAME:-}' + + entrypoint: './entrypoint.prod.sh' + command: ['node', 'main.js'] + restart: on-failure + ports: + - '3000' + networks: + - overlay + +volumes: + certificates: {} + +networks: + overlay: + driver: bridge diff --git a/.deploy/ssh/with-letsencrypt/demo/nginx-certbot.env b/.deploy/ssh/with-letsencrypt/demo/nginx-certbot.env new file mode 100644 index 00000000000..1e81781c095 --- /dev/null +++ b/.deploy/ssh/with-letsencrypt/demo/nginx-certbot.env @@ -0,0 +1,16 @@ +# Required +CERTBOT_EMAIL="ever@ever.co" + +# Optional (Defaults) +DHPARAM_SIZE=2048 +ELLIPTIC_CURVE=secp256r1 +RENEWAL_INTERVAL=8d +RSA_KEY_SIZE=2048 +STAGING=0 +USE_ECDSA=1 + +# Advanced (Defaults) +CERTBOT_AUTHENTICATOR=webroot +CERTBOT_DNS_PROPAGATION_SECONDS="" +DEBUG=0 +USE_LOCAL_CA=0 diff --git a/.deploy/ssh/with-letsencrypt/demo/user_conf.d/nginx.conf b/.deploy/ssh/with-letsencrypt/demo/user_conf.d/nginx.conf new file mode 100644 index 00000000000..3fa20e8d74a --- /dev/null +++ b/.deploy/ssh/with-letsencrypt/demo/user_conf.d/nginx.conf @@ -0,0 +1,15 @@ +server { + listen 443 ssl; + server_name apidemodts.gauzy.co; + ssl_certificate /etc/letsencrypt/live/apidemodts.gauzy.co/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/apidemodts.gauzy.co/privkey.pem; + ssl_trusted_certificate /etc/letsencrypt/live/apidemodts.gauzy.co/chain.pem; + + # Load the Diffie-Hellman parameter. + ssl_dhparam /etc/letsencrypt/dhparams/dhparam.pem; + + location / { + proxy_pass http://api:3000; + } + +} diff --git a/.deploy/ssh/with-letsencrypt/prod/docker-compose.api.prod.letsencrypt.pre.yml b/.deploy/ssh/with-letsencrypt/prod/docker-compose.api.prod.letsencrypt.pre.yml new file mode 100644 index 00000000000..7708b6ddab9 --- /dev/null +++ b/.deploy/ssh/with-letsencrypt/prod/docker-compose.api.prod.letsencrypt.pre.yml @@ -0,0 +1,25 @@ +version: '3.8' + +services: + proxy: + image: jonasal/nginx-certbot:latest + restart: always + environment: + CERTBOT_EMAIL: 'ever@ever.co' + env_file: + - ./nginx-certbot.env + ports: + - '80:80' + - '443:443' + networks: + - prod_overlay + volumes: + - nginx_secrets:/etc/letsencrypt + - ./user_conf.d:/etc/nginx/user_conf.d +volumes: + nginx_secrets: {} + certificates: {} + +networks: + prod_overlay: + external: true diff --git a/.deploy/ssh/with-letsencrypt/prod/docker-compose.api.prod.template.yml b/.deploy/ssh/with-letsencrypt/prod/docker-compose.api.prod.template.yml new file mode 100644 index 00000000000..7428da92ac7 --- /dev/null +++ b/.deploy/ssh/with-letsencrypt/prod/docker-compose.api.prod.template.yml @@ -0,0 +1,121 @@ +version: '3.8' + +services: + api: + image: ghcr.io/ever-co/gauzy-api:latest + deploy: + mode: replicated + replicas: 2 + environment: + API_HOST: '0.0.0.0' + DEMO: '${DEMO}' + NODE_ENV: '${NODE_ENV}' + ADMIN_PASSWORD_RESET: '${ADMIN_PASSWORD_RESET}' + API_BASE_URL: '${API_BASE_URL}' + CLIENT_BASE_URL: '${CLIENT_BASE_URL}' + DB_TYPE: '${DB_TYPE}' + DB_URI: '${DB_URI}' + DB_HOST: '${DB_HOST}' + DB_USER: '${DB_USER}' + DB_PASS: '${DB_PASS}' + DB_NAME: '${DB_NAME}' + DB_PORT: '${DB_PORT}' + DB_CA_CERT: '${DB_CA_CERT}' + DB_SSL_MODE: '${DB_SSL_MODE}' + DB_POOL_SIZE: '${DB_POOL_SIZE}' + DB_POOL_SIZE_KNEX: '${DB_POOL_SIZE_KNEX}' + REDIS_ENABLED: '${REDIS_ENABLED}' + REDIS_URL: '${REDIS_URL}' + CLOUD_PROVIDER: 'DO' + SENTRY_DSN: '${SENTRY_DSN}' + SENTRY_TRACES_SAMPLE_RATE: '${SENTRY_TRACES_SAMPLE_RATE}' + SENTRY_PROFILE_SAMPLE_RATE: '${SENTRY_PROFILE_SAMPLE_RATE}' + SENTRY_HTTP_TRACING_ENABLED: '${SENTRY_HTTP_TRACING_ENABLED}' + SENTRY_POSTGRES_TRACKING_ENABLED: '${SENTRY_POSTGRES_TRACKING_ENABLED}' + SENTRY_PROFILING_ENABLED: '${SENTRY_PROFILING_ENABLED}' + AWS_ACCESS_KEY_ID: '${AWS_ACCESS_KEY_ID}' + AWS_SECRET_ACCESS_KEY: '${AWS_SECRET_ACCESS_KEY}' + AWS_REGION: '${AWS_REGION}' + AWS_S3_BUCKET: '${AWS_S3_BUCKET}' + WASABI_ACCESS_KEY_ID: '${WASABI_ACCESS_KEY_ID}' + WASABI_SECRET_ACCESS_KEY: '${WASABI_SECRET_ACCESS_KEY}' + WASABI_REGION: '${WASABI_REGION}' + WASABI_SERVICE_URL: '${WASABI_SERVICE_URL}' + WASABI_S3_BUCKET: '${WASABI_S3_BUCKET}' + EXPRESS_SESSION_SECRET: '${EXPRESS_SESSION_SECRET}' + JWT_SECRET: '${JWT_SECRET}' + JWT_REFRESH_TOKEN_SECRET: '${JWT_REFRESH_TOKEN_SECRET}' + JWT_REFRESH_TOKEN_EXPIRATION_TIME: '${JWT_REFRESH_TOKEN_EXPIRATION_TIME}' + CLOUDINARY_API_KEY: '${CLOUDINARY_API_KEY}' + CLOUDINARY_API_SECRET: '${CLOUDINARY_API_SECRET}' + CLOUDINARY_CLOUD_NAME: '${CLOUDINARY_CLOUD_NAME}' + MAIL_FROM_ADDRESS: '${MAIL_FROM_ADDRESS}' + MAIL_HOST: '${MAIL_HOST}' + MAIL_PORT: '${MAIL_PORT}' + MAIL_USERNAME: '${MAIL_USERNAME}' + MAIL_PASSWORD: '${MAIL_PASSWORD}' + ALLOW_SUPER_ADMIN_ROLE: '${ALLOW_SUPER_ADMIN_ROLE}' + GOOGLE_CLIENT_ID: '${GOOGLE_CLIENT_ID}' + GOOGLE_CLIENT_SECRET: '${GOOGLE_CLIENT_SECRET}' + GOOGLE_CALLBACK_URL: '${GOOGLE_CALLBACK_URL}' + FACEBOOK_CLIENT_ID: '${FACEBOOK_CLIENT_ID}' + FACEBOOK_CLIENT_SECRET: '${FACEBOOK_CLIENT_SECRET}' + FACEBOOK_GRAPH_VERSION: '${FACEBOOK_GRAPH_VERSION}' + FACEBOOK_CALLBACK_URL: '${FACEBOOK_CALLBACK_URL}' + INTEGRATED_USER_DEFAULT_PASS: '${INTEGRATED_USER_DEFAULT_PASS}' + UPWORK_REDIRECT_URL: '${UPWORK_REDIRECT_URL}' + FILE_PROVIDER: '${FILE_PROVIDER}' + GAUZY_AI_GRAPHQL_ENDPOINT: '${GAUZY_AI_GRAPHQL_ENDPOINT}' + GAUZY_AI_REST_ENDPOINT: '${GAUZY_AI_REST_ENDPOINT}' + UNLEASH_APP_NAME: '${UNLEASH_APP_NAME}' + UNLEASH_API_URL: '${UNLEASH_API_URL}' + UNLEASH_INSTANCE_ID: '${UNLEASH_INSTANCE_ID}' + UNLEASH_REFRESH_INTERVAL: '${UNLEASH_REFRESH_INTERVAL}' + UNLEASH_METRICS_INTERVAL: '${UNLEASH_METRICS_INTERVAL}' + UNLEASH_API_KEY: '${UNLEASH_API_KEY}' + PM2_MACHINE_NAME: '${PM2_MACHINE_NAME}' + PM2_SECRET_KEY: '${PM2_SECRET_KEY}' + PM2_PUBLIC_KEY: '${PM2_PUBLIC_KEY}' + JITSU_SERVER_URL: '${JITSU_SERVER_URL}' + JITSU_SERVER_WRITE_KEY: '${JITSU_SERVER_WRITE_KEY}' + OTEL_ENABLED: '${OTEL_ENABLED}' + OTEL_PROVIDER: '${OTEL_PROVIDER}' + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT}' + OTEL_EXPORTER_OTLP_HEADERS: '${OTEL_EXPORTER_OTLP_HEADERS}' + GAUZY_GITHUB_CLIENT_ID: '${GAUZY_GITHUB_CLIENT_ID}' + GAUZY_GITHUB_CLIENT_SECRET: '${GAUZY_GITHUB_CLIENT_SECRET}' + GAUZY_GITHUB_APP_PRIVATE_KEY: '${GAUZY_GITHUB_APP_PRIVATE_KEY}' + GAUZY_GITHUB_WEBHOOK_URL: '${GAUZY_GITHUB_WEBHOOK_URL}' + GAUZY_GITHUB_WEBHOOK_SECRET: '${GAUZY_GITHUB_WEBHOOK_SECRET}' + GAUZY_GITHUB_APP_NAME: '${GAUZY_GITHUB_APP_NAME}' + GAUZY_GITHUB_REDIRECT_URL: '${GAUZY_GITHUB_REDIRECT_URL}' + GAUZY_GITHUB_POST_INSTALL_URL: '${GAUZY_GITHUB_POST_INSTALL_URL}' + GAUZY_GITHUB_APP_ID: '${GAUZY_GITHUB_APP_ID}' + GAUZY_GITHUB_OAUTH_CLIENT_ID: '${GAUZY_GITHUB_OAUTH_CLIENT_ID}' + GAUZY_GITHUB_OAUTH_CLIENT_SECRET: '${GAUZY_GITHUB_OAUTH_CLIENT_SECRET}' + GAUZY_GITHUB_OAUTH_CALLBACK_URL: '${GAUZY_GITHUB_OAUTH_CALLBACK_URL}' + JITSU_BROWSER_URL: '${JITSU_BROWSER_URL}' + JITSU_BROWSER_WRITE_KEY: '${JITSU_BROWSER_WRITE_KEY}' + MAGIC_CODE_EXPIRATION_TIME: '${MAGIC_CODE_EXPIRATION_TIME}' + APP_NAME: '${APP_NAME}' + APP_LOGO: '${APP_LOGO}' + APP_SIGNATURE: '${APP_SIGNATURE}' + APP_LINK: '${APP_LINK}' + APP_EMAIL_CONFIRMATION_URL: '${APP_EMAIL_CONFIRMATION_URL}' + APP_MAGIC_SIGN_URL: '${APP_MAGIC_SIGN_URL}' + COMPANY_LINK: '${COMPANY_LINK}' + COMPANY_NAME: '${COMPANY_NAME}' + + entrypoint: './entrypoint.prod.sh' + command: ['node', 'main.js'] + restart: on-failure + ports: + - '3000' + networks: + - overlay +volumes: + certificates: {} + +networks: + overlay: + driver: bridge diff --git a/.deploy/ssh/with-letsencrypt/prod/nginx-certbot.env b/.deploy/ssh/with-letsencrypt/prod/nginx-certbot.env new file mode 100644 index 00000000000..1e81781c095 --- /dev/null +++ b/.deploy/ssh/with-letsencrypt/prod/nginx-certbot.env @@ -0,0 +1,16 @@ +# Required +CERTBOT_EMAIL="ever@ever.co" + +# Optional (Defaults) +DHPARAM_SIZE=2048 +ELLIPTIC_CURVE=secp256r1 +RENEWAL_INTERVAL=8d +RSA_KEY_SIZE=2048 +STAGING=0 +USE_ECDSA=1 + +# Advanced (Defaults) +CERTBOT_AUTHENTICATOR=webroot +CERTBOT_DNS_PROPAGATION_SECONDS="" +DEBUG=0 +USE_LOCAL_CA=0 diff --git a/.deploy/ssh/with-letsencrypt/prod/user_conf.d/nginx.conf b/.deploy/ssh/with-letsencrypt/prod/user_conf.d/nginx.conf new file mode 100644 index 00000000000..4c529929368 --- /dev/null +++ b/.deploy/ssh/with-letsencrypt/prod/user_conf.d/nginx.conf @@ -0,0 +1,15 @@ +server { + listen 443 ssl; + server_name apidts.gauzy.co; + ssl_certificate /etc/letsencrypt/live/apidts.gauzy.co/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/apidts.gauzy.co/privkey.pem; + ssl_trusted_certificate /etc/letsencrypt/live/apidts.gauzy.co/chain.pem; + + # Load the Diffie-Hellman parameter. + ssl_dhparam /etc/letsencrypt/dhparams/dhparam.pem; + + location / { + proxy_pass http://api:3000; + } + +} diff --git a/.deploy/ssh/with-letsencrypt/stage/docker-compose.api.stage.letsencrypt.pre.yml b/.deploy/ssh/with-letsencrypt/stage/docker-compose.api.stage.letsencrypt.pre.yml new file mode 100644 index 00000000000..3c9b424e86f --- /dev/null +++ b/.deploy/ssh/with-letsencrypt/stage/docker-compose.api.stage.letsencrypt.pre.yml @@ -0,0 +1,25 @@ +version: '3.8' + +services: + proxy: + image: jonasal/nginx-certbot:latest + restart: always + environment: + CERTBOT_EMAIL: 'ever@ever.co' + env_file: + - ./nginx-certbot.env + ports: + - '80:80' + - '443:443' + networks: + - stage_overlay + volumes: + - nginx_secrets:/etc/letsencrypt + - ./user_conf.d:/etc/nginx/user_conf.d +volumes: + nginx_secrets: {} + certificates: {} + +networks: + stage_overlay: + external: true diff --git a/.deploy/ssh/with-letsencrypt/stage/docker-compose.api.stage.template.yml b/.deploy/ssh/with-letsencrypt/stage/docker-compose.api.stage.template.yml new file mode 100644 index 00000000000..6472dd893f9 --- /dev/null +++ b/.deploy/ssh/with-letsencrypt/stage/docker-compose.api.stage.template.yml @@ -0,0 +1,121 @@ +version: '3.8' + +services: + api: + image: ghcr.io/ever-co/gauzy-api-stage:latest + deploy: + mode: replicated + replicas: 2 + environment: + API_HOST: '0.0.0.0' + DEMO: '${DEMO}' + NODE_ENV: '${NODE_ENV}' + ADMIN_PASSWORD_RESET: '${ADMIN_PASSWORD_RESET}' + API_BASE_URL: '${API_BASE_URL}' + CLIENT_BASE_URL: '${CLIENT_BASE_URL}' + DB_TYPE: '${DB_TYPE}' + DB_URI: '${DB_URI}' + DB_HOST: '${DB_HOST}' + DB_USER: '${DB_USER}' + DB_PASS: '${DB_PASS}' + DB_NAME: '${DB_NAME}' + DB_PORT: '${DB_PORT}' + DB_CA_CERT: '${DB_CA_CERT}' + DB_SSL_MODE: '${DB_SSL_MODE}' + DB_POOL_SIZE: '${DB_POOL_SIZE}' + DB_POOL_SIZE_KNEX: '${DB_POOL_SIZE_KNEX}' + REDIS_ENABLED: '${REDIS_ENABLED}' + REDIS_URL: '${REDIS_URL}' + CLOUD_PROVIDER: 'DO' + SENTRY_DSN: '${SENTRY_DSN}' + SENTRY_TRACES_SAMPLE_RATE: '${SENTRY_TRACES_SAMPLE_RATE}' + SENTRY_PROFILE_SAMPLE_RATE: '${SENTRY_PROFILE_SAMPLE_RATE}' + SENTRY_HTTP_TRACING_ENABLED: '${SENTRY_HTTP_TRACING_ENABLED}' + SENTRY_POSTGRES_TRACKING_ENABLED: '${SENTRY_POSTGRES_TRACKING_ENABLED}' + SENTRY_PROFILING_ENABLED: '${SENTRY_PROFILING_ENABLED}' + AWS_ACCESS_KEY_ID: '${AWS_ACCESS_KEY_ID}' + AWS_SECRET_ACCESS_KEY: '${AWS_SECRET_ACCESS_KEY}' + AWS_REGION: '${AWS_REGION}' + AWS_S3_BUCKET: '${AWS_S3_BUCKET}' + WASABI_ACCESS_KEY_ID: '${WASABI_ACCESS_KEY_ID}' + WASABI_SECRET_ACCESS_KEY: '${WASABI_SECRET_ACCESS_KEY}' + WASABI_REGION: '${WASABI_REGION}' + WASABI_SERVICE_URL: '${WASABI_SERVICE_URL}' + WASABI_S3_BUCKET: '${WASABI_S3_BUCKET}' + EXPRESS_SESSION_SECRET: '${EXPRESS_SESSION_SECRET}' + JWT_SECRET: '${JWT_SECRET}' + JWT_REFRESH_TOKEN_SECRET: '${JWT_REFRESH_TOKEN_SECRET}' + JWT_REFRESH_TOKEN_EXPIRATION_TIME: '${JWT_REFRESH_TOKEN_EXPIRATION_TIME}' + CLOUDINARY_API_KEY: '${CLOUDINARY_API_KEY}' + CLOUDINARY_API_SECRET: '${CLOUDINARY_API_SECRET}' + CLOUDINARY_CLOUD_NAME: '${CLOUDINARY_CLOUD_NAME}' + MAIL_FROM_ADDRESS: '${MAIL_FROM_ADDRESS}' + MAIL_HOST: '${MAIL_HOST}' + MAIL_PORT: '${MAIL_PORT}' + MAIL_USERNAME: '${MAIL_USERNAME}' + MAIL_PASSWORD: '${MAIL_PASSWORD}' + ALLOW_SUPER_ADMIN_ROLE: '${ALLOW_SUPER_ADMIN_ROLE}' + GOOGLE_CLIENT_ID: '${GOOGLE_CLIENT_ID}' + GOOGLE_CLIENT_SECRET: '${GOOGLE_CLIENT_SECRET}' + GOOGLE_CALLBACK_URL: '${GOOGLE_CALLBACK_URL}' + FACEBOOK_CLIENT_ID: '${FACEBOOK_CLIENT_ID}' + FACEBOOK_CLIENT_SECRET: '${FACEBOOK_CLIENT_SECRET}' + FACEBOOK_GRAPH_VERSION: '${FACEBOOK_GRAPH_VERSION}' + FACEBOOK_CALLBACK_URL: '${FACEBOOK_CALLBACK_URL}' + INTEGRATED_USER_DEFAULT_PASS: '${INTEGRATED_USER_DEFAULT_PASS}' + UPWORK_REDIRECT_URL: '${UPWORK_REDIRECT_URL}' + FILE_PROVIDER: '${FILE_PROVIDER}' + GAUZY_AI_GRAPHQL_ENDPOINT: '${GAUZY_AI_GRAPHQL_ENDPOINT}' + GAUZY_AI_REST_ENDPOINT: '${GAUZY_AI_REST_ENDPOINT}' + UNLEASH_APP_NAME: '${UNLEASH_APP_NAME}' + UNLEASH_API_URL: '${UNLEASH_API_URL}' + UNLEASH_INSTANCE_ID: '${UNLEASH_INSTANCE_ID}' + UNLEASH_REFRESH_INTERVAL: '${UNLEASH_REFRESH_INTERVAL}' + UNLEASH_METRICS_INTERVAL: '${UNLEASH_METRICS_INTERVAL}' + UNLEASH_API_KEY: '${UNLEASH_API_KEY}' + PM2_MACHINE_NAME: '${PM2_MACHINE_NAME}' + PM2_SECRET_KEY: '${PM2_SECRET_KEY}' + PM2_PUBLIC_KEY: '${PM2_PUBLIC_KEY}' + JITSU_SERVER_URL: '${JITSU_SERVER_URL}' + JITSU_SERVER_WRITE_KEY: '${JITSU_SERVER_WRITE_KEY}' + OTEL_ENABLED: '${OTEL_ENABLED}' + OTEL_PROVIDER: '${OTEL_PROVIDER}' + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT}' + OTEL_EXPORTER_OTLP_HEADERS: '${OTEL_EXPORTER_OTLP_HEADERS}' + GAUZY_GITHUB_CLIENT_ID: '${GAUZY_GITHUB_CLIENT_ID}' + GAUZY_GITHUB_CLIENT_SECRET: '${GAUZY_GITHUB_CLIENT_SECRET}' + GAUZY_GITHUB_APP_PRIVATE_KEY: '${GAUZY_GITHUB_APP_PRIVATE_KEY}' + GAUZY_GITHUB_WEBHOOK_URL: '${GAUZY_GITHUB_WEBHOOK_URL}' + GAUZY_GITHUB_WEBHOOK_SECRET: '${GAUZY_GITHUB_WEBHOOK_SECRET}' + GAUZY_GITHUB_APP_NAME: '${GAUZY_GITHUB_APP_NAME}' + GAUZY_GITHUB_REDIRECT_URL: '${GAUZY_GITHUB_REDIRECT_URL}' + GAUZY_GITHUB_POST_INSTALL_URL: '${GAUZY_GITHUB_POST_INSTALL_URL}' + GAUZY_GITHUB_APP_ID: '${GAUZY_GITHUB_APP_ID}' + GAUZY_GITHUB_OAUTH_CLIENT_ID: '${GAUZY_GITHUB_OAUTH_CLIENT_ID}' + GAUZY_GITHUB_OAUTH_CLIENT_SECRET: '${GAUZY_GITHUB_OAUTH_CLIENT_SECRET}' + GAUZY_GITHUB_OAUTH_CALLBACK_URL: '${GAUZY_GITHUB_OAUTH_CALLBACK_URL}' + JITSU_BROWSER_URL: '${JITSU_BROWSER_URL}' + JITSU_BROWSER_WRITE_KEY: '${JITSU_BROWSER_WRITE_KEY}' + MAGIC_CODE_EXPIRATION_TIME: '${MAGIC_CODE_EXPIRATION_TIME}' + APP_NAME: '${APP_NAME}' + APP_LOGO: '${APP_LOGO}' + APP_SIGNATURE: '${APP_SIGNATURE}' + APP_LINK: '${APP_LINK}' + APP_EMAIL_CONFIRMATION_URL: '${APP_EMAIL_CONFIRMATION_URL}' + APP_MAGIC_SIGN_URL: '${APP_MAGIC_SIGN_URL}' + COMPANY_LINK: '${COMPANY_LINK}' + COMPANY_NAME: '${COMPANY_NAME}' + + entrypoint: './entrypoint.prod.sh' + command: ['node', 'main.js'] + restart: on-failure + ports: + - '3000' + networks: + - overlay +volumes: + certificates: {} + +networks: + overlay: + driver: bridge diff --git a/.deploy/ssh/with-letsencrypt/stage/nginx-certbot.env b/.deploy/ssh/with-letsencrypt/stage/nginx-certbot.env new file mode 100644 index 00000000000..1e81781c095 --- /dev/null +++ b/.deploy/ssh/with-letsencrypt/stage/nginx-certbot.env @@ -0,0 +1,16 @@ +# Required +CERTBOT_EMAIL="ever@ever.co" + +# Optional (Defaults) +DHPARAM_SIZE=2048 +ELLIPTIC_CURVE=secp256r1 +RENEWAL_INTERVAL=8d +RSA_KEY_SIZE=2048 +STAGING=0 +USE_ECDSA=1 + +# Advanced (Defaults) +CERTBOT_AUTHENTICATOR=webroot +CERTBOT_DNS_PROPAGATION_SECONDS="" +DEBUG=0 +USE_LOCAL_CA=0 diff --git a/.deploy/ssh/with-letsencrypt/stage/user_conf.d/nginx.conf b/.deploy/ssh/with-letsencrypt/stage/user_conf.d/nginx.conf new file mode 100644 index 00000000000..301fdf0b378 --- /dev/null +++ b/.deploy/ssh/with-letsencrypt/stage/user_conf.d/nginx.conf @@ -0,0 +1,15 @@ +server { + listen 443 ssl; + server_name apistagedts.gauzy.co; + ssl_certificate /etc/letsencrypt/live/apistagedts.gauzy.co/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/apistagedts.gauzy.co/privkey.pem; + ssl_trusted_certificate /etc/letsencrypt/live/apistagedts.gauzy.co/chain.pem; + + # Load the Diffie-Hellman parameter. + ssl_dhparam /etc/letsencrypt/dhparams/dhparam.pem; + + location / { + proxy_pass http://api:3000; + } + +} diff --git a/.do/app.yaml b/.do/app.yaml new file mode 100644 index 00000000000..bf62fffcaa9 --- /dev/null +++ b/.do/app.yaml @@ -0,0 +1,315 @@ +alerts: + - rule: DEPLOYMENT_FAILED + - rule: DOMAIN_FAILED +name: ever-gauzy-$ENV_NAME +region: sfo +domains: + - domain: $APP_DOMAIN + type: ALIAS +services: + - name: api + instance_count: $INSTANCE_COUNT + instance_size_slug: $INSTANCE_SIZE + http_port: 3000 + image: + registry_type: 'DOCR' + registry: '' + repository: $DOCR_REPOSITORY + tag: 'latest' + deploy_on_push: + enabled: true + envs: + - key: API_HOST + scope: RUN_TIME + value: '$API_HOST' + - key: DEMO + scope: RUN_TIME + value: '$DEMO' + - key: NODE_ENV + scope: RUN_TIME + value: '$NODE_ENV' + - key: ADMIN_PASSWORD_RESET + scope: RUN_TIME + value: '$ADMIN_PASSWORD_RESET' + - key: API_BASE_URL + scope: RUN_TIME + value: '$API_BASE_URL' + - key: CLIENT_BASE_URL + scope: RUN_TIME + value: '$CLIENT_BASE_URL' + - key: DB_TYPE + scope: RUN_TIME + value: '$DB_TYPE' + - key: DB_URI + scope: RUN_TIME + value: '$DB_URI' + - key: DB_HOST + scope: RUN_TIME + value: '$DB_HOST' + - key: DB_USER + scope: RUN_TIME + value: '$DB_USER' + - key: DB_PASS + scope: RUN_TIME + value: '$DB_PASS' + - key: DB_NAME + scope: RUN_TIME + value: '$DB_NAME' + - key: DB_PORT + scope: RUN_TIME + value: '$DB_PORT' + - key: DB_CA_CERT + scope: RUN_TIME + value: '$DB_CA_CERT' + - key: DB_SSL_MODE + scope: RUN_TIME + value: '$DB_SSL_MODE' + - key: DB_POOL_SIZE + scope: RUN_TIME + value: '$DB_POOL_SIZE' + - key: DB_POOL_SIZE_KNEX + scope: RUN_TIME + value: '$DB_POOL_SIZE_KNEX' + - key: REDIS_ENABLED + scope: RUN_TIME + value: '$REDIS_ENABLED' + - key: REDIS_URL + scope: RUN_TIME + value: '$REDIS_URL' + - key: CLOUD_PROVIDER + scope: RUN_TIME + value: 'DO' + - key: SENTRY_DSN + scope: RUN_TIME + value: '$SENTRY_DSN' + - key: SENTRY_TRACES_SAMPLE_RATE + scope: RUN_TIME + value: '$SENTRY_TRACES_SAMPLE_RATE' + - key: SENTRY_PROFILE_SAMPLE_RATE + scope: RUN_TIME + value: '$SENTRY_PROFILE_SAMPLE_RATE' + - key: SENTRY_HTTP_TRACING_ENABLED + scope: RUN_TIME + value: '$SENTRY_HTTP_TRACING_ENABLED' + - key: SENTRY_POSTGRES_TRACKING_ENABLED + scope: RUN_TIME + value: '$SENTRY_POSTGRES_TRACKING_ENABLED' + - key: SENTRY_PROFILING_ENABLED + scope: RUN_TIME + value: '$SENTRY_PROFILING_ENABLED' + - key: AWS_ACCESS_KEY_ID + scope: RUN_TIME + value: '$AWS_ACCESS_KEY_ID' + - key: AWS_SECRET_ACCESS_KEY + scope: RUN_TIME + value: '$AWS_SECRET_ACCESS_KEY' + - key: AWS_REGION + scope: RUN_TIME + value: '$AWS_REGION' + - key: AWS_S3_BUCKET + scope: RUN_TIME + value: '$AWS_S3_BUCKET' + - key: WASABI_ACCESS_KEY_ID + scope: RUN_TIME + value: '$WASABI_ACCESS_KEY_ID' + - key: WASABI_SECRET_ACCESS_KEY + scope: RUN_TIME + value: '$WASABI_SECRET_ACCESS_KEY' + - key: WASABI_REGION + scope: RUN_TIME + value: '$WASABI_REGION' + - key: WASABI_SERVICE_URL + scope: RUN_TIME + value: '$WASABI_SERVICE_URL' + - key: WASABI_S3_BUCKET + scope: RUN_TIME + value: '$WASABI_S3_BUCKET' + - key: EXPRESS_SESSION_SECRET + scope: RUN_TIME + value: '$EXPRESS_SESSION_SECRET' + - key: JWT_SECRET + scope: RUN_TIME + value: '$JWT_SECRET' + - key: JWT_REFRESH_TOKEN_SECRET + scope: RUN_TIME + value: '$JWT_REFRESH_TOKEN_SECRET' + - key: JWT_REFRESH_TOKEN_EXPIRATION_TIME + scope: RUN_TIME + value: '$JWT_REFRESH_TOKEN_EXPIRATION_TIME' + - key: CLOUDINARY_API_KEY + scope: RUN_TIME + value: '$CLOUDINARY_API_KEY' + - key: CLOUDINARY_API_SECRET + scope: RUN_TIME + value: '$CLOUDINARY_API_SECRET' + - key: CLOUDINARY_CLOUD_NAME + scope: RUN_TIME + value: '$CLOUDINARY_CLOUD_NAME' + - key: MAIL_FROM_ADDRESS + scope: RUN_TIME + value: '$MAIL_FROM_ADDRESS' + - key: MAIL_HOST + scope: RUN_TIME + value: '$MAIL_HOST' + - key: MAIL_PORT + scope: RUN_TIME + value: '$MAIL_PORT' + - key: MAIL_USERNAME + scope: RUN_TIME + value: '$MAIL_USERNAME' + - key: MAIL_PASSWORD + scope: RUN_TIME + value: '$MAIL_PASSWORD' + - key: ALLOW_SUPER_ADMIN_ROLE + scope: RUN_TIME + value: '$ALLOW_SUPER_ADMIN_ROLE' + - key: GOOGLE_CLIENT_ID + scope: RUN_TIME + value: '$GOOGLE_CLIENT_ID' + - key: GOOGLE_CLIENT_SECRET + scope: RUN_TIME + value: '$GOOGLE_CLIENT_SECRET' + - key: GOOGLE_CALLBACK_URL + scope: RUN_TIME + value: '$GOOGLE_CALLBACK_URL' + - key: FACEBOOK_CLIENT_ID + scope: RUN_TIME + value: '$FACEBOOK_CLIENT_ID' + - key: FACEBOOK_CLIENT_SECRET + scope: RUN_TIME + value: '$FACEBOOK_CLIENT_SECRET' + - key: FACEBOOK_GRAPH_VERSION + scope: RUN_TIME + value: '$FACEBOOK_GRAPH_VERSION' + - key: FACEBOOK_CALLBACK_URL + scope: RUN_TIME + value: '$FACEBOOK_CALLBACK_URL' + - key: INTEGRATED_USER_DEFAULT_PASS + scope: RUN_TIME + value: '$INTEGRATED_USER_DEFAULT_PASS' + - key: UPWORK_REDIRECT_URL + scope: RUN_TIME + value: '$UPWORK_REDIRECT_URL' + - key: FILE_PROVIDER + scope: RUN_TIME + value: '$FILE_PROVIDER' + - key: GAUZY_AI_GRAPHQL_ENDPOINT + scope: RUN_TIME + value: '$GAUZY_AI_GRAPHQL_ENDPOINT' + - key: GAUZY_AI_REST_ENDPOINT + scope: RUN_TIME + value: '$GAUZY_AI_REST_ENDPOINT' + - key: UNLEASH_APP_NAME + scope: RUN_TIME + value: '$UNLEASH_APP_NAME' + - key: UNLEASH_API_URL + scope: RUN_TIME + value: '$UNLEASH_API_URL' + - key: UNLEASH_INSTANCE_ID + scope: RUN_TIME + value: '$UNLEASH_INSTANCE_ID' + - key: UNLEASH_REFRESH_INTERVAL + scope: RUN_TIME + value: '$UNLEASH_REFRESH_INTERVAL' + - key: UNLEASH_METRICS_INTERVAL + scope: RUN_TIME + value: '$UNLEASH_METRICS_INTERVAL' + - key: UNLEASH_API_KEY + scope: RUN_TIME + value: '$UNLEASH_API_KEY' + - key: PM2_MACHINE_NAME + scope: RUN_TIME + value: '$PM2_MACHINE_NAME' + - key: PM2_SECRET_KEY + scope: RUN_TIME + value: '$PM2_SECRET_KEY' + - key: PM2_PUBLIC_KEY + scope: RUN_TIME + value: '$PM2_PUBLIC_KEY' + - key: JITSU_SERVER_URL + scope: RUN_TIME + value: '$JITSU_SERVER_URL' + - key: JITSU_SERVER_WRITE_KEY + scope: RUN_TIME + value: '$JITSU_SERVER_WRITE_KEY' + - key: OTEL_ENABLED + scope: RUN_TIME + value: '$OTEL_ENABLED' + - key: OTEL_PROVIDER + scope: RUN_TIME + value: '$OTEL_PROVIDER' + - key: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT + scope: RUN_TIME + value: '$OTEL_EXPORTER_OTLP_TRACES_ENDPOINT' + - key: OTEL_EXPORTER_OTLP_HEADERS + scope: RUN_TIME + value: '$OTEL_EXPORTER_OTLP_HEADERS' + - key: GAUZY_GITHUB_CLIENT_ID + scope: RUN_TIME + value: '$GAUZY_GITHUB_CLIENT_ID' + - key: GAUZY_GITHUB_CLIENT_SECRET + scope: RUN_TIME + value: '$GAUZY_GITHUB_CLIENT_SECRET' + - key: GAUZY_GITHUB_APP_PRIVATE_KEY + scope: RUN_TIME + value: '$GAUZY_GITHUB_APP_PRIVATE_KEY' + - key: GAUZY_GITHUB_WEBHOOK_URL + scope: RUN_TIME + value: '$GAUZY_GITHUB_WEBHOOK_URL' + - key: GAUZY_GITHUB_WEBHOOK_SECRET + scope: RUN_TIME + value: '$GAUZY_GITHUB_WEBHOOK_SECRET' + - key: GAUZY_GITHUB_APP_NAME + scope: RUN_TIME + value: '$GAUZY_GITHUB_APP_NAME' + - key: GAUZY_GITHUB_REDIRECT_URL + scope: RUN_TIME + value: '$GAUZY_GITHUB_REDIRECT_URL' + - key: GAUZY_GITHUB_POST_INSTALL_URL + scope: RUN_TIME + value: '$GAUZY_GITHUB_POST_INSTALL_URL' + - key: GAUZY_GITHUB_APP_ID + scope: RUN_TIME + value: '$GAUZY_GITHUB_APP_ID' + - key: GAUZY_GITHUB_OAUTH_CLIENT_ID + scope: RUN_TIME + value: '$GAUZY_GITHUB_OAUTH_CLIENT_ID' + - key: GAUZY_GITHUB_OAUTH_CLIENT_SECRET + scope: RUN_TIME + value: '$GAUZY_GITHUB_OAUTH_CLIENT_SECRET' + - key: GAUZY_GITHUB_OAUTH_CALLBACK_URL + scope: RUN_TIME + value: '$GAUZY_GITHUB_OAUTH_CALLBACK_URL' + - key: JITSU_BROWSER_URL + scope: RUN_TIME + value: '$JITSU_BROWSER_URL' + - key: JITSU_BROWSER_WRITE_KEY + scope: RUN_TIME + value: '$JITSU_BROWSER_WRITE_KEY' + - key: MAGIC_CODE_EXPIRATION_TIME + scope: RUN_TIME + value: '$MAGIC_CODE_EXPIRATION_TIME' + - key: APP_NAME + scope: RUN_TIME + value: '$APP_NAME' + - key: APP_LOGO + scope: RUN_TIME + value: '$APP_LOGO' + - key: APP_SIGNATURE + scope: RUN_TIME + value: '$APP_SIGNATURE' + - key: APP_LINK + scope: RUN_TIME + value: '$APP_LINK' + - key: APP_EMAIL_CONFIRMATION_URL + scope: RUN_TIME + value: '$APP_EMAIL_CONFIRMATION_URL' + - key: APP_MAGIC_SIGN_URL + scope: RUN_TIME + value: '$APP_MAGIC_SIGN_URL' + - key: COMPANY_LINK + scope: RUN_TIME + value: '$COMPANY_LINK' + - key: COMPANY_NAME + scope: RUN_TIME + value: '$COMPANY_NAME' diff --git a/.env.compose b/.env.compose index 521b146d66a..e5d2d38931c 100644 --- a/.env.compose +++ b/.env.compose @@ -384,10 +384,18 @@ JITSU_SERVER_WRITE_KEY= JITSU_SERVER_DEBUG= JITSU_SERVER_ECHO_EVENTS= -# Signoz Configuration +# Tracing Configuration +OTEL_ENABLED=false +OTEL_PROVIDER=zipkin +OTEL_SERVICE_NAME= +OTEL_EXPORTER_OTLP_PROTOCOL= OTEL_EXPORTER_OTLP_HEADERS= OTEL_EXPORTER_OTLP_TRACES_ENDPOINT= -OTEL_ENABLED=false +OTEL_EXPORTER_OTLP_METRICS_ENDPOINT= +OTEL_EXPORTER_OTLP_ENDPOINT= +ASPECTO_API_KEY= +HONEYCOMB_API_KEY= +HONEYCOMB_ENABLE_LOCAL_VISUALIZATIONS= # Platform Logo resource URL (SVG is Recommended) PLATFORM_LOGO='assets/images/logos/logo_Gauzy.svg' diff --git a/.env.demo.compose b/.env.demo.compose index 62ca8f34b2d..98df33830ec 100644 --- a/.env.demo.compose +++ b/.env.demo.compose @@ -386,10 +386,18 @@ JITSU_SERVER_WRITE_KEY= JITSU_SERVER_DEBUG= JITSU_SERVER_ECHO_EVENTS= -# Signoz Configuration +# Tracing Configuration +OTEL_ENABLED=false +OTEL_PROVIDER=zipkin +OTEL_SERVICE_NAME= +OTEL_EXPORTER_OTLP_PROTOCOL= OTEL_EXPORTER_OTLP_HEADERS= OTEL_EXPORTER_OTLP_TRACES_ENDPOINT= -OTEL_ENABLED=false +OTEL_EXPORTER_OTLP_METRICS_ENDPOINT= +OTEL_EXPORTER_OTLP_ENDPOINT= +ASPECTO_API_KEY= +HONEYCOMB_API_KEY= +HONEYCOMB_ENABLE_LOCAL_VISUALIZATIONS= # Platform Logo resource URL (SVG is Recommended) PLATFORM_LOGO='assets/images/logos/logo_Gauzy.svg' diff --git a/.env.docker b/.env.docker index abe583a99a6..60fa75543a9 100644 --- a/.env.docker +++ b/.env.docker @@ -365,10 +365,18 @@ JITSU_SERVER_WRITE_KEY= JITSU_SERVER_DEBUG= JITSU_SERVER_ECHO_EVENTS= -# Signoz Configuration +# Tracing Configuration +OTEL_ENABLED=false +OTEL_PROVIDER=zipkin +OTEL_SERVICE_NAME= +OTEL_EXPORTER_OTLP_PROTOCOL= OTEL_EXPORTER_OTLP_HEADERS= OTEL_EXPORTER_OTLP_TRACES_ENDPOINT= -OTEL_ENABLED=false +OTEL_EXPORTER_OTLP_METRICS_ENDPOINT= +OTEL_EXPORTER_OTLP_ENDPOINT= +ASPECTO_API_KEY= +HONEYCOMB_API_KEY= +HONEYCOMB_ENABLE_LOCAL_VISUALIZATIONS= # Platform Logo resource URL (SVG is Recommended) PLATFORM_LOGO='assets/images/logos/logo_Gauzy.svg' diff --git a/.env.local b/.env.local index 9d3626dbbfb..dac6768b0a7 100644 --- a/.env.local +++ b/.env.local @@ -355,10 +355,18 @@ JITSU_SERVER_WRITE_KEY= JITSU_SERVER_DEBUG= JITSU_SERVER_ECHO_EVENTS= -# Signoz Configuration +# Tracing Configuration +OTEL_ENABLED=false +OTEL_PROVIDER=zipkin +OTEL_SERVICE_NAME= +OTEL_EXPORTER_OTLP_PROTOCOL= OTEL_EXPORTER_OTLP_HEADERS= OTEL_EXPORTER_OTLP_TRACES_ENDPOINT= -OTEL_ENABLED=false +OTEL_EXPORTER_OTLP_METRICS_ENDPOINT= +OTEL_EXPORTER_OTLP_ENDPOINT= +ASPECTO_API_KEY= +HONEYCOMB_API_KEY= +HONEYCOMB_ENABLE_LOCAL_VISUALIZATIONS= # Platform Logo resource URL (SVG is Recommended) PLATFORM_LOGO='assets/images/logos/logo_Gauzy.svg' diff --git a/.env.sample b/.env.sample index 15b0c54d424..17c22f87df7 100644 --- a/.env.sample +++ b/.env.sample @@ -376,10 +376,18 @@ JITSU_SERVER_WRITE_KEY= JITSU_SERVER_DEBUG= JITSU_SERVER_ECHO_EVENTS= -# Signoz Configuration +# Tracing Configuration +OTEL_ENABLED=false +OTEL_PROVIDER=zipkin +OTEL_SERVICE_NAME= +OTEL_EXPORTER_OTLP_PROTOCOL= OTEL_EXPORTER_OTLP_HEADERS= OTEL_EXPORTER_OTLP_TRACES_ENDPOINT= -OTEL_ENABLED=false +OTEL_EXPORTER_OTLP_METRICS_ENDPOINT= +OTEL_EXPORTER_OTLP_ENDPOINT= +ASPECTO_API_KEY= +HONEYCOMB_API_KEY= +HONEYCOMB_ENABLE_LOCAL_VISUALIZATIONS= # Platform Logo resource URL (SVG is Recommended) PLATFORM_LOGO='assets/images/logos/logo_Gauzy.svg' diff --git a/.github/workflows/deploy-civo-demo.yml b/.github/workflows/deploy-civo-demo.yml index 6f111ffb266..ef90b8beb28 100644 --- a/.github/workflows/deploy-civo-demo.yml +++ b/.github/workflows/deploy-civo-demo.yml @@ -46,6 +46,7 @@ jobs: SENTRY_POSTGRES_TRACKING_ENABLED: '${{ secrets.SENTRY_POSTGRES_TRACKING_ENABLED }}' SENTRY_PROFILING_ENABLED: '${{ secrets.SENTRY_PROFILING_ENABLED }}' OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}' OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' diff --git a/.github/workflows/deploy-civo-prod.yml b/.github/workflows/deploy-civo-prod.yml index b460e9523c9..5818e8dd542 100644 --- a/.github/workflows/deploy-civo-prod.yml +++ b/.github/workflows/deploy-civo-prod.yml @@ -110,6 +110,7 @@ jobs: JITSU_SERVER_URL: '${{ secrets.JITSU_SERVER_URL }}' JITSU_SERVER_WRITE_KEY: '${{ secrets.JITSU_SERVER_WRITE_KEY }}' OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}' OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' GAUZY_GITHUB_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_CLIENT_ID }}' diff --git a/.github/workflows/deploy-civo-stage.yml b/.github/workflows/deploy-civo-stage.yml index e6282c01750..97e1be8448c 100644 --- a/.github/workflows/deploy-civo-stage.yml +++ b/.github/workflows/deploy-civo-stage.yml @@ -111,6 +111,7 @@ jobs: JITSU_SERVER_URL: '${{ secrets.JITSU_SERVER_URL }}' JITSU_SERVER_WRITE_KEY: '${{ secrets.JITSU_SERVER_WRITE_KEY }}' OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}' OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' GAUZY_GITHUB_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_CLIENT_ID }}' diff --git a/.github/workflows/deploy-cw-demo.yml b/.github/workflows/deploy-cw-demo.yml index 45cb8395761..d7ea4055683 100644 --- a/.github/workflows/deploy-cw-demo.yml +++ b/.github/workflows/deploy-cw-demo.yml @@ -46,6 +46,7 @@ jobs: SENTRY_POSTGRES_TRACKING_ENABLED: '${{ secrets.SENTRY_POSTGRES_TRACKING_ENABLED }}' SENTRY_PROFILING_ENABLED: '${{ secrets.SENTRY_PROFILING_ENABLED }}' OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}' OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' diff --git a/.github/workflows/deploy-cw-prod.yml b/.github/workflows/deploy-cw-prod.yml index 08f9121b5ca..414acb3adf5 100644 --- a/.github/workflows/deploy-cw-prod.yml +++ b/.github/workflows/deploy-cw-prod.yml @@ -110,6 +110,7 @@ jobs: JITSU_SERVER_URL: '${{ secrets.JITSU_SERVER_URL }}' JITSU_SERVER_WRITE_KEY: '${{ secrets.JITSU_SERVER_WRITE_KEY }}' OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}' OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' GAUZY_GITHUB_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_CLIENT_ID }}' diff --git a/.github/workflows/deploy-cw-stage.yml b/.github/workflows/deploy-cw-stage.yml index 951c08645a6..08d9724e708 100644 --- a/.github/workflows/deploy-cw-stage.yml +++ b/.github/workflows/deploy-cw-stage.yml @@ -111,6 +111,7 @@ jobs: JITSU_SERVER_URL: '${{ secrets.JITSU_SERVER_URL }}' JITSU_SERVER_WRITE_KEY: '${{ secrets.JITSU_SERVER_WRITE_KEY }}' OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}' OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' GAUZY_GITHUB_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_CLIENT_ID }}' diff --git a/.github/workflows/deploy-do-app-platform-demo.yml b/.github/workflows/deploy-do-app-platform-demo.yml new file mode 100644 index 00000000000..a292d22f2dd --- /dev/null +++ b/.github/workflows/deploy-do-app-platform-demo.yml @@ -0,0 +1,164 @@ +name: Deploy to DigitalOcean App Platform Demo + +on: + workflow_run: + workflows: ['Build and Publish Docker Images Demo'] + branches: [develop] + types: + - completed + +jobs: + deploy: + runs-on: buildjet-4vcpu-ubuntu-2204 + + environment: demo + + steps: + - name: checkout out code + uses: actions/checkout@v4 + + - name: Install doctl + uses: digitalocean/action-doctl@v2 + with: + token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + + - name: Modify DB_HOST and REDIS_URL + run: | + echo "DB_HOST_PUBLIC=$(echo '${{ secrets.DB_HOST }}' | sed 's/private-//')" >> $GITHUB_ENV + echo "REDIS_URL_PUBLIC=$(echo '${{ secrets.REDIS_URL }}' | sed 's/private-//')" >> $GITHUB_ENV + + - name: Inject secrets into .do/app.yaml + run: | + envsubst < $GITHUB_WORKSPACE/.do/app.yaml > temp.yaml && mv temp.yaml $GITHUB_WORKSPACE/.do/app.yaml + env: + ENV_NAME: 'demo' + DOCR_REPOSITORY: 'gauzy-api-demo' + APP_DOMAIN: 'apidemoda.gauzy.co' + INSTANCE_COUNT: '1' + INSTANCE_SIZE: 'professional-xs' + API_HOST: '0.0.0.0' + DEMO: 'true' + NODE_ENV: 'development' + ADMIN_PASSWORD_RESET: 'true' + API_BASE_URL: 'https://apidemoda.gauzy.co' + CLIENT_BASE_URL: 'https://demo.gauzy.co' + DB_TYPE: '${{ secrets.DB_TYPE }}' + DB_URI: '${{ secrets.DB_URI }}' + DB_HOST: '${{ env.DB_HOST_PUBLIC }}' + DB_USER: '${{ secrets.DB_USER }}' + DB_PASS: '${{ secrets.DB_PASS }}' + DB_NAME: '${{ secrets.DB_NAME }}' + DB_PORT: '${{ secrets.DB_PORT }}' + DB_CA_CERT: '${{ secrets.DB_CA_CERT }}' + DB_SSL_MODE: '${{ secrets.DB_SSL_MODE }}' + DB_POOL_SIZE: '${{ secrets.DB_POOL_SIZE }}' + DB_POOL_SIZE_KNEX: '${{ secrets.DB_POOL_SIZE_KNEX }}' + REDIS_ENABLED: '${{ secrets.REDIS_ENABLED }}' + REDIS_URL: '${{ env.REDIS_URL_PUBLIC }}' + CLOUD_PROVIDER: 'DO' + SENTRY_DSN: '${{ secrets.SENTRY_DSN }}' + SENTRY_TRACES_SAMPLE_RATE: '${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}' + SENTRY_PROFILE_SAMPLE_RATE: '${{ secrets.SENTRY_PROFILE_SAMPLE_RATE }}' + SENTRY_HTTP_TRACING_ENABLED: '${{ secrets.SENTRY_HTTP_TRACING_ENABLED }}' + SENTRY_POSTGRES_TRACKING_ENABLED: '${{ secrets.SENTRY_POSTGRES_TRACKING_ENABLED }}' + SENTRY_PROFILING_ENABLED: '${{ secrets.SENTRY_PROFILING_ENABLED }}' + AWS_ACCESS_KEY_ID: '${{ secrets.AWS_ACCESS_KEY_ID }}' + AWS_SECRET_ACCESS_KEY: '${{ secrets.AWS_SECRET_ACCESS_KEY }}' + AWS_REGION: '${{ secrets.AWS_REGION }}' + AWS_S3_BUCKET: '${{ secrets.AWS_S3_BUCKET }}' + WASABI_ACCESS_KEY_ID: '${{ secrets.WASABI_ACCESS_KEY_ID }}' + WASABI_SECRET_ACCESS_KEY: '${{ secrets.WASABI_SECRET_ACCESS_KEY }}' + WASABI_REGION: '${{ secrets.WASABI_REGION }}' + WASABI_SERVICE_URL: '${{ secrets.WASABI_SERVICE_URL }}' + WASABI_S3_BUCKET: '${{ secrets.WASABI_S3_BUCKET }}' + EXPRESS_SESSION_SECRET: '${{ secrets.EXPRESS_SESSION_SECRET }}' + JWT_SECRET: '${{ secrets.JWT_SECRET }}' + JWT_REFRESH_TOKEN_SECRET: '${{ secrets.JWT_REFRESH_TOKEN_SECRET }}' + JWT_REFRESH_TOKEN_EXPIRATION_TIME: '${{ secrets.JWT_REFRESH_TOKEN_EXPIRATION_TIME }}' + CLOUDINARY_API_KEY: '${{ secrets.CLOUDINARY_API_KEY }}' + CLOUDINARY_API_SECRET: '${{ secrets.CLOUDINARY_API_SECRET }}' + CLOUDINARY_CLOUD_NAME: '${{ secrets.CLOUDINARY_CLOUD_NAME }}' + MAIL_FROM_ADDRESS: '${{ secrets.MAIL_FROM_ADDRESS }}' + MAIL_HOST: '${{ secrets.MAIL_HOST }}' + MAIL_PORT: '${{ secrets.MAIL_PORT }}' + MAIL_USERNAME: '${{ secrets.MAIL_USERNAME }}' + MAIL_PASSWORD: '${{ secrets.MAIL_PASSWORD }}' + ALLOW_SUPER_ADMIN_ROLE: '${{ secrets.ALLOW_SUPER_ADMIN_ROLE }}' + GOOGLE_CLIENT_ID: '${{ secrets.GOOGLE_CLIENT_ID }}' + GOOGLE_CLIENT_SECRET: '${{ secrets.GOOGLE_CLIENT_SECRET }}' + GOOGLE_CALLBACK_URL: '${{ secrets.GOOGLE_CALLBACK_URL }}' + FACEBOOK_CLIENT_ID: '${{ secrets.FACEBOOK_CLIENT_ID }}' + FACEBOOK_CLIENT_SECRET: '${{ secrets.FACEBOOK_CLIENT_SECRET }}' + FACEBOOK_GRAPH_VERSION: '${{ secrets.FACEBOOK_GRAPH_VERSION }}' + FACEBOOK_CALLBACK_URL: '${{ secrets.FACEBOOK_CALLBACK_URL }}' + INTEGRATED_USER_DEFAULT_PASS: '${{ secrets.INTEGRATED_USER_DEFAULT_PASS }}' + UPWORK_REDIRECT_URL: '${{ secrets.UPWORK_REDIRECT_URL }}' + FILE_PROVIDER: '${{ secrets.FILE_PROVIDER }}' + GAUZY_AI_GRAPHQL_ENDPOINT: '${{ secrets.GAUZY_AI_GRAPHQL_ENDPOINT }}' + GAUZY_AI_REST_ENDPOINT: '${{ secrets.GAUZY_AI_REST_ENDPOINT }}' + UNLEASH_APP_NAME: '${{ secrets.UNLEASH_APP_NAME }}' + UNLEASH_API_URL: '${{ secrets.UNLEASH_API_URL }}' + UNLEASH_INSTANCE_ID: '${{ secrets.UNLEASH_INSTANCE_ID }}' + UNLEASH_REFRESH_INTERVAL: '${{ secrets.UNLEASH_REFRESH_INTERVAL }}' + UNLEASH_METRICS_INTERVAL: '${{ secrets.UNLEASH_METRICS_INTERVAL }}' + UNLEASH_API_KEY: '${{ secrets.UNLEASH_API_KEY }}' + PM2_MACHINE_NAME: '${{ secrets.PM2_MACHINE_NAME }}' + PM2_SECRET_KEY: '${{ secrets.PM2_SECRET_KEY }}' + PM2_PUBLIC_KEY: '${{ secrets.PM2_PUBLIC_KEY }}' + JITSU_SERVER_URL: '${{ secrets.JITSU_SERVER_URL }}' + JITSU_SERVER_WRITE_KEY: '${{ secrets.JITSU_SERVER_WRITE_KEY }}' + OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}' + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' + OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' + GAUZY_GITHUB_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_CLIENT_ID }}' + GAUZY_GITHUB_CLIENT_SECRET: '${{ secrets.GAUZY_GITHUB_CLIENT_SECRET }}' + GAUZY_GITHUB_APP_PRIVATE_KEY: '${{ secrets.GAUZY_GITHUB_APP_PRIVATE_KEY }}' + GAUZY_GITHUB_WEBHOOK_URL: '${{ secrets.GAUZY_GITHUB_WEBHOOK_URL }}' + GAUZY_GITHUB_WEBHOOK_SECRET: '${{ secrets.GAUZY_GITHUB_WEBHOOK_SECRET }}' + GAUZY_GITHUB_APP_NAME: '${{ secrets.GAUZY_GITHUB_APP_NAME }}' + GAUZY_GITHUB_REDIRECT_URL: '${{ secrets.GAUZY_GITHUB_REDIRECT_URL }}' + GAUZY_GITHUB_POST_INSTALL_URL: '${{ secrets.GAUZY_GITHUB_POST_INSTALL_URL }}' + GAUZY_GITHUB_APP_ID: '${{ secrets.GAUZY_GITHUB_APP_ID }}' + GAUZY_GITHUB_OAUTH_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_OAUTH_CLIENT_ID }}' + GAUZY_GITHUB_OAUTH_CLIENT_SECRET: '${{ secrets.GAUZY_GITHUB_OAUTH_CLIENT_SECRET }}' + GAUZY_GITHUB_OAUTH_CALLBACK_URL: '${{ secrets.GAUZY_GITHUB_OAUTH_CALLBACK_URL }}' + JITSU_BROWSER_URL: '${{ secrets.JITSU_BROWSER_URL }}' + JITSU_BROWSER_WRITE_KEY: '${{ secrets.JITSU_BROWSER_WRITE_KEY }}' + MAGIC_CODE_EXPIRATION_TIME: '${{ secrets.MAGIC_CODE_EXPIRATION_TIME }}' + APP_NAME: '${{ secrets.APP_NAME }}' + APP_LOGO: '${{ secrets.APP_LOGO }}' + APP_SIGNATURE: '${{ secrets.APP_SIGNATURE }}' + APP_LINK: '${{ secrets.APP_LINK }}' + APP_EMAIL_CONFIRMATION_URL: '${{ secrets.APP_EMAIL_CONFIRMATION_URL }}' + APP_MAGIC_SIGN_URL: '${{ secrets.APP_MAGIC_SIGN_URL }}' + COMPANY_LINK: '${{ secrets.COMPANY_LINK }}' + COMPANY_NAME: '${{ secrets.COMPANY_NAME }}' + + - name: Check if App Exists + id: check-app + run: | + echo "ENV_NAME is set to '${ENV_NAME}'" + APP_NAME="ever-gauzy-${ENV_NAME}" + echo "Looking for app with name: $APP_NAME" + doctl apps list --no-header + APP_ID=$(doctl apps list --no-header | awk -v appName="$APP_NAME" '$2 == appName {print $1}') + if [ -z "$APP_ID" ]; then + echo "App does not exist, setting CREATE_APP to true" + echo "::set-output name=create_app::true" + else + echo "App exists with ID $APP_ID, setting APP_ID" + echo "::set-output name=app_id::$APP_ID" + echo "::set-output name=create_app::false" + fi + env: + DIGITALOCEAN_ACCESS_TOKEN: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + ENV_NAME: 'demo' + + - name: Create App + if: steps.check-app.outputs.create_app == 'true' + run: doctl apps create --spec .do/app.yaml + + - name: Update App + if: steps.check-app.outputs.create_app == 'false' + run: doctl apps update ${{ steps.check-app.outputs.app_id }} --spec .do/app.yaml diff --git a/.github/workflows/deploy-do-app-platform-prod.yml b/.github/workflows/deploy-do-app-platform-prod.yml new file mode 100644 index 00000000000..86cbce2769c --- /dev/null +++ b/.github/workflows/deploy-do-app-platform-prod.yml @@ -0,0 +1,164 @@ +name: Deploy to DigitalOcean App Platform Prod + +on: + workflow_run: + workflows: ['Build and Publish Docker Images Prod'] + branches: [master] + types: + - completed + +jobs: + deploy: + runs-on: buildjet-4vcpu-ubuntu-2204 + + environment: prod + + steps: + - name: checkout out code + uses: actions/checkout@v4 + + - name: Install doctl + uses: digitalocean/action-doctl@v2 + with: + token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + + - name: Modify DB_HOST and REDIS_URL + run: | + echo "DB_HOST_PUBLIC=$(echo '${{ secrets.DB_HOST }}' | sed 's/private-//')" >> $GITHUB_ENV + echo "REDIS_URL_PUBLIC=$(echo '${{ secrets.REDIS_URL }}' | sed 's/private-//')" >> $GITHUB_ENV + + - name: Inject secrets into .do/app.yaml + run: | + envsubst < $GITHUB_WORKSPACE/.do/app.yaml > temp.yaml && mv temp.yaml $GITHUB_WORKSPACE/.do/app.yaml + env: + ENV_NAME: 'prod' + DOCR_REPOSITORY: 'gauzy-api' + APP_DOMAIN: 'apida.gauzy.co' + INSTANCE_COUNT: '2' + INSTANCE_SIZE: 'professional-s' + API_HOST: '0.0.0.0' + DEMO: 'false' + NODE_ENV: 'production' + ADMIN_PASSWORD_RESET: 'false' + API_BASE_URL: 'https://apida.gauzy.co' + CLIENT_BASE_URL: 'https://app.gauzy.co' + DB_TYPE: '${{ secrets.DB_TYPE }}' + DB_URI: '${{ secrets.DB_URI }}' + DB_HOST: '${{ env.DB_HOST_PUBLIC }}' + DB_USER: '${{ secrets.DB_USER }}' + DB_PASS: '${{ secrets.DB_PASS }}' + DB_NAME: '${{ secrets.DB_NAME }}' + DB_PORT: '${{ secrets.DB_PORT }}' + DB_CA_CERT: '${{ secrets.DB_CA_CERT }}' + DB_SSL_MODE: '${{ secrets.DB_SSL_MODE }}' + DB_POOL_SIZE: '${{ secrets.DB_POOL_SIZE }}' + DB_POOL_SIZE_KNEX: '${{ secrets.DB_POOL_SIZE_KNEX }}' + REDIS_ENABLED: '${{ secrets.REDIS_ENABLED }}' + REDIS_URL: '${{ env.REDIS_URL_PUBLIC }}' + CLOUD_PROVIDER: 'DO' + SENTRY_DSN: '${{ secrets.SENTRY_DSN }}' + SENTRY_TRACES_SAMPLE_RATE: '${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}' + SENTRY_PROFILE_SAMPLE_RATE: '${{ secrets.SENTRY_PROFILE_SAMPLE_RATE }}' + SENTRY_HTTP_TRACING_ENABLED: '${{ secrets.SENTRY_HTTP_TRACING_ENABLED }}' + SENTRY_POSTGRES_TRACKING_ENABLED: '${{ secrets.SENTRY_POSTGRES_TRACKING_ENABLED }}' + SENTRY_PROFILING_ENABLED: '${{ secrets.SENTRY_PROFILING_ENABLED }}' + AWS_ACCESS_KEY_ID: '${{ secrets.AWS_ACCESS_KEY_ID }}' + AWS_SECRET_ACCESS_KEY: '${{ secrets.AWS_SECRET_ACCESS_KEY }}' + AWS_REGION: '${{ secrets.AWS_REGION }}' + AWS_S3_BUCKET: '${{ secrets.AWS_S3_BUCKET }}' + WASABI_ACCESS_KEY_ID: '${{ secrets.WASABI_ACCESS_KEY_ID }}' + WASABI_SECRET_ACCESS_KEY: '${{ secrets.WASABI_SECRET_ACCESS_KEY }}' + WASABI_REGION: '${{ secrets.WASABI_REGION }}' + WASABI_SERVICE_URL: '${{ secrets.WASABI_SERVICE_URL }}' + WASABI_S3_BUCKET: '${{ secrets.WASABI_S3_BUCKET }}' + EXPRESS_SESSION_SECRET: '${{ secrets.EXPRESS_SESSION_SECRET }}' + JWT_SECRET: '${{ secrets.JWT_SECRET }}' + JWT_REFRESH_TOKEN_SECRET: '${{ secrets.JWT_REFRESH_TOKEN_SECRET }}' + JWT_REFRESH_TOKEN_EXPIRATION_TIME: '${{ secrets.JWT_REFRESH_TOKEN_EXPIRATION_TIME }}' + CLOUDINARY_API_KEY: '${{ secrets.CLOUDINARY_API_KEY }}' + CLOUDINARY_API_SECRET: '${{ secrets.CLOUDINARY_API_SECRET }}' + CLOUDINARY_CLOUD_NAME: '${{ secrets.CLOUDINARY_CLOUD_NAME }}' + MAIL_FROM_ADDRESS: '${{ secrets.MAIL_FROM_ADDRESS }}' + MAIL_HOST: '${{ secrets.MAIL_HOST }}' + MAIL_PORT: '${{ secrets.MAIL_PORT }}' + MAIL_USERNAME: '${{ secrets.MAIL_USERNAME }}' + MAIL_PASSWORD: '${{ secrets.MAIL_PASSWORD }}' + ALLOW_SUPER_ADMIN_ROLE: '${{ secrets.ALLOW_SUPER_ADMIN_ROLE }}' + GOOGLE_CLIENT_ID: '${{ secrets.GOOGLE_CLIENT_ID }}' + GOOGLE_CLIENT_SECRET: '${{ secrets.GOOGLE_CLIENT_SECRET }}' + GOOGLE_CALLBACK_URL: '${{ secrets.GOOGLE_CALLBACK_URL }}' + FACEBOOK_CLIENT_ID: '${{ secrets.FACEBOOK_CLIENT_ID }}' + FACEBOOK_CLIENT_SECRET: '${{ secrets.FACEBOOK_CLIENT_SECRET }}' + FACEBOOK_GRAPH_VERSION: '${{ secrets.FACEBOOK_GRAPH_VERSION }}' + FACEBOOK_CALLBACK_URL: '${{ secrets.FACEBOOK_CALLBACK_URL }}' + INTEGRATED_USER_DEFAULT_PASS: '${{ secrets.INTEGRATED_USER_DEFAULT_PASS }}' + UPWORK_REDIRECT_URL: '${{ secrets.UPWORK_REDIRECT_URL }}' + FILE_PROVIDER: '${{ secrets.FILE_PROVIDER }}' + GAUZY_AI_GRAPHQL_ENDPOINT: '${{ secrets.GAUZY_AI_GRAPHQL_ENDPOINT }}' + GAUZY_AI_REST_ENDPOINT: '${{ secrets.GAUZY_AI_REST_ENDPOINT }}' + UNLEASH_APP_NAME: '${{ secrets.UNLEASH_APP_NAME }}' + UNLEASH_API_URL: '${{ secrets.UNLEASH_API_URL }}' + UNLEASH_INSTANCE_ID: '${{ secrets.UNLEASH_INSTANCE_ID }}' + UNLEASH_REFRESH_INTERVAL: '${{ secrets.UNLEASH_REFRESH_INTERVAL }}' + UNLEASH_METRICS_INTERVAL: '${{ secrets.UNLEASH_METRICS_INTERVAL }}' + UNLEASH_API_KEY: '${{ secrets.UNLEASH_API_KEY }}' + PM2_MACHINE_NAME: '${{ secrets.PM2_MACHINE_NAME }}' + PM2_SECRET_KEY: '${{ secrets.PM2_SECRET_KEY }}' + PM2_PUBLIC_KEY: '${{ secrets.PM2_PUBLIC_KEY }}' + JITSU_SERVER_URL: '${{ secrets.JITSU_SERVER_URL }}' + JITSU_SERVER_WRITE_KEY: '${{ secrets.JITSU_SERVER_WRITE_KEY }}' + OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}' + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' + OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' + GAUZY_GITHUB_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_CLIENT_ID }}' + GAUZY_GITHUB_CLIENT_SECRET: '${{ secrets.GAUZY_GITHUB_CLIENT_SECRET }}' + GAUZY_GITHUB_APP_PRIVATE_KEY: '${{ secrets.GAUZY_GITHUB_APP_PRIVATE_KEY }}' + GAUZY_GITHUB_WEBHOOK_URL: '${{ secrets.GAUZY_GITHUB_WEBHOOK_URL }}' + GAUZY_GITHUB_WEBHOOK_SECRET: '${{ secrets.GAUZY_GITHUB_WEBHOOK_SECRET }}' + GAUZY_GITHUB_APP_NAME: '${{ secrets.GAUZY_GITHUB_APP_NAME }}' + GAUZY_GITHUB_REDIRECT_URL: '${{ secrets.GAUZY_GITHUB_REDIRECT_URL }}' + GAUZY_GITHUB_POST_INSTALL_URL: '${{ secrets.GAUZY_GITHUB_POST_INSTALL_URL }}' + GAUZY_GITHUB_APP_ID: '${{ secrets.GAUZY_GITHUB_APP_ID }}' + GAUZY_GITHUB_OAUTH_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_OAUTH_CLIENT_ID }}' + GAUZY_GITHUB_OAUTH_CLIENT_SECRET: '${{ secrets.GAUZY_GITHUB_OAUTH_CLIENT_SECRET }}' + GAUZY_GITHUB_OAUTH_CALLBACK_URL: '${{ secrets.GAUZY_GITHUB_OAUTH_CALLBACK_URL }}' + JITSU_BROWSER_URL: '${{ secrets.JITSU_BROWSER_URL }}' + JITSU_BROWSER_WRITE_KEY: '${{ secrets.JITSU_BROWSER_WRITE_KEY }}' + MAGIC_CODE_EXPIRATION_TIME: '${{ secrets.MAGIC_CODE_EXPIRATION_TIME }}' + APP_NAME: '${{ secrets.APP_NAME }}' + APP_LOGO: '${{ secrets.APP_LOGO }}' + APP_SIGNATURE: '${{ secrets.APP_SIGNATURE }}' + APP_LINK: '${{ secrets.APP_LINK }}' + APP_EMAIL_CONFIRMATION_URL: '${{ secrets.APP_EMAIL_CONFIRMATION_URL }}' + APP_MAGIC_SIGN_URL: '${{ secrets.APP_MAGIC_SIGN_URL }}' + COMPANY_LINK: '${{ secrets.COMPANY_LINK }}' + COMPANY_NAME: '${{ secrets.COMPANY_NAME }}' + + - name: Check if App Exists + id: check-app + run: | + echo "ENV_NAME is set to '${ENV_NAME}'" + APP_NAME="ever-gauzy-${ENV_NAME}" + echo "Looking for app with name: $APP_NAME" + doctl apps list --no-header + APP_ID=$(doctl apps list --no-header | awk -v appName="$APP_NAME" '$2 == appName {print $1}') + if [ -z "$APP_ID" ]; then + echo "App does not exist, setting CREATE_APP to true" + echo "::set-output name=create_app::true" + else + echo "App exists with ID $APP_ID, setting APP_ID" + echo "::set-output name=app_id::$APP_ID" + echo "::set-output name=create_app::false" + fi + env: + DIGITALOCEAN_ACCESS_TOKEN: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + ENV_NAME: 'prod' + + - name: Create App + if: steps.check-app.outputs.create_app == 'true' + run: doctl apps create --spec .do/app.yaml + + - name: Update App + if: steps.check-app.outputs.create_app == 'false' + run: doctl apps update ${{ steps.check-app.outputs.app_id }} --spec .do/app.yaml diff --git a/.github/workflows/deploy-do-app-platform-stage.yml b/.github/workflows/deploy-do-app-platform-stage.yml new file mode 100644 index 00000000000..e7c8b16e01e --- /dev/null +++ b/.github/workflows/deploy-do-app-platform-stage.yml @@ -0,0 +1,164 @@ +name: Deploy to DigitalOcean App Platform Stage + +on: + workflow_run: + workflows: ['Build and Publish Docker Images Stage'] + branches: [stage] + types: + - completed + +jobs: + deploy: + runs-on: buildjet-4vcpu-ubuntu-2204 + + environment: stage + + steps: + - name: checkout out code + uses: actions/checkout@v4 + + - name: Install doctl + uses: digitalocean/action-doctl@v2 + with: + token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + + - name: Modify DB_HOST and REDIS_URL + run: | + echo "DB_HOST_PUBLIC=$(echo '${{ secrets.DB_HOST }}' | sed 's/private-//')" >> $GITHUB_ENV + echo "REDIS_URL_PUBLIC=$(echo '${{ secrets.REDIS_URL }}' | sed 's/private-//')" >> $GITHUB_ENV + + - name: Inject secrets into .do/app.yaml + run: | + envsubst < $GITHUB_WORKSPACE/.do/app.yaml > temp.yaml && mv temp.yaml $GITHUB_WORKSPACE/.do/app.yaml + env: + ENV_NAME: 'stage' + DOCR_REPOSITORY: 'gauzy-api-stage' + APP_DOMAIN: 'apistageda.gauzy.co' + INSTANCE_COUNT: '2' + INSTANCE_SIZE: 'professional-xs' + API_HOST: '0.0.0.0' + DEMO: 'false' + NODE_ENV: 'production' + ADMIN_PASSWORD_RESET: 'true' + API_BASE_URL: 'https://apistageda.gauzy.co' + CLIENT_BASE_URL: 'https://stage.gauzy.co' + DB_TYPE: '${{ secrets.DB_TYPE }}' + DB_URI: '${{ secrets.DB_URI }}' + DB_HOST: '${{ env.DB_HOST_PUBLIC }}' + DB_USER: '${{ secrets.DB_USER }}' + DB_PASS: '${{ secrets.DB_PASS }}' + DB_NAME: '${{ secrets.DB_NAME }}' + DB_PORT: '${{ secrets.DB_PORT }}' + DB_CA_CERT: '${{ secrets.DB_CA_CERT }}' + DB_SSL_MODE: '${{ secrets.DB_SSL_MODE }}' + DB_POOL_SIZE: '${{ secrets.DB_POOL_SIZE }}' + DB_POOL_SIZE_KNEX: '${{ secrets.DB_POOL_SIZE_KNEX }}' + REDIS_ENABLED: '${{ secrets.REDIS_ENABLED }}' + REDIS_URL: '${{ env.REDIS_URL_PUBLIC }}' + CLOUD_PROVIDER: 'DO' + SENTRY_DSN: '${{ secrets.SENTRY_DSN }}' + SENTRY_TRACES_SAMPLE_RATE: '${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}' + SENTRY_PROFILE_SAMPLE_RATE: '${{ secrets.SENTRY_PROFILE_SAMPLE_RATE }}' + SENTRY_HTTP_TRACING_ENABLED: '${{ secrets.SENTRY_HTTP_TRACING_ENABLED }}' + SENTRY_POSTGRES_TRACKING_ENABLED: '${{ secrets.SENTRY_POSTGRES_TRACKING_ENABLED }}' + SENTRY_PROFILING_ENABLED: '${{ secrets.SENTRY_PROFILING_ENABLED }}' + AWS_ACCESS_KEY_ID: '${{ secrets.AWS_ACCESS_KEY_ID }}' + AWS_SECRET_ACCESS_KEY: '${{ secrets.AWS_SECRET_ACCESS_KEY }}' + AWS_REGION: '${{ secrets.AWS_REGION }}' + AWS_S3_BUCKET: '${{ secrets.AWS_S3_BUCKET }}' + WASABI_ACCESS_KEY_ID: '${{ secrets.WASABI_ACCESS_KEY_ID }}' + WASABI_SECRET_ACCESS_KEY: '${{ secrets.WASABI_SECRET_ACCESS_KEY }}' + WASABI_REGION: '${{ secrets.WASABI_REGION }}' + WASABI_SERVICE_URL: '${{ secrets.WASABI_SERVICE_URL }}' + WASABI_S3_BUCKET: '${{ secrets.WASABI_S3_BUCKET }}' + EXPRESS_SESSION_SECRET: '${{ secrets.EXPRESS_SESSION_SECRET }}' + JWT_SECRET: '${{ secrets.JWT_SECRET }}' + JWT_REFRESH_TOKEN_SECRET: '${{ secrets.JWT_REFRESH_TOKEN_SECRET }}' + JWT_REFRESH_TOKEN_EXPIRATION_TIME: '${{ secrets.JWT_REFRESH_TOKEN_EXPIRATION_TIME }}' + CLOUDINARY_API_KEY: '${{ secrets.CLOUDINARY_API_KEY }}' + CLOUDINARY_API_SECRET: '${{ secrets.CLOUDINARY_API_SECRET }}' + CLOUDINARY_CLOUD_NAME: '${{ secrets.CLOUDINARY_CLOUD_NAME }}' + MAIL_FROM_ADDRESS: '${{ secrets.MAIL_FROM_ADDRESS }}' + MAIL_HOST: '${{ secrets.MAIL_HOST }}' + MAIL_PORT: '${{ secrets.MAIL_PORT }}' + MAIL_USERNAME: '${{ secrets.MAIL_USERNAME }}' + MAIL_PASSWORD: '${{ secrets.MAIL_PASSWORD }}' + ALLOW_SUPER_ADMIN_ROLE: '${{ secrets.ALLOW_SUPER_ADMIN_ROLE }}' + GOOGLE_CLIENT_ID: '${{ secrets.GOOGLE_CLIENT_ID }}' + GOOGLE_CLIENT_SECRET: '${{ secrets.GOOGLE_CLIENT_SECRET }}' + GOOGLE_CALLBACK_URL: '${{ secrets.GOOGLE_CALLBACK_URL }}' + FACEBOOK_CLIENT_ID: '${{ secrets.FACEBOOK_CLIENT_ID }}' + FACEBOOK_CLIENT_SECRET: '${{ secrets.FACEBOOK_CLIENT_SECRET }}' + FACEBOOK_GRAPH_VERSION: '${{ secrets.FACEBOOK_GRAPH_VERSION }}' + FACEBOOK_CALLBACK_URL: '${{ secrets.FACEBOOK_CALLBACK_URL }}' + INTEGRATED_USER_DEFAULT_PASS: '${{ secrets.INTEGRATED_USER_DEFAULT_PASS }}' + UPWORK_REDIRECT_URL: '${{ secrets.UPWORK_REDIRECT_URL }}' + FILE_PROVIDER: '${{ secrets.FILE_PROVIDER }}' + GAUZY_AI_GRAPHQL_ENDPOINT: '${{ secrets.GAUZY_AI_GRAPHQL_ENDPOINT }}' + GAUZY_AI_REST_ENDPOINT: '${{ secrets.GAUZY_AI_REST_ENDPOINT }}' + UNLEASH_APP_NAME: '${{ secrets.UNLEASH_APP_NAME }}' + UNLEASH_API_URL: '${{ secrets.UNLEASH_API_URL }}' + UNLEASH_INSTANCE_ID: '${{ secrets.UNLEASH_INSTANCE_ID }}' + UNLEASH_REFRESH_INTERVAL: '${{ secrets.UNLEASH_REFRESH_INTERVAL }}' + UNLEASH_METRICS_INTERVAL: '${{ secrets.UNLEASH_METRICS_INTERVAL }}' + UNLEASH_API_KEY: '${{ secrets.UNLEASH_API_KEY }}' + PM2_MACHINE_NAME: '${{ secrets.PM2_MACHINE_NAME }}' + PM2_SECRET_KEY: '${{ secrets.PM2_SECRET_KEY }}' + PM2_PUBLIC_KEY: '${{ secrets.PM2_PUBLIC_KEY }}' + JITSU_SERVER_URL: '${{ secrets.JITSU_SERVER_URL }}' + JITSU_SERVER_WRITE_KEY: '${{ secrets.JITSU_SERVER_WRITE_KEY }}' + OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}' + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' + OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' + GAUZY_GITHUB_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_CLIENT_ID }}' + GAUZY_GITHUB_CLIENT_SECRET: '${{ secrets.GAUZY_GITHUB_CLIENT_SECRET }}' + GAUZY_GITHUB_APP_PRIVATE_KEY: '${{ secrets.GAUZY_GITHUB_APP_PRIVATE_KEY }}' + GAUZY_GITHUB_WEBHOOK_URL: '${{ secrets.GAUZY_GITHUB_WEBHOOK_URL }}' + GAUZY_GITHUB_WEBHOOK_SECRET: '${{ secrets.GAUZY_GITHUB_WEBHOOK_SECRET }}' + GAUZY_GITHUB_APP_NAME: '${{ secrets.GAUZY_GITHUB_APP_NAME }}' + GAUZY_GITHUB_REDIRECT_URL: '${{ secrets.GAUZY_GITHUB_REDIRECT_URL }}' + GAUZY_GITHUB_POST_INSTALL_URL: '${{ secrets.GAUZY_GITHUB_POST_INSTALL_URL }}' + GAUZY_GITHUB_APP_ID: '${{ secrets.GAUZY_GITHUB_APP_ID }}' + GAUZY_GITHUB_OAUTH_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_OAUTH_CLIENT_ID }}' + GAUZY_GITHUB_OAUTH_CLIENT_SECRET: '${{ secrets.GAUZY_GITHUB_OAUTH_CLIENT_SECRET }}' + GAUZY_GITHUB_OAUTH_CALLBACK_URL: '${{ secrets.GAUZY_GITHUB_OAUTH_CALLBACK_URL }}' + JITSU_BROWSER_URL: '${{ secrets.JITSU_BROWSER_URL }}' + JITSU_BROWSER_WRITE_KEY: '${{ secrets.JITSU_BROWSER_WRITE_KEY }}' + MAGIC_CODE_EXPIRATION_TIME: '${{ secrets.MAGIC_CODE_EXPIRATION_TIME }}' + APP_NAME: '${{ secrets.APP_NAME }}' + APP_LOGO: '${{ secrets.APP_LOGO }}' + APP_SIGNATURE: '${{ secrets.APP_SIGNATURE }}' + APP_LINK: '${{ secrets.APP_LINK }}' + APP_EMAIL_CONFIRMATION_URL: '${{ secrets.APP_EMAIL_CONFIRMATION_URL }}' + APP_MAGIC_SIGN_URL: '${{ secrets.APP_MAGIC_SIGN_URL }}' + COMPANY_LINK: '${{ secrets.COMPANY_LINK }}' + COMPANY_NAME: '${{ secrets.COMPANY_NAME }}' + + - name: Check if App Exists + id: check-app + run: | + echo "ENV_NAME is set to '${ENV_NAME}'" + APP_NAME="ever-gauzy-${ENV_NAME}" + echo "Looking for app with name: $APP_NAME" + doctl apps list --no-header + APP_ID=$(doctl apps list --no-header | awk -v appName="$APP_NAME" '$2 == appName {print $1}') + if [ -z "$APP_ID" ]; then + echo "App does not exist, setting CREATE_APP to true" + echo "::set-output name=create_app::true" + else + echo "App exists with ID $APP_ID, setting APP_ID" + echo "::set-output name=app_id::$APP_ID" + echo "::set-output name=create_app::false" + fi + env: + DIGITALOCEAN_ACCESS_TOKEN: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} + ENV_NAME: 'stage' + + - name: Create App + if: steps.check-app.outputs.create_app == 'true' + run: doctl apps create --spec .do/app.yaml + + - name: Update App + if: steps.check-app.outputs.create_app == 'false' + run: doctl apps update ${{ steps.check-app.outputs.app_id }} --spec .do/app.yaml diff --git a/.github/workflows/deploy-do-demo.yml b/.github/workflows/deploy-do-demo.yml index bddd073c9be..959c03f0937 100644 --- a/.github/workflows/deploy-do-demo.yml +++ b/.github/workflows/deploy-do-demo.yml @@ -42,6 +42,7 @@ jobs: SENTRY_POSTGRES_TRACKING_ENABLED: '${{ secrets.SENTRY_POSTGRES_TRACKING_ENABLED }}' SENTRY_PROFILING_ENABLED: '${{ secrets.SENTRY_PROFILING_ENABLED }}' OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}' OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' diff --git a/.github/workflows/deploy-do-droplet-demo.yml b/.github/workflows/deploy-do-droplet-demo.yml new file mode 100644 index 00000000000..752ee258331 --- /dev/null +++ b/.github/workflows/deploy-do-droplet-demo.yml @@ -0,0 +1,181 @@ +name: Deploy to DigitalOcean Droplet Demo + +on: + workflow_run: + workflows: ['Deploy to DigitalOcean Droplet Demo Pre'] + branches: [develop] + types: + - completed + +jobs: + deploy: + runs-on: buildjet-4vcpu-ubuntu-2204 + + environment: demo + + steps: + - name: checkout out code + uses: actions/checkout@v4 + + - name: Modify API_BASE_URL + run: | + echo "INGRESS_CERT_TYPE=${{ env.INGRESS_CERT_TYPE }}" >> $GITHUB_ENV + + if [ "${{ env.INGRESS_CERT_TYPE }}" = "cloudflare" ]; then + echo "API_BASE_URL=https://apidemodt.gauzy.co" >> $GITHUB_ENV + elif [ "${{ env.INGRESS_CERT_TYPE }}" = "letsencrypt" ]; then + echo "API_BASE_URL=https://apidemodts.gauzy.co" >> $GITHUB_ENV + else + echo "UNKNOWN INGRESS_CERT_TYPE" + fi + env: + INGRESS_CERT_TYPE: 'letsencrypt' + + - name: Inject secrets into .env-template.compose + run: | + if [ "${{ env.INGRESS_CERT_TYPE }}" = "cloudflare" ]; then + envsubst < $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/demo/docker-compose.api.demo.template.yml > temp.yaml && mv temp.yaml $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/demo/docker-compose.api.demo.yml + touch $GITHUB_WORKSPACE/.deploy/ssh/with-letsencrypt/demo/docker-compose.api.demo.yml + elif [ "${{ env.INGRESS_CERT_TYPE }}" = "letsencrypt" ]; then + envsubst < $GITHUB_WORKSPACE/.deploy/ssh/with-letsencrypt/demo/docker-compose.api.demo.template.yml > temp.yaml && mv temp.yaml $GITHUB_WORKSPACE/.deploy/ssh/with-letsencrypt/demo/docker-compose.api.demo.yml + touch $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/demo/docker-compose.api.demo.yml + else + echo "UNKNOWN INGRESS_CERT_TYPE" + fi + env: + ENV_NAME: 'demo' + DEMO: 'true' + NODE_ENV: 'development' + ADMIN_PASSWORD_RESET: 'true' + API_HOST: $API_HOST + API_BASE_URL: '${{ env.API_BASE_URL }}' + CLIENT_BASE_URL: 'https://demo.gauzy.co' + DB_TYPE: '${{ secrets.DB_TYPE }}' + DB_URI: '${{ secrets.DB_URI }}' + DB_HOST: '${{ secrets.DB_HOST }}' + DB_USER: '${{ secrets.DB_USER }}' + DB_PASS: '${{ secrets.DB_PASS }}' + DB_NAME: '${{ secrets.DB_NAME }}' + DB_PORT: '${{ secrets.DB_PORT }}' + DB_CA_CERT: '${{ secrets.DB_CA_CERT }}' + DB_SSL_MODE: '${{ secrets.DB_SSL_MODE }}' + DB_POOL_SIZE: '${{ secrets.DB_POOL_SIZE }}' + DB_POOL_SIZE_KNEX: '${{ secrets.DB_POOL_SIZE_KNEX }}' + REDIS_ENABLED: '${{ secrets.REDIS_ENABLED }}' + REDIS_URL: '${{ secrets.REDIS_URL }}' + CLOUD_PROVIDER: 'DO' + SENTRY_DSN: '${{ secrets.SENTRY_DSN }}' + SENTRY_TRACES_SAMPLE_RATE: '${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}' + SENTRY_PROFILE_SAMPLE_RATE: '${{ secrets.SENTRY_PROFILE_SAMPLE_RATE }}' + SENTRY_HTTP_TRACING_ENABLED: '${{ secrets.SENTRY_HTTP_TRACING_ENABLED }}' + SENTRY_POSTGRES_TRACKING_ENABLED: '${{ secrets.SENTRY_POSTGRES_TRACKING_ENABLED }}' + SENTRY_PROFILING_ENABLED: '${{ secrets.SENTRY_PROFILING_ENABLED }}' + AWS_ACCESS_KEY_ID: '${{ secrets.AWS_ACCESS_KEY_ID }}' + AWS_SECRET_ACCESS_KEY: '${{ secrets.AWS_SECRET_ACCESS_KEY }}' + AWS_REGION: '${{ secrets.AWS_REGION }}' + AWS_S3_BUCKET: '${{ secrets.AWS_S3_BUCKET }}' + WASABI_ACCESS_KEY_ID: '${{ secrets.WASABI_ACCESS_KEY_ID }}' + WASABI_SECRET_ACCESS_KEY: '${{ secrets.WASABI_SECRET_ACCESS_KEY }}' + WASABI_REGION: '${{ secrets.WASABI_REGION }}' + WASABI_SERVICE_URL: '${{ secrets.WASABI_SERVICE_URL }}' + WASABI_S3_BUCKET: '${{ secrets.WASABI_S3_BUCKET }}' + EXPRESS_SESSION_SECRET: '${{ secrets.EXPRESS_SESSION_SECRET }}' + JWT_SECRET: '${{ secrets.JWT_SECRET }}' + JWT_REFRESH_TOKEN_SECRET: '${{ secrets.JWT_REFRESH_TOKEN_SECRET }}' + JWT_REFRESH_TOKEN_EXPIRATION_TIME: '${{ secrets.JWT_REFRESH_TOKEN_EXPIRATION_TIME }}' + CLOUDINARY_API_KEY: '${{ secrets.CLOUDINARY_API_KEY }}' + CLOUDINARY_API_SECRET: '${{ secrets.CLOUDINARY_API_SECRET }}' + CLOUDINARY_CLOUD_NAME: '${{ secrets.CLOUDINARY_CLOUD_NAME }}' + MAIL_FROM_ADDRESS: '${{ secrets.MAIL_FROM_ADDRESS }}' + MAIL_HOST: '${{ secrets.MAIL_HOST }}' + MAIL_PORT: '${{ secrets.MAIL_PORT }}' + MAIL_USERNAME: '${{ secrets.MAIL_USERNAME }}' + MAIL_PASSWORD: '${{ secrets.MAIL_PASSWORD }}' + ALLOW_SUPER_ADMIN_ROLE: '${{ secrets.ALLOW_SUPER_ADMIN_ROLE }}' + GOOGLE_CLIENT_ID: '${{ secrets.GOOGLE_CLIENT_ID }}' + GOOGLE_CLIENT_SECRET: '${{ secrets.GOOGLE_CLIENT_SECRET }}' + GOOGLE_CALLBACK_URL: '${{ secrets.GOOGLE_CALLBACK_URL }}' + FACEBOOK_CLIENT_ID: '${{ secrets.FACEBOOK_CLIENT_ID }}' + FACEBOOK_CLIENT_SECRET: '${{ secrets.FACEBOOK_CLIENT_SECRET }}' + FACEBOOK_GRAPH_VERSION: '${{ secrets.FACEBOOK_GRAPH_VERSION }}' + FACEBOOK_CALLBACK_URL: '${{ secrets.FACEBOOK_CALLBACK_URL }}' + INTEGRATED_USER_DEFAULT_PASS: '${{ secrets.INTEGRATED_USER_DEFAULT_PASS }}' + UPWORK_REDIRECT_URL: '${{ secrets.UPWORK_REDIRECT_URL }}' + FILE_PROVIDER: '${{ secrets.FILE_PROVIDER }}' + GAUZY_AI_GRAPHQL_ENDPOINT: '${{ secrets.GAUZY_AI_GRAPHQL_ENDPOINT }}' + GAUZY_AI_REST_ENDPOINT: '${{ secrets.GAUZY_AI_REST_ENDPOINT }}' + UNLEASH_APP_NAME: '${{ secrets.UNLEASH_APP_NAME }}' + UNLEASH_API_URL: '${{ secrets.UNLEASH_API_URL }}' + UNLEASH_INSTANCE_ID: '${{ secrets.UNLEASH_INSTANCE_ID }}' + UNLEASH_REFRESH_INTERVAL: '${{ secrets.UNLEASH_REFRESH_INTERVAL }}' + UNLEASH_METRICS_INTERVAL: '${{ secrets.UNLEASH_METRICS_INTERVAL }}' + UNLEASH_API_KEY: '${{ secrets.UNLEASH_API_KEY }}' + PM2_MACHINE_NAME: '${{ secrets.PM2_MACHINE_NAME }}' + PM2_SECRET_KEY: '${{ secrets.PM2_SECRET_KEY }}' + PM2_PUBLIC_KEY: '${{ secrets.PM2_PUBLIC_KEY }}' + JITSU_SERVER_URL: '${{ secrets.JITSU_SERVER_URL }}' + JITSU_SERVER_WRITE_KEY: '${{ secrets.JITSU_SERVER_WRITE_KEY }}' + OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}' + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' + OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' + GAUZY_GITHUB_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_CLIENT_ID }}' + GAUZY_GITHUB_CLIENT_SECRET: '${{ secrets.GAUZY_GITHUB_CLIENT_SECRET }}' + GAUZY_GITHUB_APP_PRIVATE_KEY: '${{ secrets.GAUZY_GITHUB_APP_PRIVATE_KEY }}' + GAUZY_GITHUB_WEBHOOK_URL: '${{ secrets.GAUZY_GITHUB_WEBHOOK_URL }}' + GAUZY_GITHUB_WEBHOOK_SECRET: '${{ secrets.GAUZY_GITHUB_WEBHOOK_SECRET }}' + GAUZY_GITHUB_APP_NAME: '${{ secrets.GAUZY_GITHUB_APP_NAME }}' + GAUZY_GITHUB_REDIRECT_URL: '${{ secrets.GAUZY_GITHUB_REDIRECT_URL }}' + GAUZY_GITHUB_POST_INSTALL_URL: '${{ secrets.GAUZY_GITHUB_POST_INSTALL_URL }}' + GAUZY_GITHUB_APP_ID: '${{ secrets.GAUZY_GITHUB_APP_ID }}' + GAUZY_GITHUB_OAUTH_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_OAUTH_CLIENT_ID }}' + GAUZY_GITHUB_OAUTH_CLIENT_SECRET: '${{ secrets.GAUZY_GITHUB_OAUTH_CLIENT_SECRET }}' + GAUZY_GITHUB_OAUTH_CALLBACK_URL: '${{ secrets.GAUZY_GITHUB_OAUTH_CALLBACK_URL }}' + JITSU_BROWSER_URL: '${{ secrets.JITSU_BROWSER_URL }}' + JITSU_BROWSER_WRITE_KEY: '${{ secrets.JITSU_BROWSER_WRITE_KEY }}' + MAGIC_CODE_EXPIRATION_TIME: '${{ secrets.MAGIC_CODE_EXPIRATION_TIME }}' + APP_NAME: '${{ secrets.APP_NAME }}' + APP_LOGO: '${{ secrets.APP_LOGO }}' + APP_SIGNATURE: '${{ secrets.APP_SIGNATURE }}' + APP_LINK: '${{ secrets.APP_LINK }}' + APP_EMAIL_CONFIRMATION_URL: '${{ secrets.APP_EMAIL_CONFIRMATION_URL }}' + APP_MAGIC_SIGN_URL: '${{ secrets.APP_MAGIC_SIGN_URL }}' + COMPANY_LINK: '${{ secrets.COMPANY_LINK }}' + COMPANY_NAME: '${{ secrets.COMPANY_NAME }}' + + - name: Copy file via scp - with-cloudflare + if: ${{ env.INGRESS_CERT_TYPE == 'cloudflare' }} + uses: appleboy/scp-action@master + with: + host: ${{secrets.DO_DROPLET_DEMO_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + source: '.deploy/ssh/with-cloudflare/demo/docker-compose.api.demo.yml' + target: '.' + - name: Copy file via scp - with-letsencrypt + if: ${{ env.INGRESS_CERT_TYPE == 'letsencrypt' }} + uses: appleboy/scp-action@master + with: + host: ${{secrets.DO_DROPLET_DEMO_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + source: '.deploy/ssh/with-letsencrypt/demo/docker-compose.api.demo.yml' + target: '.' + - name: Deploy to DigitalOcean Droplet + uses: appleboy/ssh-action@master + with: + host: ${{secrets.DO_DROPLET_DEMO_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + envs: INGRESS_CERT_TYPE + script: | + if [ "${{ env.INGRESS_CERT_TYPE }}" = "cloudflare" ]; then + docker-compose -f .deploy/ssh/with-letsencrypt/demo/docker-compose.api.demo.yml down + docker-compose -f .deploy/ssh/with-cloudflare/demo/docker-compose.api.demo.yml up -d + elif [ "${{ env.INGRESS_CERT_TYPE }}" = "letsencrypt" ]; then + docker-compose -f .deploy/ssh/with-cloudflare/demo/docker-compose.api.demo.yml down + docker-compose -f .deploy/ssh/with-letsencrypt/demo/docker-compose.api.demo.yml up -d + else + echo "Unknown INGRESS_CERT_TYPE: $INGRESS_CERT_TYPE" + exit 1 + fi diff --git a/.github/workflows/deploy-do-droplet-pre-demo.yml b/.github/workflows/deploy-do-droplet-pre-demo.yml new file mode 100644 index 00000000000..a27466a0880 --- /dev/null +++ b/.github/workflows/deploy-do-droplet-pre-demo.yml @@ -0,0 +1,95 @@ +name: Deploy to DigitalOcean Droplet Demo Pre + +on: + push: + branches: + - develop + +jobs: + deploy: + runs-on: buildjet-4vcpu-ubuntu-2204 + + environment: demo + + steps: + - name: checkout out code + uses: actions/checkout@v4 + + - name: Globalise Ingress certificate type env + run: | + echo "INGRESS_CERT_TYPE=${{ env.INGRESS_CERT_TYPE }}" >> $GITHUB_ENV + env: + INGRESS_CERT_TYPE: 'letsencrypt' + + - name: Generate TLS Secrets for DO Droplet + run: | + rm -f $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/demo/ingress.api.crt $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/demo/ingress.api.key + echo ${{ secrets.INGRESS_API_CERT }} | base64 --decode > $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/demo/ingress.api.crt + echo ${{ secrets.INGRESS_API_CERT_KEY }} | base64 --decode > $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/demo/ingress.api.key + + - name: Copy file via scp - cloudflare + if: ${{ env.INGRESS_CERT_TYPE == 'cloudflare' }} + uses: appleboy/scp-action@master + with: + host: ${{secrets.DO_DROPLET_DEMO_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + source: '.deploy/ssh/with-cloudflare/demo/docker-compose.api.demo.cloudflare.pre.yml,.deploy/ssh/with-cloudflare/demo/nginx.demo.pre.cloudflare.conf,.deploy/ssh/with-cloudflare/demo/ingress.api.crt,.deploy/ssh/with-cloudflare/demo/ingress.api.key' + target: '.' + - name: Copy file via scp - letsencrypt + if: ${{ env.INGRESS_CERT_TYPE == 'letsencrypt' }} + uses: appleboy/scp-action@master + with: + host: ${{secrets.DO_DROPLET_DEMO_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + source: '.deploy/ssh/with-letsencrypt/demo/docker-compose.api.demo.letsencrypt.pre.yml,.deploy/ssh/with-letsencrypt/demo/user_conf.d,.deploy/ssh/with-letsencrypt/demo/nginx-certbot.env' + target: '.' + + - name: Install Docker + uses: appleboy/ssh-action@master + with: + host: ${{secrets.DO_DROPLET_DEMO_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + script: | + if ! command -v docker &> /dev/null; then + echo "Docker not installed. Installing..." + sudo apt-get update + sudo apt-get install -y docker.io + sudo systemctl start docker + sudo systemctl enable docker + else + echo "Docker is already installed." + fi + - name: Install Docker Compose + uses: appleboy/ssh-action@master + with: + host: ${{secrets.DO_DROPLET_DEMO_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + script: | + if ! command -v docker-compose &> /dev/null; then + echo "Docker Compose not installed. Installing..." + sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose + sudo chmod +x /usr/local/bin/docker-compose + else + echo "Docker Compose is already installed." + fi + - name: Deploy to DigitalOcean Droplet + uses: appleboy/ssh-action@master + with: + host: ${{secrets.DO_DROPLET_DEMO_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + script: | + if [ "${{ env.INGRESS_CERT_TYPE }}" = "cloudflare" ]; then + docker-compose -f .deploy/ssh/with-letsencrypt/demo/docker-compose.api.demo.letsencrypt.pre.yml down + docker-compose -f .deploy/ssh/with-cloudflare/demo/docker-compose.api.demo.cloudflare.pre.yml up -d + elif [ "${{ env.INGRESS_CERT_TYPE }}" = "letsencrypt" ]; then + docker-compose -f .deploy/ssh/with-cloudflare/demo/docker-compose.api.demo.cloudflare.pre.yml down + docker-compose -f .deploy/ssh/with-letsencrypt/demo/docker-compose.api.demo.letsencrypt.pre.yml up -d + else + echo "Unknown INGRESS_CERT_TYPE: $INGRESS_CERT_TYPE" + exit 1 + fi diff --git a/.github/workflows/deploy-do-droplet-pre-prod.yml b/.github/workflows/deploy-do-droplet-pre-prod.yml new file mode 100644 index 00000000000..953bf69f3c1 --- /dev/null +++ b/.github/workflows/deploy-do-droplet-pre-prod.yml @@ -0,0 +1,92 @@ +name: Deploy to DigitalOcean Droplet Prod Pre + +on: + push: + branches: + - master + +jobs: + deploy: + runs-on: buildjet-4vcpu-ubuntu-2204 + + environment: prod + + steps: + - name: checkout out code + uses: actions/checkout@v4 + + - name: Globalise Ingress certificate type env + run: | + echo "INGRESS_CERT_TYPE=${{ env.INGRESS_CERT_TYPE }}" >> $GITHUB_ENV + env: + INGRESS_CERT_TYPE: 'cloudflare' + + - name: Generate TLS Secrets for DO Droplet + run: | + rm -f $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/prod/ingress.api.crt $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/prod/ingress.api.key + echo ${{ secrets.INGRESS_API_CERT }} | base64 --decode > $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/prod/ingress.api.crt + echo ${{ secrets.INGRESS_API_CERT_KEY }} | base64 --decode > $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/prod/ingress.api.key + + - name: Copy file via scp - cloudflare + uses: appleboy/scp-action@master + with: + host: ${{secrets.DO_DROPLET_PROD_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + source: '.deploy/ssh/with-cloudflare/prod/docker-compose.api.prod.cloudflare.pre.yml,.deploy/ssh/with-cloudflare/prod/nginx.prod.pre.cloudflare.conf,.deploy/ssh/with-cloudflare/prod/ingress.api.crt,.deploy/ssh/with-cloudflare/prod/ingress.api.key' + target: '.' + - name: Copy file via scp - letsencrypt + uses: appleboy/scp-action@master + with: + host: ${{secrets.DO_DROPLET_PROD_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + source: '.deploy/ssh/with-letsencrypt/prod/docker-compose.api.prod.letsencrypt.pre.yml,.deploy/ssh/with-letsencrypt/prod/user_conf.d,.deploy/ssh/with-letsencrypt/prod/nginx-certbot.env' + target: '.' + - name: Install Docker + uses: appleboy/ssh-action@master + with: + host: ${{secrets.DO_DROPLET_PROD_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + script: | + if ! command -v docker &> /dev/null; then + echo "Docker not installed. Installing..." + sudo apt-get update + sudo apt-get install -y docker.io + sudo systemctl start docker + sudo systemctl enable docker + else + echo "Docker is already installed." + fi + - name: Install Docker Compose + uses: appleboy/ssh-action@master + with: + host: ${{secrets.DO_DROPLET_PROD_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + script: | + if ! command -v docker-compose &> /dev/null; then + echo "Docker Compose not installed. Installing..." + sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose + sudo chmod +x /usr/local/bin/docker-compose + else + echo "Docker Compose is already installed." + fi + - name: Deploy to DigitalOcean Droplet + uses: appleboy/ssh-action@master + with: + host: ${{secrets.DO_DROPLET_PROD_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + script: | + if [ "${{ env.INGRESS_CERT_TYPE }}" = "cloudflare" ]; then + docker-compose -f .deploy/ssh/with-letsencrypt/prod/docker-compose.api.prod.letsencrypt.pre.yml down + docker-compose -f .deploy/ssh/with-cloudflare/prod/docker-compose.api.prod.cloudflare.pre.yml up -d + elif [ "${{ env.INGRESS_CERT_TYPE }}" = "letsencrypt" ]; then + docker-compose -f .deploy/ssh/with-cloudflare/prod/docker-compose.api.prod.cloudflare.pre.yml down + docker-compose -f .deploy/ssh/with-letsencrypt/prod/docker-compose.api.prod.letsencrypt.pre.yml up -d + else + echo "Unknown INGRESS_CERT_TYPE: $INGRESS_CERT_TYPE" + exit 1 + fi diff --git a/.github/workflows/deploy-do-droplet-pre-stage.yml b/.github/workflows/deploy-do-droplet-pre-stage.yml new file mode 100644 index 00000000000..f95a233a7f7 --- /dev/null +++ b/.github/workflows/deploy-do-droplet-pre-stage.yml @@ -0,0 +1,92 @@ +name: Deploy to DigitalOcean Droplet Stage Pre + +on: + push: + branches: + - stage + +jobs: + deploy: + runs-on: buildjet-4vcpu-ubuntu-2204 + + environment: stage + + steps: + - name: checkout out code + uses: actions/checkout@v4 + + - name: Globalise Ingress certificate type env + run: | + echo "INGRESS_CERT_TYPE=${{ env.INGRESS_CERT_TYPE }}" >> $GITHUB_ENV + env: + INGRESS_CERT_TYPE: 'letsencrypt' + + - name: Generate TLS Secrets for DO Droplet + run: | + rm -f $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/stage/ingress.api.crt $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/stage/ingress.api.key + echo ${{ secrets.INGRESS_API_CERT }} | base64 --decode > $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/stage/ingress.api.crt + echo ${{ secrets.INGRESS_API_CERT_KEY }} | base64 --decode > $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/stage/ingress.api.key + + - name: Copy file via scp - cloudflare + uses: appleboy/scp-action@master + with: + host: ${{secrets.DO_DROPLET_STAGE_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + source: '.deploy/ssh/with-cloudflare/stage/docker-compose.api.stage.cloudflare.pre.yml,.deploy/ssh/with-cloudflare/stage/nginx.stage.pre.cloudflare.conf,.deploy/ssh/with-cloudflare/stage/ingress.api.crt,.deploy/ssh/with-cloudflare/stage/ingress.api.key' + target: '.' + - name: Copy file via scp - letsencrypt + uses: appleboy/scp-action@master + with: + host: ${{secrets.DO_DROPLET_STAGE_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + source: '.deploy/ssh/with-letsencrypt/stage/docker-compose.api.stage.letsencrypt.pre.yml,.deploy/ssh/with-letsencrypt/stage/user_conf.d,.deploy/ssh/with-letsencrypt/stage/nginx-certbot.env' + target: '.' + - name: Install Docker + uses: appleboy/ssh-action@master + with: + host: ${{secrets.DO_DROPLET_STAGE_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + script: | + if ! command -v docker &> /dev/null; then + echo "Docker not installed. Installing..." + sudo apt-get update + sudo apt-get install -y docker.io + sudo systemctl start docker + sudo systemctl enable docker + else + echo "Docker is already installed." + fi + - name: Install Docker Compose + uses: appleboy/ssh-action@master + with: + host: ${{secrets.DO_DROPLET_STAGE_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + script: | + if ! command -v docker-compose &> /dev/null; then + echo "Docker Compose not installed. Installing..." + sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose + sudo chmod +x /usr/local/bin/docker-compose + else + echo "Docker Compose is already installed." + fi + - name: Deploy to DigitalOcean Droplet + uses: appleboy/ssh-action@master + with: + host: ${{secrets.DO_DROPLET_STAGE_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + script: | + if [ "${{ env.INGRESS_CERT_TYPE }}" = "cloudflare" ]; then + docker-compose -f .deploy/ssh/with-letsencrypt/stage/docker-compose.api.stage.letsencrypt.pre.yml down + docker-compose -f .deploy/ssh/with-cloudflare/stage/docker-compose.api.stage.cloudflare.pre.yml up -d + elif [ "${{ env.INGRESS_CERT_TYPE }}" = "letsencrypt" ]; then + docker-compose -f .deploy/ssh/with-cloudflare/stage/docker-compose.api.stage.cloudflare.pre.yml down + docker-compose -f .deploy/ssh/with-letsencrypt/stage/docker-compose.api.stage.letsencrypt.pre.yml up -d + else + echo "Unknown INGRESS_CERT_TYPE: $INGRESS_CERT_TYPE" + exit 1 + fi diff --git a/.github/workflows/deploy-do-droplet-prod.yml b/.github/workflows/deploy-do-droplet-prod.yml new file mode 100644 index 00000000000..53955244907 --- /dev/null +++ b/.github/workflows/deploy-do-droplet-prod.yml @@ -0,0 +1,181 @@ +name: Deploy to DigitalOcean Droplet Prod + +on: + workflow_run: + workflows: ['Deploy to DigitalOcean Droplet Prod Pre'] + branches: [master] + types: + - completed + +jobs: + deploy: + runs-on: buildjet-4vcpu-ubuntu-2204 + + environment: prod + + steps: + - name: checkout out code + uses: actions/checkout@v4 + + - name: Modify API_BASE_URL + run: | + echo "INGRESS_CERT_TYPE=${{ env.INGRESS_CERT_TYPE }}" >> $GITHUB_ENV + + if [ "${{ env.INGRESS_CERT_TYPE }}" = "cloudflare" ]; then + echo "API_BASE_URL=https://apidt.gauzy.co" >> $GITHUB_ENV + elif [ "${{ env.INGRESS_CERT_TYPE }}" = "letsencrypt" ]; then + echo "API_BASE_URL=https://apidts.gauzy.co" >> $GITHUB_ENV + else + echo "UNKNOWN INGRESS_CERT_TYPE" + fi + env: + INGRESS_CERT_TYPE: 'cloudflare' + + - name: Inject secrets into .env-template.compose + run: | + if [ "${{ env.INGRESS_CERT_TYPE }}" = "cloudflare" ]; then + envsubst < $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/prod/docker-compose.api.prod.template.yml > temp.yaml && mv temp.yaml $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/prod/docker-compose.api.prod.yml + touch $GITHUB_WORKSPACE/.deploy/ssh/with-letsencrypt/prod/docker-compose.api.prod.yml + elif [ "${{ env.INGRESS_CERT_TYPE }}" = "letsencrypt" ]; then + envsubst < $GITHUB_WORKSPACE/.deploy/ssh/with-letsencrypt/prod/docker-compose.api.prod.template.yml > temp.yaml && mv temp.yaml $GITHUB_WORKSPACE/.deploy/ssh/with-letsencrypt/prod/docker-compose.api.prod.yml + touch $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/prod/docker-compose.api.prod.yml + else + echo "UNKNOWN INGRESS_CERT_TYPE" + fi + env: + ENV_NAME: 'prod' + DEMO: 'false' + NODE_ENV: 'development' + ADMIN_PASSWORD_RESET: 'true' + API_HOST: $API_HOST + API_BASE_URL: '${{ env.API_BASE_URL }}' + CLIENT_BASE_URL: 'https://app.gauzy.co' + DB_TYPE: '${{ secrets.DB_TYPE }}' + DB_URI: '${{ secrets.DB_URI }}' + DB_HOST: '${{ secrets.DB_HOST }}' + DB_USER: '${{ secrets.DB_USER }}' + DB_PASS: '${{ secrets.DB_PASS }}' + DB_NAME: '${{ secrets.DB_NAME }}' + DB_PORT: '${{ secrets.DB_PORT }}' + DB_CA_CERT: '${{ secrets.DB_CA_CERT }}' + DB_SSL_MODE: '${{ secrets.DB_SSL_MODE }}' + DB_POOL_SIZE: '${{ secrets.DB_POOL_SIZE }}' + DB_POOL_SIZE_KNEX: '${{ secrets.DB_POOL_SIZE_KNEX }}' + REDIS_ENABLED: '${{ secrets.REDIS_ENABLED }}' + REDIS_URL: '${{ secrets.REDIS_URL }}' + CLOUD_PROVIDER: 'DO' + SENTRY_DSN: '${{ secrets.SENTRY_DSN }}' + SENTRY_TRACES_SAMPLE_RATE: '${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}' + SENTRY_PROFILE_SAMPLE_RATE: '${{ secrets.SENTRY_PROFILE_SAMPLE_RATE }}' + SENTRY_HTTP_TRACING_ENABLED: '${{ secrets.SENTRY_HTTP_TRACING_ENABLED }}' + SENTRY_POSTGRES_TRACKING_ENABLED: '${{ secrets.SENTRY_POSTGRES_TRACKING_ENABLED }}' + SENTRY_PROFILING_ENABLED: '${{ secrets.SENTRY_PROFILING_ENABLED }}' + AWS_ACCESS_KEY_ID: '${{ secrets.AWS_ACCESS_KEY_ID }}' + AWS_SECRET_ACCESS_KEY: '${{ secrets.AWS_SECRET_ACCESS_KEY }}' + AWS_REGION: '${{ secrets.AWS_REGION }}' + AWS_S3_BUCKET: '${{ secrets.AWS_S3_BUCKET }}' + WASABI_ACCESS_KEY_ID: '${{ secrets.WASABI_ACCESS_KEY_ID }}' + WASABI_SECRET_ACCESS_KEY: '${{ secrets.WASABI_SECRET_ACCESS_KEY }}' + WASABI_REGION: '${{ secrets.WASABI_REGION }}' + WASABI_SERVICE_URL: '${{ secrets.WASABI_SERVICE_URL }}' + WASABI_S3_BUCKET: '${{ secrets.WASABI_S3_BUCKET }}' + EXPRESS_SESSION_SECRET: '${{ secrets.EXPRESS_SESSION_SECRET }}' + JWT_SECRET: '${{ secrets.JWT_SECRET }}' + JWT_REFRESH_TOKEN_SECRET: '${{ secrets.JWT_REFRESH_TOKEN_SECRET }}' + JWT_REFRESH_TOKEN_EXPIRATION_TIME: '${{ secrets.JWT_REFRESH_TOKEN_EXPIRATION_TIME }}' + CLOUDINARY_API_KEY: '${{ secrets.CLOUDINARY_API_KEY }}' + CLOUDINARY_API_SECRET: '${{ secrets.CLOUDINARY_API_SECRET }}' + CLOUDINARY_CLOUD_NAME: '${{ secrets.CLOUDINARY_CLOUD_NAME }}' + MAIL_FROM_ADDRESS: '${{ secrets.MAIL_FROM_ADDRESS }}' + MAIL_HOST: '${{ secrets.MAIL_HOST }}' + MAIL_PORT: '${{ secrets.MAIL_PORT }}' + MAIL_USERNAME: '${{ secrets.MAIL_USERNAME }}' + MAIL_PASSWORD: '${{ secrets.MAIL_PASSWORD }}' + ALLOW_SUPER_ADMIN_ROLE: '${{ secrets.ALLOW_SUPER_ADMIN_ROLE }}' + GOOGLE_CLIENT_ID: '${{ secrets.GOOGLE_CLIENT_ID }}' + GOOGLE_CLIENT_SECRET: '${{ secrets.GOOGLE_CLIENT_SECRET }}' + GOOGLE_CALLBACK_URL: '${{ secrets.GOOGLE_CALLBACK_URL }}' + FACEBOOK_CLIENT_ID: '${{ secrets.FACEBOOK_CLIENT_ID }}' + FACEBOOK_CLIENT_SECRET: '${{ secrets.FACEBOOK_CLIENT_SECRET }}' + FACEBOOK_GRAPH_VERSION: '${{ secrets.FACEBOOK_GRAPH_VERSION }}' + FACEBOOK_CALLBACK_URL: '${{ secrets.FACEBOOK_CALLBACK_URL }}' + INTEGRATED_USER_DEFAULT_PASS: '${{ secrets.INTEGRATED_USER_DEFAULT_PASS }}' + UPWORK_REDIRECT_URL: '${{ secrets.UPWORK_REDIRECT_URL }}' + FILE_PROVIDER: '${{ secrets.FILE_PROVIDER }}' + GAUZY_AI_GRAPHQL_ENDPOINT: '${{ secrets.GAUZY_AI_GRAPHQL_ENDPOINT }}' + GAUZY_AI_REST_ENDPOINT: '${{ secrets.GAUZY_AI_REST_ENDPOINT }}' + UNLEASH_APP_NAME: '${{ secrets.UNLEASH_APP_NAME }}' + UNLEASH_API_URL: '${{ secrets.UNLEASH_API_URL }}' + UNLEASH_INSTANCE_ID: '${{ secrets.UNLEASH_INSTANCE_ID }}' + UNLEASH_REFRESH_INTERVAL: '${{ secrets.UNLEASH_REFRESH_INTERVAL }}' + UNLEASH_METRICS_INTERVAL: '${{ secrets.UNLEASH_METRICS_INTERVAL }}' + UNLEASH_API_KEY: '${{ secrets.UNLEASH_API_KEY }}' + PM2_MACHINE_NAME: '${{ secrets.PM2_MACHINE_NAME }}' + PM2_SECRET_KEY: '${{ secrets.PM2_SECRET_KEY }}' + PM2_PUBLIC_KEY: '${{ secrets.PM2_PUBLIC_KEY }}' + JITSU_SERVER_URL: '${{ secrets.JITSU_SERVER_URL }}' + JITSU_SERVER_WRITE_KEY: '${{ secrets.JITSU_SERVER_WRITE_KEY }}' + OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}' + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' + OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' + GAUZY_GITHUB_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_CLIENT_ID }}' + GAUZY_GITHUB_CLIENT_SECRET: '${{ secrets.GAUZY_GITHUB_CLIENT_SECRET }}' + GAUZY_GITHUB_APP_PRIVATE_KEY: '${{ secrets.GAUZY_GITHUB_APP_PRIVATE_KEY }}' + GAUZY_GITHUB_WEBHOOK_URL: '${{ secrets.GAUZY_GITHUB_WEBHOOK_URL }}' + GAUZY_GITHUB_WEBHOOK_SECRET: '${{ secrets.GAUZY_GITHUB_WEBHOOK_SECRET }}' + GAUZY_GITHUB_APP_NAME: '${{ secrets.GAUZY_GITHUB_APP_NAME }}' + GAUZY_GITHUB_REDIRECT_URL: '${{ secrets.GAUZY_GITHUB_REDIRECT_URL }}' + GAUZY_GITHUB_POST_INSTALL_URL: '${{ secrets.GAUZY_GITHUB_POST_INSTALL_URL }}' + GAUZY_GITHUB_APP_ID: '${{ secrets.GAUZY_GITHUB_APP_ID }}' + GAUZY_GITHUB_OAUTH_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_OAUTH_CLIENT_ID }}' + GAUZY_GITHUB_OAUTH_CLIENT_SECRET: '${{ secrets.GAUZY_GITHUB_OAUTH_CLIENT_SECRET }}' + GAUZY_GITHUB_OAUTH_CALLBACK_URL: '${{ secrets.GAUZY_GITHUB_OAUTH_CALLBACK_URL }}' + JITSU_BROWSER_URL: '${{ secrets.JITSU_BROWSER_URL }}' + JITSU_BROWSER_WRITE_KEY: '${{ secrets.JITSU_BROWSER_WRITE_KEY }}' + MAGIC_CODE_EXPIRATION_TIME: '${{ secrets.MAGIC_CODE_EXPIRATION_TIME }}' + APP_NAME: '${{ secrets.APP_NAME }}' + APP_LOGO: '${{ secrets.APP_LOGO }}' + APP_SIGNATURE: '${{ secrets.APP_SIGNATURE }}' + APP_LINK: '${{ secrets.APP_LINK }}' + APP_EMAIL_CONFIRMATION_URL: '${{ secrets.APP_EMAIL_CONFIRMATION_URL }}' + APP_MAGIC_SIGN_URL: '${{ secrets.APP_MAGIC_SIGN_URL }}' + COMPANY_LINK: '${{ secrets.COMPANY_LINK }}' + COMPANY_NAME: '${{ secrets.COMPANY_NAME }}' + + - name: Copy file via scp - with-cloudflare + if: ${{ env.INGRESS_CERT_TYPE == 'cloudflare' }} + uses: appleboy/scp-action@master + with: + host: ${{secrets.DO_DROPLET_PROD_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + source: '.deploy/ssh/with-cloudflare/prod/docker-compose.api.prod.yml' + target: '.' + - name: Copy file via scp - with-letsencrypt + if: ${{ env.INGRESS_CERT_TYPE == 'letsencrypt' }} + uses: appleboy/scp-action@master + with: + host: ${{secrets.DO_DROPLET_PROD_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + source: '.deploy/ssh/with-letsencrypt/prod/docker-compose.api.prod.yml' + target: '.' + - name: Deploy to DigitalOcean Droplet + uses: appleboy/ssh-action@master + with: + host: ${{secrets.DO_DROPLET_PROD_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + envs: INGRESS_CERT_TYPE + script: | + if [ "${{ env.INGRESS_CERT_TYPE }}" = "cloudflare" ]; then + docker-compose -f .deploy/ssh/with-letsencrypt/prod/docker-compose.api.prod.yml down + docker-compose -f .deploy/ssh/with-cloudflare/prod/docker-compose.api.prod.yml up -d + elif [ "${{ env.INGRESS_CERT_TYPE }}" = "letsencrypt" ]; then + docker-compose -f .deploy/ssh/with-cloudflare/prod/docker-compose.api.prod.yml down + docker-compose -f .deploy/ssh/with-letsencrypt/prod/docker-compose.api.prod.yml up -d + else + echo "Unknown INGRESS_CERT_TYPE: $INGRESS_CERT_TYPE" + exit 1 + fi diff --git a/.github/workflows/deploy-do-droplet-stage.yml b/.github/workflows/deploy-do-droplet-stage.yml new file mode 100644 index 00000000000..fc4597ed72f --- /dev/null +++ b/.github/workflows/deploy-do-droplet-stage.yml @@ -0,0 +1,181 @@ +name: Deploy to DigitalOcean Droplet Stage + +on: + workflow_run: + workflows: ['Deploy to DigitalOcean Droplet Stage Pre'] + branches: [stage] + types: + - completed + +jobs: + deploy: + runs-on: buildjet-4vcpu-ubuntu-2204 + + environment: stage + + steps: + - name: checkout out code + uses: actions/checkout@v4 + + - name: Modify API_BASE_URL + run: | + echo "INGRESS_CERT_TYPE=${{ env.INGRESS_CERT_TYPE }}" >> $GITHUB_ENV + + if [ "${{ env.INGRESS_CERT_TYPE }}" = "cloudflare" ]; then + echo "API_BASE_URL=https://apistagedt.gauzy.co" >> $GITHUB_ENV + elif [ "${{ env.INGRESS_CERT_TYPE }}" = "letsencrypt" ]; then + echo "API_BASE_URL=https://apistagedts.gauzy.co" >> $GITHUB_ENV + else + echo "UNKNOWN INGRESS_CERT_TYPE" + fi + env: + INGRESS_CERT_TYPE: 'letsencrypt' + + - name: Inject secrets into .env-template.compose + run: | + if [ "${{ env.INGRESS_CERT_TYPE }}" = "cloudflare" ]; then + envsubst < $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/stage/docker-compose.api.stage.template.yml > temp.yaml && mv temp.yaml $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/stage/docker-compose.api.stage.yml + touch $GITHUB_WORKSPACE/.deploy/ssh/with-letsencrypt/stage/docker-compose.api.stage.yml + elif [ "${{ env.INGRESS_CERT_TYPE }}" = "letsencrypt" ]; then + envsubst < $GITHUB_WORKSPACE/.deploy/ssh/with-letsencrypt/stage/docker-compose.api.stage.template.yml > temp.yaml && mv temp.yaml $GITHUB_WORKSPACE/.deploy/ssh/with-letsencrypt/stage/docker-compose.api.stage.yml + touch $GITHUB_WORKSPACE/.deploy/ssh/with-cloudflare/stage/docker-compose.api.stage.yml + else + echo "UNKNOWN INGRESS_CERT_TYPE" + fi + env: + ENV_NAME: 'stage' + DEMO: 'false' + NODE_ENV: 'development' + ADMIN_PASSWORD_RESET: 'true' + API_HOST: $API_HOST + API_BASE_URL: '${{ env.API_BASE_URL }}' + CLIENT_BASE_URL: 'https://stage.gauzy.co' + DB_TYPE: '${{ secrets.DB_TYPE }}' + DB_URI: '${{ secrets.DB_URI }}' + DB_HOST: '${{ secrets.DB_HOST }}' + DB_USER: '${{ secrets.DB_USER }}' + DB_PASS: '${{ secrets.DB_PASS }}' + DB_NAME: '${{ secrets.DB_NAME }}' + DB_PORT: '${{ secrets.DB_PORT }}' + DB_CA_CERT: '${{ secrets.DB_CA_CERT }}' + DB_SSL_MODE: '${{ secrets.DB_SSL_MODE }}' + DB_POOL_SIZE: '${{ secrets.DB_POOL_SIZE }}' + DB_POOL_SIZE_KNEX: '${{ secrets.DB_POOL_SIZE_KNEX }}' + REDIS_ENABLED: '${{ secrets.REDIS_ENABLED }}' + REDIS_URL: '${{ secrets.REDIS_URL }}' + CLOUD_PROVIDER: 'DO' + SENTRY_DSN: '${{ secrets.SENTRY_DSN }}' + SENTRY_TRACES_SAMPLE_RATE: '${{ secrets.SENTRY_TRACES_SAMPLE_RATE }}' + SENTRY_PROFILE_SAMPLE_RATE: '${{ secrets.SENTRY_PROFILE_SAMPLE_RATE }}' + SENTRY_HTTP_TRACING_ENABLED: '${{ secrets.SENTRY_HTTP_TRACING_ENABLED }}' + SENTRY_POSTGRES_TRACKING_ENABLED: '${{ secrets.SENTRY_POSTGRES_TRACKING_ENABLED }}' + SENTRY_PROFILING_ENABLED: '${{ secrets.SENTRY_PROFILING_ENABLED }}' + AWS_ACCESS_KEY_ID: '${{ secrets.AWS_ACCESS_KEY_ID }}' + AWS_SECRET_ACCESS_KEY: '${{ secrets.AWS_SECRET_ACCESS_KEY }}' + AWS_REGION: '${{ secrets.AWS_REGION }}' + AWS_S3_BUCKET: '${{ secrets.AWS_S3_BUCKET }}' + WASABI_ACCESS_KEY_ID: '${{ secrets.WASABI_ACCESS_KEY_ID }}' + WASABI_SECRET_ACCESS_KEY: '${{ secrets.WASABI_SECRET_ACCESS_KEY }}' + WASABI_REGION: '${{ secrets.WASABI_REGION }}' + WASABI_SERVICE_URL: '${{ secrets.WASABI_SERVICE_URL }}' + WASABI_S3_BUCKET: '${{ secrets.WASABI_S3_BUCKET }}' + EXPRESS_SESSION_SECRET: '${{ secrets.EXPRESS_SESSION_SECRET }}' + JWT_SECRET: '${{ secrets.JWT_SECRET }}' + JWT_REFRESH_TOKEN_SECRET: '${{ secrets.JWT_REFRESH_TOKEN_SECRET }}' + JWT_REFRESH_TOKEN_EXPIRATION_TIME: '${{ secrets.JWT_REFRESH_TOKEN_EXPIRATION_TIME }}' + CLOUDINARY_API_KEY: '${{ secrets.CLOUDINARY_API_KEY }}' + CLOUDINARY_API_SECRET: '${{ secrets.CLOUDINARY_API_SECRET }}' + CLOUDINARY_CLOUD_NAME: '${{ secrets.CLOUDINARY_CLOUD_NAME }}' + MAIL_FROM_ADDRESS: '${{ secrets.MAIL_FROM_ADDRESS }}' + MAIL_HOST: '${{ secrets.MAIL_HOST }}' + MAIL_PORT: '${{ secrets.MAIL_PORT }}' + MAIL_USERNAME: '${{ secrets.MAIL_USERNAME }}' + MAIL_PASSWORD: '${{ secrets.MAIL_PASSWORD }}' + ALLOW_SUPER_ADMIN_ROLE: '${{ secrets.ALLOW_SUPER_ADMIN_ROLE }}' + GOOGLE_CLIENT_ID: '${{ secrets.GOOGLE_CLIENT_ID }}' + GOOGLE_CLIENT_SECRET: '${{ secrets.GOOGLE_CLIENT_SECRET }}' + GOOGLE_CALLBACK_URL: '${{ secrets.GOOGLE_CALLBACK_URL }}' + FACEBOOK_CLIENT_ID: '${{ secrets.FACEBOOK_CLIENT_ID }}' + FACEBOOK_CLIENT_SECRET: '${{ secrets.FACEBOOK_CLIENT_SECRET }}' + FACEBOOK_GRAPH_VERSION: '${{ secrets.FACEBOOK_GRAPH_VERSION }}' + FACEBOOK_CALLBACK_URL: '${{ secrets.FACEBOOK_CALLBACK_URL }}' + INTEGRATED_USER_DEFAULT_PASS: '${{ secrets.INTEGRATED_USER_DEFAULT_PASS }}' + UPWORK_REDIRECT_URL: '${{ secrets.UPWORK_REDIRECT_URL }}' + FILE_PROVIDER: '${{ secrets.FILE_PROVIDER }}' + GAUZY_AI_GRAPHQL_ENDPOINT: '${{ secrets.GAUZY_AI_GRAPHQL_ENDPOINT }}' + GAUZY_AI_REST_ENDPOINT: '${{ secrets.GAUZY_AI_REST_ENDPOINT }}' + UNLEASH_APP_NAME: '${{ secrets.UNLEASH_APP_NAME }}' + UNLEASH_API_URL: '${{ secrets.UNLEASH_API_URL }}' + UNLEASH_INSTANCE_ID: '${{ secrets.UNLEASH_INSTANCE_ID }}' + UNLEASH_REFRESH_INTERVAL: '${{ secrets.UNLEASH_REFRESH_INTERVAL }}' + UNLEASH_METRICS_INTERVAL: '${{ secrets.UNLEASH_METRICS_INTERVAL }}' + UNLEASH_API_KEY: '${{ secrets.UNLEASH_API_KEY }}' + PM2_MACHINE_NAME: '${{ secrets.PM2_MACHINE_NAME }}' + PM2_SECRET_KEY: '${{ secrets.PM2_SECRET_KEY }}' + PM2_PUBLIC_KEY: '${{ secrets.PM2_PUBLIC_KEY }}' + JITSU_SERVER_URL: '${{ secrets.JITSU_SERVER_URL }}' + JITSU_SERVER_WRITE_KEY: '${{ secrets.JITSU_SERVER_WRITE_KEY }}' + OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}' + OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' + OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' + GAUZY_GITHUB_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_CLIENT_ID }}' + GAUZY_GITHUB_CLIENT_SECRET: '${{ secrets.GAUZY_GITHUB_CLIENT_SECRET }}' + GAUZY_GITHUB_APP_PRIVATE_KEY: '${{ secrets.GAUZY_GITHUB_APP_PRIVATE_KEY }}' + GAUZY_GITHUB_WEBHOOK_URL: '${{ secrets.GAUZY_GITHUB_WEBHOOK_URL }}' + GAUZY_GITHUB_WEBHOOK_SECRET: '${{ secrets.GAUZY_GITHUB_WEBHOOK_SECRET }}' + GAUZY_GITHUB_APP_NAME: '${{ secrets.GAUZY_GITHUB_APP_NAME }}' + GAUZY_GITHUB_REDIRECT_URL: '${{ secrets.GAUZY_GITHUB_REDIRECT_URL }}' + GAUZY_GITHUB_POST_INSTALL_URL: '${{ secrets.GAUZY_GITHUB_POST_INSTALL_URL }}' + GAUZY_GITHUB_APP_ID: '${{ secrets.GAUZY_GITHUB_APP_ID }}' + GAUZY_GITHUB_OAUTH_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_OAUTH_CLIENT_ID }}' + GAUZY_GITHUB_OAUTH_CLIENT_SECRET: '${{ secrets.GAUZY_GITHUB_OAUTH_CLIENT_SECRET }}' + GAUZY_GITHUB_OAUTH_CALLBACK_URL: '${{ secrets.GAUZY_GITHUB_OAUTH_CALLBACK_URL }}' + JITSU_BROWSER_URL: '${{ secrets.JITSU_BROWSER_URL }}' + JITSU_BROWSER_WRITE_KEY: '${{ secrets.JITSU_BROWSER_WRITE_KEY }}' + MAGIC_CODE_EXPIRATION_TIME: '${{ secrets.MAGIC_CODE_EXPIRATION_TIME }}' + APP_NAME: '${{ secrets.APP_NAME }}' + APP_LOGO: '${{ secrets.APP_LOGO }}' + APP_SIGNATURE: '${{ secrets.APP_SIGNATURE }}' + APP_LINK: '${{ secrets.APP_LINK }}' + APP_EMAIL_CONFIRMATION_URL: '${{ secrets.APP_EMAIL_CONFIRMATION_URL }}' + APP_MAGIC_SIGN_URL: '${{ secrets.APP_MAGIC_SIGN_URL }}' + COMPANY_LINK: '${{ secrets.COMPANY_LINK }}' + COMPANY_NAME: '${{ secrets.COMPANY_NAME }}' + + - name: Copy file via scp - with-cloudflare + if: ${{ env.INGRESS_CERT_TYPE == 'cloudflare' }} + uses: appleboy/scp-action@master + with: + host: ${{secrets.DO_DROPLET_STAGE_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + source: '.deploy/ssh/with-cloudflare/stage/docker-compose.api.stage.yml' + target: '.' + - name: Copy file via scp - with-letsencrypt + if: ${{ env.INGRESS_CERT_TYPE == 'letsencrypt' }} + uses: appleboy/scp-action@master + with: + host: ${{secrets.DO_DROPLET_STAGE_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + source: '.deploy/ssh/with-letsencrypt/stage/docker-compose.api.stage.yml' + target: '.' + - name: Deploy to DigitalOcean Droplet + uses: appleboy/ssh-action@master + with: + host: ${{secrets.DO_DROPLET_STAGE_HOST}} + username: ${{secrets.DO_DROPLET_USERNAME}} + key: ${{secrets.DO_DROPLET_KEY}} + envs: INGRESS_CERT_TYPE + script: | + if [ "${{ env.INGRESS_CERT_TYPE }}" = "cloudflare" ]; then + docker-compose -f .deploy/ssh/with-letsencrypt/stage/docker-compose.api.stage.yml down + docker-compose -f .deploy/ssh/with-cloudflare/stage/docker-compose.api.stage.yml up -d + elif [ "${{ env.INGRESS_CERT_TYPE }}" = "letsencrypt" ]; then + docker-compose -f .deploy/ssh/with-cloudflare/stage/docker-compose.api.stage.yml down + docker-compose -f .deploy/ssh/with-letsencrypt/stage/docker-compose.api.stage.yml up -d + else + echo "Unknown INGRESS_CERT_TYPE: $INGRESS_CERT_TYPE" + exit 1 + fi diff --git a/.github/workflows/deploy-do-prod.yml b/.github/workflows/deploy-do-prod.yml index 5b0a1088d2e..0241c88a5dc 100644 --- a/.github/workflows/deploy-do-prod.yml +++ b/.github/workflows/deploy-do-prod.yml @@ -105,6 +105,7 @@ jobs: JITSU_SERVER_URL: '${{ secrets.JITSU_SERVER_URL }}' JITSU_SERVER_WRITE_KEY: '${{ secrets.JITSU_SERVER_WRITE_KEY }}' OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}' OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' GAUZY_GITHUB_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_CLIENT_ID }}' diff --git a/.github/workflows/deploy-do-stage.yml b/.github/workflows/deploy-do-stage.yml index 56981daaa21..5c9500c3d1b 100644 --- a/.github/workflows/deploy-do-stage.yml +++ b/.github/workflows/deploy-do-stage.yml @@ -106,6 +106,7 @@ jobs: JITSU_SERVER_URL: '${{ secrets.JITSU_SERVER_URL }}' JITSU_SERVER_WRITE_KEY: '${{ secrets.JITSU_SERVER_WRITE_KEY }}' OTEL_ENABLED: '${{ secrets.OTEL_ENABLED }}' + OTEL_PROVIDER: '${{ secrets.OTEL_PROVIDER }}' OTEL_EXPORTER_OTLP_TRACES_ENDPOINT: '${{ secrets.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT }}' OTEL_EXPORTER_OTLP_HEADERS: '${{ secrets.OTEL_EXPORTER_OTLP_HEADERS }}' GAUZY_GITHUB_CLIENT_ID: '${{ secrets.GAUZY_GITHUB_CLIENT_ID }}' diff --git a/.github/workflows/desktop-app-prod.yml b/.github/workflows/desktop-app-prod.yml index ca4a9abaa4f..df07aef2c8b 100644 --- a/.github/workflows/desktop-app-prod.yml +++ b/.github/workflows/desktop-app-prod.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: buildjet/setup-node@v3 + uses: buildjet/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -51,7 +51,7 @@ jobs: run: 'yarn bootstrap' - name: Bump version desktop app - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -85,7 +85,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -106,7 +106,7 @@ jobs: run: 'yarn bootstrap' - name: Bump version desktop app - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -140,7 +140,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -161,7 +161,7 @@ jobs: run: 'yarn bootstrap' - name: Bump version desktop app - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') diff --git a/.github/workflows/desktop-app-stage.yml b/.github/workflows/desktop-app-stage.yml index b4d9578d76d..80227d104d2 100644 --- a/.github/workflows/desktop-app-stage.yml +++ b/.github/workflows/desktop-app-stage.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: buildjet/setup-node@v3 + uses: buildjet/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -51,7 +51,7 @@ jobs: run: 'yarn bootstrap' - name: Bump version desktop app - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -85,7 +85,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -106,7 +106,7 @@ jobs: run: 'yarn bootstrap' - name: Bump version desktop app - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -140,7 +140,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -161,7 +161,7 @@ jobs: run: 'yarn bootstrap' - name: Bump version desktop app - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') diff --git a/.github/workflows/desktop-timer-app-prod.yml b/.github/workflows/desktop-timer-app-prod.yml index ab07cc16e6b..ab34accc8df 100644 --- a/.github/workflows/desktop-timer-app-prod.yml +++ b/.github/workflows/desktop-timer-app-prod.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: buildjet/setup-node@v3 + uses: buildjet/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -51,7 +51,7 @@ jobs: run: 'yarn bootstrap' - name: Bump version desktop timer app - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -91,7 +91,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -112,7 +112,7 @@ jobs: run: 'yarn bootstrap' - name: Bump version desktop timer app - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -152,7 +152,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -173,7 +173,7 @@ jobs: run: 'yarn bootstrap' - name: Bump version desktop timer app - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') diff --git a/.github/workflows/desktop-timer-app-stage.yml b/.github/workflows/desktop-timer-app-stage.yml index 19363ccae0b..6df5fbea44b 100644 --- a/.github/workflows/desktop-timer-app-stage.yml +++ b/.github/workflows/desktop-timer-app-stage.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: buildjet/setup-node@v3 + uses: buildjet/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -51,7 +51,7 @@ jobs: run: 'yarn bootstrap' - name: Bump version desktop timer app - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -91,7 +91,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -112,7 +112,7 @@ jobs: run: 'yarn bootstrap' - name: Bump version desktop timer app - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -152,7 +152,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -173,7 +173,7 @@ jobs: run: 'yarn bootstrap' - name: Bump version desktop timer app - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') diff --git a/.github/workflows/docker-build-publish-demo.yml b/.github/workflows/docker-build-publish-demo.yml index 89b5cbdea90..74b6aa77c52 100644 --- a/.github/workflows/docker-build-publish-demo.yml +++ b/.github/workflows/docker-build-publish-demo.yml @@ -16,13 +16,15 @@ jobs: uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 + with: + driver: docker - name: Build - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . file: ./.deploy/api/Dockerfile @@ -33,7 +35,7 @@ jobs: everco/gauzy-api-demo:latest registry.digitalocean.com/ever/gauzy-api-demo:latest ${{ secrets.CW_DOCKER_REGISTRY }}/ever-co/gauzy-api-demo:latest - cache-from: type=registry,ref=everco/gauzy-api-demo:latest + cache-from: type=registry,ref=ghcr.io/ever-co/gauzy-api-demo:latest cache-to: type=inline build-args: | NODE_ENV=development @@ -43,7 +45,7 @@ jobs: sudo docker image list - name: Login to DockerHub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -65,7 +67,7 @@ jobs: docker push registry.digitalocean.com/ever/gauzy-api-demo:latest - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -76,7 +78,7 @@ jobs: docker push ghcr.io/ever-co/gauzy-api-demo:latest - name: Login to CW Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ secrets.CW_DOCKER_REGISTRY }} username: ${{ secrets.CW_DOCKER_USER }} @@ -93,29 +95,34 @@ jobs: uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - - name: Build and push - uses: docker/build-push-action@v4 + - name: Build + uses: docker/build-push-action@v5 with: context: . file: ./.deploy/webapp/Dockerfile load: true + platforms: linux/amd64 tags: | ghcr.io/ever-co/gauzy-webapp-demo:latest everco/gauzy-webapp-demo:latest registry.digitalocean.com/ever/gauzy-webapp-demo:latest ${{ secrets.CW_DOCKER_REGISTRY }}/ever-co/gauzy-webapp-demo:latest - cache-from: type=registry,ref=everco/gauzy-webapp-demo:latest + cache-from: type=registry,ref=ghcr.io/ever-co/gauzy-webapp-demo:latest cache-to: type=inline build-args: | NODE_ENV=development + - name: Docker images list + run: | + sudo docker image list + - name: Login to DockerHub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -137,7 +144,7 @@ jobs: docker push registry.digitalocean.com/ever/gauzy-webapp-demo:latest - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -148,7 +155,7 @@ jobs: docker push ghcr.io/ever-co/gauzy-webapp-demo:latest - name: Login to CW Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ secrets.CW_DOCKER_REGISTRY }} username: ${{ secrets.CW_DOCKER_USER }} diff --git a/.github/workflows/docker-build-publish-prod.yml b/.github/workflows/docker-build-publish-prod.yml index 3c320d58fdb..2dc76396457 100644 --- a/.github/workflows/docker-build-publish-prod.yml +++ b/.github/workflows/docker-build-publish-prod.yml @@ -16,13 +16,15 @@ jobs: uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 + with: + driver: docker - name: Build - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . file: ./.deploy/api/Dockerfile @@ -33,7 +35,7 @@ jobs: everco/gauzy-api:latest registry.digitalocean.com/ever/gauzy-api:latest ${{ secrets.CW_DOCKER_REGISTRY }}/ever-co/gauzy-api:latest - cache-from: type=registry,ref=everco/gauzy-api:latest + cache-from: type=registry,ref=ghcr.io/ever-co/gauzy-api:latest cache-to: type=inline build-args: | NODE_ENV=production @@ -43,7 +45,7 @@ jobs: sudo docker image list - name: Login to DockerHub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -65,7 +67,7 @@ jobs: docker push registry.digitalocean.com/ever/gauzy-api:latest - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -76,7 +78,7 @@ jobs: docker push ghcr.io/ever-co/gauzy-api:latest - name: Login to CW Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ secrets.CW_DOCKER_REGISTRY }} username: ${{ secrets.CW_DOCKER_USER }} @@ -93,29 +95,34 @@ jobs: uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - - name: Build and push - uses: docker/build-push-action@v4 + - name: Build + uses: docker/build-push-action@v5 with: context: . file: ./.deploy/webapp/Dockerfile load: true + platforms: linux/amd64 tags: | ghcr.io/ever-co/gauzy-webapp:latest everco/gauzy-webapp:latest registry.digitalocean.com/ever/gauzy-webapp:latest ${{ secrets.CW_DOCKER_REGISTRY }}/ever-co/gauzy-webapp:latest - cache-from: type=registry,ref=everco/gauzy-webapp:latest + cache-from: type=registry,ref=ghcr.io/ever-co/gauzy-webapp:latest cache-to: type=inline build-args: | NODE_ENV=production + - name: Docker images list + run: | + sudo docker image list + - name: Login to DockerHub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -137,7 +144,7 @@ jobs: docker push registry.digitalocean.com/ever/gauzy-webapp:latest - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -148,7 +155,7 @@ jobs: docker push ghcr.io/ever-co/gauzy-webapp:latest - name: Login to CW Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ secrets.CW_DOCKER_REGISTRY }} username: ${{ secrets.CW_DOCKER_USER }} diff --git a/.github/workflows/docker-build-publish-stage.yml b/.github/workflows/docker-build-publish-stage.yml index 986018a1a2b..47255720608 100644 --- a/.github/workflows/docker-build-publish-stage.yml +++ b/.github/workflows/docker-build-publish-stage.yml @@ -16,13 +16,15 @@ jobs: uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 + with: + driver: docker - name: Build - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . file: ./.deploy/api/Dockerfile @@ -33,7 +35,7 @@ jobs: everco/gauzy-api-stage:latest registry.digitalocean.com/ever/gauzy-api-stage:latest ${{ secrets.CW_DOCKER_REGISTRY }}/ever-co/gauzy-api-stage:latest - cache-from: type=registry,ref=everco/gauzy-api-stage:latest + cache-from: type=registry,ref=ghcr.io/ever-co/gauzy-api-stage:latest cache-to: type=inline build-args: | NODE_ENV=development @@ -43,7 +45,7 @@ jobs: sudo docker image list - name: Login to DockerHub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -65,7 +67,7 @@ jobs: docker push registry.digitalocean.com/ever/gauzy-api-stage:latest - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -76,7 +78,7 @@ jobs: docker push ghcr.io/ever-co/gauzy-api-stage:latest - name: Login to CW Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ secrets.CW_DOCKER_REGISTRY }} username: ${{ secrets.CW_DOCKER_USER }} @@ -93,29 +95,34 @@ jobs: uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v2 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - - name: Build and push - uses: docker/build-push-action@v4 + - name: Build + uses: docker/build-push-action@v5 with: context: . file: ./.deploy/webapp/Dockerfile load: true + platforms: linux/amd64 tags: | ghcr.io/ever-co/gauzy-webapp-stage:latest everco/gauzy-webapp-stage:latest registry.digitalocean.com/ever/gauzy-webapp-stage:latest ${{ secrets.CW_DOCKER_REGISTRY }}/ever-co/gauzy-webapp-stage:latest - cache-from: type=registry,ref=everco/gauzy-webapp-stage:latest + cache-from: type=registry,ref=ghcr.io/ever-co/gauzy-webapp-stage:latest cache-to: type=inline build-args: | NODE_ENV=development + - name: Docker images list + run: | + sudo docker image list + - name: Login to DockerHub - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} @@ -137,7 +144,7 @@ jobs: docker push registry.digitalocean.com/ever/gauzy-webapp-stage:latest - name: Login to GitHub Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} @@ -148,7 +155,7 @@ jobs: docker push ghcr.io/ever-co/gauzy-webapp-stage:latest - name: Login to CW Container Registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ secrets.CW_DOCKER_REGISTRY }} username: ${{ secrets.CW_DOCKER_USER }} diff --git a/.github/workflows/server-api-prod.yml b/.github/workflows/server-api-prod.yml index ec2a1a34afd..cf02a0e290e 100644 --- a/.github/workflows/server-api-prod.yml +++ b/.github/workflows/server-api-prod.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: buildjet/setup-node@v3 + uses: buildjet/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -51,7 +51,7 @@ jobs: run: 'yarn bootstrap' - name: Bump server version - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -85,7 +85,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -106,7 +106,7 @@ jobs: run: 'yarn bootstrap' - name: Bump Server version - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -140,7 +140,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -161,7 +161,7 @@ jobs: run: 'yarn bootstrap' - name: Bump Server version - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') diff --git a/.github/workflows/server-api-stage.yml b/.github/workflows/server-api-stage.yml index 1c905a5c19d..ef0b3b50adb 100644 --- a/.github/workflows/server-api-stage.yml +++ b/.github/workflows/server-api-stage.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: buildjet/setup-node@v3 + uses: buildjet/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -51,7 +51,7 @@ jobs: run: 'yarn bootstrap' - name: Bump server version - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -85,7 +85,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -106,7 +106,7 @@ jobs: run: 'yarn bootstrap' - name: Bump Server version - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -140,7 +140,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -161,7 +161,7 @@ jobs: run: 'yarn bootstrap' - name: Bump Server version - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') diff --git a/.github/workflows/server-prod.yml b/.github/workflows/server-prod.yml index f5c94d16606..e22a0d1e35a 100644 --- a/.github/workflows/server-prod.yml +++ b/.github/workflows/server-prod.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: buildjet/setup-node@v3 + uses: buildjet/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -51,7 +51,7 @@ jobs: run: 'yarn bootstrap' - name: Bump server version - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -85,7 +85,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -106,7 +106,7 @@ jobs: run: 'yarn bootstrap' - name: Bump Server version - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -140,7 +140,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -161,7 +161,7 @@ jobs: run: 'yarn bootstrap' - name: Bump Server version - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') diff --git a/.github/workflows/server-stage.yml b/.github/workflows/server-stage.yml index a9709d68e53..80f483ebe8f 100644 --- a/.github/workflows/server-stage.yml +++ b/.github/workflows/server-stage.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: buildjet/setup-node@v3 + uses: buildjet/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -51,7 +51,7 @@ jobs: run: 'yarn bootstrap' - name: Bump server version - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -85,7 +85,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -106,7 +106,7 @@ jobs: run: 'yarn bootstrap' - name: Bump Server version - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') @@ -140,7 +140,7 @@ jobs: uses: actions/checkout@v4 - name: Install Node.js, NPM and Yarn - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: 18 cache: 'yarn' @@ -161,7 +161,7 @@ jobs: run: 'yarn bootstrap' - name: Bump Server version - uses: actions/github-script@v6 + uses: actions/github-script@v7 with: script: | const script = require('./.scripts/bump-version-electron.js') diff --git a/README.md b/README.md index eeeb4aef09d..5a1d38133eb 100644 --- a/README.md +++ b/README.md @@ -161,13 +161,11 @@ More information about our Server & Desktop Apps: ## 🧱 Technology Stack and Requirements -- [TypeScript](https://www.typescriptlang.org) language +- [TypeScript](https://www.typescriptlang.org) - [NodeJs](https://nodejs.org) / [NestJs](https://github.com/nestjs/nest) -- [Nx](https://nx.dev) -- [Angular](https://angular.io) -- [RxJS](http://reactivex.io/rxjs) -- [TypeORM](https://github.com/typeorm/typeorm) -- [Ngx-admin](https://github.com/akveo/ngx-admin) +- [Nx](https://nx.dev) / [Lerna](https://github.com/lerna/lerna) +- [Angular](https://angular.io) / [RxJS](http://reactivex.io/rxjs) / [Ngx-admin](https://github.com/akveo/ngx-admin) +- [TypeORM](https://github.com/typeorm/typeorm) / [MikroORM](https://github.com/mikro-orm/mikro-orm) / [Knex](https://github.com/knex/knex) For Production, we recommend: @@ -232,7 +230,7 @@ Notes: #### Optional / Recommended for Production -- Optionally (recommended for production) install and run [PostgreSQL](https://www.postgresql.org) version 14 or later. Note: other DB can be configured manually in TypeORM. The default DB is set to SQLite (recommended for testing/demo purposes only). +- Optionally (recommended for production) install and run [PostgreSQL](https://www.postgresql.org) version 14 or later (16.x recommended for production). Note: other DB can be configured manually in TypeORM / MikroORM / Knex. The default DB is set to SQLite (recommended for testing/demo purposes only). - Optionally (recommended for production) install and run [Redis](https://github.com/redis/redis). Notes: the platform will work without Redis using an in-memory caching strategy instead of a distributed one (recommended for testing/demo purposes only). Please note however that Redis is required for Jitsu. - Optionally (recommended for production) install and run [ElasticSearch](https://github.com/elastic/elasticsearch). Note: the platform will work without ElasticSearch using DB build-in search capabilities (recommended for testing/demo purposes only). - Optionally install and run [MinIO](https://github.com/minio/minio) or [LocalStack](https://github.com/localstack/localstack). Note: the platform will work without MinIO / LocalStack or other S3-compatible storage using local filesystem-based storage (recommended for testing/demo purposes only). For production, we recommend using Wasabi or AWS S3 storage or another S3-compatible cloud storage. @@ -243,7 +241,9 @@ Notes: - See [Setup Gauzy for Client Server](https://github.com/ever-co/ever-gauzy/wiki/Setup-Gauzy-for-Client-Server) for more information about production setup on your servers. - We recommend deploying to Kubernetes (k8s), either manually (see below) or with our [Ever Helm Charts](https://github.com/ever-co/ever-charts). -- For simple deployment scenarios (e.g. for yourself or your small organization), check our [Kubernetes configurations](https://github.com/ever-co/ever-gauzy/tree/develop/.deploy/k8s), which we are using to deploy Gauzy into [DigitalOcean k8s cluster](https://www.digitalocean.com/products/kubernetes). +- For the most simple deployment scenarios (e.g. for yourself or your small organization), check our [DigitalOcean App Platform configurations](https://github.com/ever-co/ever-gauzy/tree/develop/.do) and corresponding [GitHub Action](https://github.com/ever-co/ever-gauzy/blob/develop/.github/workflows/deploy-do-app-platform-stage.yml). +- Another variant to deploy Gauzy is to use DigitalOcean Droplets or any other virtual instance (with Ubuntu OS) and deploy using SCP/SSH, for example following [GitHub Action](https://github.com/ever-co/ever-gauzy/blob/develop/.github/workflows/deploy-do-droplet-demo.yml) +- For more complex deployment scenarios, please see [Kubernetes configurations](https://github.com/ever-co/ever-gauzy/tree/develop/.deploy/k8s), which we are using to deploy Gauzy into [DigitalOcean k8s cluster](https://www.digitalocean.com/products/kubernetes). - In addition, check [Gauzy Pulumi](https://github.com/ever-co/ever-gauzy-pulumi) project (WIP), it makes complex Clouds deployments possible with a single command (`pulumi up`). Note: it currently supports AWS EKS (Kubernetes) for development and production with Application Load Balancers and AWS RDS Serverless PostgreSQL DB deployments. We also implemented deployments to ECS EC2 and Fargate Clusters in the same Pulumi project. ## 💌 Contact Us diff --git a/apps/api/package.json b/apps/api/package.json index 873662574ac..4d715e81db0 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -49,11 +49,11 @@ "yargs": "^17.5.0" }, "devDependencies": { - "@nestjs/schematics": "^10.0.3", - "@nestjs/testing": "^10.3.0", - "nodemon": "^2.0.7", - "pm2": "^4.5.1", - "ts-node": "^10.9.1", + "@nestjs/schematics": "^10.1.1", + "@nestjs/testing": "^10.3.3", + "nodemon": "^3.1.0", + "pm2": "^5.3.1", + "ts-node": "^10.9.2", "typescript": "5.1.6" } } diff --git a/apps/api/src/main.ts b/apps/api/src/main.ts index 21c772cd457..529f9eaa98c 100755 --- a/apps/api/src/main.ts +++ b/apps/api/src/main.ts @@ -1,7 +1,15 @@ import { bootstrap } from '@gauzy/core'; +console.log('Bootstrap loaded'); + import { pluginConfig } from './plugin-config'; +console.log('Plugin Config loaded'); + +bootstrap(pluginConfig) + .then(() => { + console.log('API is running'); + }) + .catch(async (error) => { + console.log(error); -bootstrap(pluginConfig).catch((error) => { - console.log(error); - process.exit(1); -}); + process.exit(1); + }); diff --git a/apps/api/src/plugin-config.ts b/apps/api/src/plugin-config.ts index 5131457f7fa..c2587d43e7d 100644 --- a/apps/api/src/plugin-config.ts +++ b/apps/api/src/plugin-config.ts @@ -1,7 +1,18 @@ import * as path from 'path'; import * as chalk from 'chalk'; -import { ApplicationPluginConfig, DEFAULT_API_PORT, DEFAULT_GRAPHQL_API_PATH, DEFAULT_API_HOST, DEFAULT_API_BASE_URL } from '@gauzy/common'; -import { dbTypeOrmConnectionConfig, dbMikroOrmConnectionConfig, environment, dbKnexConnectionConfig } from '@gauzy/config'; +import { + ApplicationPluginConfig, + DEFAULT_API_PORT, + DEFAULT_GRAPHQL_API_PATH, + DEFAULT_API_HOST, + DEFAULT_API_BASE_URL +} from '@gauzy/common'; +import { + dbTypeOrmConnectionConfig, + dbMikroOrmConnectionConfig, + environment, + dbKnexConnectionConfig +} from '@gauzy/config'; import { SentryService } from '@gauzy/sentry-plugin'; import { SentryTracing as SentryPlugin } from './sentry'; import { version } from './../version'; @@ -41,7 +52,7 @@ export const pluginConfig: ApplicationPluginConfig = { playground: true, debug: true, apolloServerPlugins: [] - }, + } }, dbConnectionOptions: { retryAttempts: 100, @@ -63,5 +74,5 @@ export const pluginConfig: ApplicationPluginConfig = { assetPublicPath: assetPublicPath }, ...(sentry?.dsn ? { logger: new SentryService(SentryPlugin.options) } : {}), - plugins, + plugins }; diff --git a/apps/api/src/sentry.ts b/apps/api/src/sentry.ts index 499ff8ebf97..221e0b29d35 100644 --- a/apps/api/src/sentry.ts +++ b/apps/api/src/sentry.ts @@ -6,23 +6,32 @@ import { version } from '../version'; * Initializes and configures the Sentry module. * @returns The configured Sentry instance. */ -export function initializeSentry(): typeof SentryPlugin { - return SentryPlugin.init({ - dsn: environment.sentry.dsn, - debug: process.env.SENTRY_DEBUG === 'true' || !environment.production, - environment: environment.production ? 'production' : 'development', - release: 'gauzy@' + version, - logLevels: ['error'], - integrations: [ - ...DefaultSentryIntegrations - ], - tracesSampleRate: process.env.SENTRY_TRACES_SAMPLE_RATE ? parseInt(process.env.SENTRY_TRACES_SAMPLE_RATE) : 0.01, - profilesSampleRate: process.env.SENTRY_PROFILE_SAMPLE_RATE ? parseInt(process.env.SENTRY_PROFILE_SAMPLE_RATE) : 1, - close: { - enabled: true, - timeout: 3000 // Time in milliseconds to forcefully quit the application - } - }); +export function initializeSentry(): typeof SentryPlugin | null { + if (environment.sentry.dsn) { + console.log('Initializing Sentry with DSN:', environment.sentry.dsn); + + return SentryPlugin.init({ + dsn: environment.sentry.dsn, + debug: process.env.SENTRY_DEBUG === 'true' || !environment.production, + environment: environment.production ? 'production' : 'development', + release: 'gauzy@' + version, + logLevels: ['error'], + integrations: [...DefaultSentryIntegrations], + tracesSampleRate: process.env.SENTRY_TRACES_SAMPLE_RATE + ? parseInt(process.env.SENTRY_TRACES_SAMPLE_RATE) + : 0.01, + profilesSampleRate: process.env.SENTRY_PROFILE_SAMPLE_RATE + ? parseInt(process.env.SENTRY_PROFILE_SAMPLE_RATE) + : 1, + close: { + enabled: true, + timeout: 3000 // Time in milliseconds to forcefully quit the application + } + }); + } else { + console.log('Sentry not initialized: DSN not provided'); + return null; + } } export const SentryTracing = initializeSentry(); diff --git a/apps/api/tsconfig.json b/apps/api/tsconfig.json index 4dfaebfb931..bba17574137 100644 --- a/apps/api/tsconfig.json +++ b/apps/api/tsconfig.json @@ -5,6 +5,6 @@ "incremental": true, "tsBuildInfoFile": "./tsconfig.tsbuildinfo" }, - "include": ["**/*.ts"], + "include": ["**/*.ts", "../../packages/core/src/bootstrap/tracer.ts"], "exclude": ["jest.config.ts"] } diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 00922bcfd0b..039005203fa 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -48,7 +48,7 @@ "@nebular/eva-icons": "^12.0.0", "@nebular/security": "^12.0.0", "@nebular/theme": "^12.0.0", - "@nestjs/typeorm": "^10.0.1", + "@nestjs/typeorm": "^10.0.2", "@ng-select/ng-select": "^11.2.0", "@ngneat/until-destroy": "^9.2.0", "@ngx-translate/core": "^14.0.0", @@ -86,7 +86,7 @@ "sqlite3": "^5.1.5", "squirrelly": "^8.0.8", "twing": "^5.0.2", - "typeorm": "^0.3.17", + "typeorm": "^0.3.20", "underscore": "^1.13.3" }, "optionalDependencies": { diff --git a/apps/desktop/src/package.json b/apps/desktop/src/package.json index 5859f316c35..68c6a00d838 100644 --- a/apps/desktop/src/package.json +++ b/apps/desktop/src/package.json @@ -1,183 +1,183 @@ { - "name": "gauzy-desktop", - "productName": "Gauzy Desktop", - "version": "0.1.0", - "description": "Gauzy Desktop", - "license": "AGPL-3.0", - "homepage": "https://gauzy.co", - "repository": { - "type": "git", - "url": "https://github.com/ever-co/ever-gauzy.git" - }, - "bugs": { - "url": "https://github.com/ever-co/ever-gauzy/issues" - }, - "private": true, - "author": { - "name": "Ever Co. LTD", - "email": "ever@ever.co", - "url": "https://ever.co" - }, - "main": "index.js", - "workspaces": { - "packages": [ - "../../../packages/core", - "../../../packages/auth", - "../../../packages/desktop-window", - "../../../packages/desktop-libs", - "../../../packages/plugins/knowledge-base", - "../../../packages/plugins/changelog", - "../../../packages/plugins/jitsu-analytics", - "../../../packages/plugins/sentry-tracing", - "../../../packages/common", - "../../../packages/config", - "../../../packages/contracts", - "../../../packages/plugins/integration-ai", - "../../../packages/plugins/integration-hubstaff", - "../../../packages/plugins/integration-upwork", - "../../../packages/plugins/integration-github", - "../../../packages/plugins/integration-jira", - "../../../packages/plugin" - ] - }, - "build": { - "appId": "com.ever.gauzydesktop", - "artifactName": "${name}-${version}.${ext}", - "productName": "Gauzy Desktop", - "copyright": "Copyright © 2019-Present. Ever Co. LTD", - "dmg": { - "sign": false - }, - "asar": true, - "npmRebuild": true, - "asarUnpack": [ - "node_modules/screenshot-desktop/lib/win32", - "node_modules/@sentry/electron", - "node_modules/sqlite3/lib", - "node_modules/better-sqlite3", - "node_modules/@sentry/profiling-node/lib" - ], - "directories": { - "buildResources": "icons", - "output": "../desktop-packages" - }, - "publish": [ - { - "provider": "github", - "repo": "ever-gauzy-desktop", - "releaseType": "release" - }, - { - "provider": "spaces", - "name": "ever", - "region": "sfo3", - "path": "/ever-gauzy-desktop", - "acl": "public-read" - } - ], - "mac": { - "category": "public.app-category.developer-tools", - "icon": "icon.icns", - "target": [ - "zip", - "dmg" - ], - "asarUnpack": "**/*.node", - "artifactName": "${name}-${version}.${ext}", - "hardenedRuntime": true, - "gatekeeperAssess": false, - "entitlements": "tools/build/entitlements.mas.plist", - "entitlementsInherit": "tools/build/entitlements.mas.plist", - "extendInfo": { - "NSAppleEventsUsageDescription": "Please allow access to script browser applications to detect the current URL when triggering instant lookup." - } - }, - "win": { - "publisherName": "Ever", - "target": [ - { - "target": "nsis", - "arch": [ - "x64" - ] - } - ], - "icon": "icon.ico", - "verifyUpdateCodeSignature": false - }, - "linux": { - "icon": "linux", - "target": [ - "AppImage", - "deb", - "tar.gz" - ], - "executableName": "gauzy-desktop", - "artifactName": "${name}-${version}.${ext}", - "synopsis": "Desktop", - "category": "Development" - }, - "nsis": { - "oneClick": false, - "perMachine": true, - "createDesktopShortcut": true, - "createStartMenuShortcut": true, - "allowToChangeInstallationDirectory": true, - "allowElevation": true, - "installerIcon": "icon.ico", - "artifactName": "${name}-${version}.${ext}", - "deleteAppDataOnUninstall": true, - "menuCategory": true - }, - "extraResources": [ - "./data/**/*" - ] - }, - "dependencies": { - "@datorama/akita": "^7.1.1", - "@datorama/akita-ngdevtools": "^7.0.0", - "@electron/remote": "^2.0.8", - "@gauzy/auth": "^0.1.0", - "@gauzy/changelog-plugin": "^0.1.0", - "@gauzy/core": "^0.1.0", - "@gauzy/desktop-libs": "^0.1.0", - "@gauzy/desktop-window": "^0.1.0", - "@gauzy/knowledge-base-plugin": "^0.1.0", - "@nestjs/platform-express": "^10.3.0", - "@sentry/electron": "^4.18.0", - "@sentry/node": "^7.101.1", - "@sentry/tracing": "^7.101.1", - "@sentry/types": "^7.101.1", - "@sentry/profiling-node": "^7.101.1", - "auto-launch": "5.0.5", - "consolidate": "^0.16.0", - "electron-log": "^4.4.8", - "electron-store": "^8.1.0", - "electron-updater": "^6.1.7", - "electron-util": "^0.17.2", - "embedded-queue": "^0.0.11", - "ffi-napi": "^4.0.3", - "form-data": "^3.0.0", - "htmlparser2": "^8.0.2", - "iconv": "^3.0.1", - "knex": "^3.1.0", - "mac-screen-capture-permissions": "^2.0.0", - "moment": "^2.29.4", - "node-fetch": "^2.6.7", - "node-notifier": "^8.0.0", - "pg": "^8.11.3", - "pg-query-stream": "^4.5.3", - "screenshot-desktop": "^1.12.7", - "sound-play": "1.1.0", - "sqlite3": "^5.1.5", - "squirrelly": "^8.0.8", - "tslib": "^2.3.0", - "twing": "^5.0.2", - "underscore": "^1.13.3" - }, - "optionalDependencies": { - "node-linux": "^0.1.12", - "node-mac": "^1.0.1", - "node-windows": "^1.0.0-beta.8" - } -} \ No newline at end of file + "name": "gauzy-desktop", + "productName": "Gauzy Desktop", + "version": "0.1.0", + "description": "Gauzy Desktop", + "license": "AGPL-3.0", + "homepage": "https://gauzy.co", + "repository": { + "type": "git", + "url": "https://github.com/ever-co/ever-gauzy.git" + }, + "bugs": { + "url": "https://github.com/ever-co/ever-gauzy/issues" + }, + "private": true, + "author": { + "name": "Ever Co. LTD", + "email": "ever@ever.co", + "url": "https://ever.co" + }, + "main": "index.js", + "workspaces": { + "packages": [ + "../../../packages/core", + "../../../packages/auth", + "../../../packages/desktop-window", + "../../../packages/desktop-libs", + "../../../packages/plugins/knowledge-base", + "../../../packages/plugins/changelog", + "../../../packages/plugins/jitsu-analytics", + "../../../packages/plugins/sentry-tracing", + "../../../packages/common", + "../../../packages/config", + "../../../packages/contracts", + "../../../packages/plugins/integration-ai", + "../../../packages/plugins/integration-hubstaff", + "../../../packages/plugins/integration-upwork", + "../../../packages/plugins/integration-github", + "../../../packages/plugins/integration-jira", + "../../../packages/plugin" + ] + }, + "build": { + "appId": "com.ever.gauzydesktop", + "artifactName": "${name}-${version}.${ext}", + "productName": "Gauzy Desktop", + "copyright": "Copyright © 2019-Present. Ever Co. LTD", + "dmg": { + "sign": false + }, + "asar": true, + "npmRebuild": true, + "asarUnpack": [ + "node_modules/screenshot-desktop/lib/win32", + "node_modules/@sentry/electron", + "node_modules/sqlite3/lib", + "node_modules/better-sqlite3", + "node_modules/@sentry/profiling-node/lib" + ], + "directories": { + "buildResources": "icons", + "output": "../desktop-packages" + }, + "publish": [ + { + "provider": "github", + "repo": "ever-gauzy-desktop", + "releaseType": "release" + }, + { + "provider": "spaces", + "name": "ever", + "region": "sfo3", + "path": "/ever-gauzy-desktop", + "acl": "public-read" + } + ], + "mac": { + "category": "public.app-category.developer-tools", + "icon": "icon.icns", + "target": [ + "zip", + "dmg" + ], + "asarUnpack": "**/*.node", + "artifactName": "${name}-${version}.${ext}", + "hardenedRuntime": true, + "gatekeeperAssess": false, + "entitlements": "tools/build/entitlements.mas.plist", + "entitlementsInherit": "tools/build/entitlements.mas.plist", + "extendInfo": { + "NSAppleEventsUsageDescription": "Please allow access to script browser applications to detect the current URL when triggering instant lookup." + } + }, + "win": { + "publisherName": "Ever", + "target": [ + { + "target": "nsis", + "arch": [ + "x64" + ] + } + ], + "icon": "icon.ico", + "verifyUpdateCodeSignature": false + }, + "linux": { + "icon": "linux", + "target": [ + "AppImage", + "deb", + "tar.gz" + ], + "executableName": "gauzy-desktop", + "artifactName": "${name}-${version}.${ext}", + "synopsis": "Desktop", + "category": "Development" + }, + "nsis": { + "oneClick": false, + "perMachine": true, + "createDesktopShortcut": true, + "createStartMenuShortcut": true, + "allowToChangeInstallationDirectory": true, + "allowElevation": true, + "installerIcon": "icon.ico", + "artifactName": "${name}-${version}.${ext}", + "deleteAppDataOnUninstall": true, + "menuCategory": true + }, + "extraResources": [ + "./data/**/*" + ] + }, + "dependencies": { + "@datorama/akita": "^7.1.1", + "@datorama/akita-ngdevtools": "^7.0.0", + "@electron/remote": "^2.0.8", + "@gauzy/auth": "^0.1.0", + "@gauzy/changelog-plugin": "^0.1.0", + "@gauzy/core": "^0.1.0", + "@gauzy/desktop-libs": "^0.1.0", + "@gauzy/desktop-window": "^0.1.0", + "@gauzy/knowledge-base-plugin": "^0.1.0", + "@nestjs/platform-express": "^10.3.3", + "@sentry/electron": "^4.18.0", + "@sentry/node": "^7.101.1", + "@sentry/tracing": "^7.101.1", + "@sentry/types": "^7.101.1", + "@sentry/profiling-node": "^7.101.1", + "auto-launch": "5.0.5", + "consolidate": "^0.16.0", + "electron-log": "^4.4.8", + "electron-store": "^8.1.0", + "electron-updater": "^6.1.7", + "electron-util": "^0.17.2", + "embedded-queue": "^0.0.11", + "ffi-napi": "^4.0.3", + "form-data": "^3.0.0", + "htmlparser2": "^8.0.2", + "iconv": "^3.0.1", + "knex": "^3.1.0", + "mac-screen-capture-permissions": "^2.0.0", + "moment": "^2.29.4", + "node-fetch": "^2.6.7", + "node-notifier": "^8.0.0", + "pg": "^8.11.3", + "pg-query-stream": "^4.5.3", + "screenshot-desktop": "^1.12.7", + "sound-play": "1.1.0", + "sqlite3": "^5.1.5", + "squirrelly": "^8.0.8", + "tslib": "^2.3.0", + "twing": "^5.0.2", + "underscore": "^1.13.3" + }, + "optionalDependencies": { + "node-linux": "^0.1.12", + "node-mac": "^1.0.1", + "node-windows": "^1.0.0-beta.8" + } +} diff --git a/apps/gauzy/package.json b/apps/gauzy/package.json index 740f83f5b3f..ec83b33bddc 100644 --- a/apps/gauzy/package.json +++ b/apps/gauzy/package.json @@ -205,7 +205,7 @@ "karma-coverage-istanbul-reporter": "^3.0.3", "karma-jasmine": "^4.0.1", "karma-jasmine-html-reporter": "^1.5.4", - "pm2": "^4.5.1", + "pm2": "^5.3.1", "terser": "^5.10.0", "terser-webpack-plugin": "^5.2.5", "webpack": "^5.65.0", diff --git a/apps/gauzy/src/app/@core/sentry-error.handler.ts b/apps/gauzy/src/app/@core/sentry-error.handler.ts index e997dba6bea..4a1aa831b82 100644 --- a/apps/gauzy/src/app/@core/sentry-error.handler.ts +++ b/apps/gauzy/src/app/@core/sentry-error.handler.ts @@ -5,7 +5,7 @@ import { GAUZY_ENV } from './constants'; @Injectable() export class SentryErrorHandler implements ErrorHandler { - constructor(@Inject(GAUZY_ENV) private readonly environment: Environment) {} + constructor(@Inject(GAUZY_ENV) private readonly environment: Environment) { } handleError(error) { if (this.environment.SENTRY_DSN) { diff --git a/apps/gauzy/src/app/@core/services/employees.service.ts b/apps/gauzy/src/app/@core/services/employees.service.ts index 33a7ea0d20f..e30eb04c08b 100644 --- a/apps/gauzy/src/app/@core/services/employees.service.ts +++ b/apps/gauzy/src/app/@core/services/employees.service.ts @@ -19,7 +19,7 @@ import { API_PREFIX } from '../constants/app.constants'; export class EmployeesService { constructor( private readonly http: HttpClient - ) {} + ) { } getAllPublic( request: IEmployeeFindInput, @@ -43,8 +43,8 @@ export class EmployeesService { getAll( relations: string[] = [], where?: IEmployeeFindInput - ): Observable<{ items: IEmployee[]; total: number }> { - return this.http.get<{ items: IEmployee[]; total: number }>( `${API_PREFIX}/employee`, { + ): Observable> { + return this.http.get>(`${API_PREFIX}/employee`, { params: toParams({ where, relations }) }); } @@ -62,7 +62,7 @@ export class EmployeesService { tenantId: string, forRange: IDateRangePicker, withUser: boolean - ): Promise<{ items: IEmployee[]; total: number }> { + ): Promise> { const query = { organizationId, tenantId, @@ -71,31 +71,26 @@ export class EmployeesService { }; const data = JSON.stringify({ findInput: query }); return firstValueFrom( - this.http.get<{ items: IEmployee[]; total: number }>( - `${API_PREFIX}/employee/working`, - { - params: { data } - } - ) + this.http.get>(`${API_PREFIX}/employee/working`, { + params: { data } + }) ); } getWorkingCount( organizationId: string, tenantId: string, - forRange: IDateRangePicker, - withUser: boolean + forRange: IDateRangePicker ): Promise<{ total: number }> { const query = { organizationId, tenantId, - forRange, - withUser + forRange }; const data = JSON.stringify({ findInput: query }); return firstValueFrom( - this.http.get<{ items: IEmployee[]; total: number }>( `${API_PREFIX}/employee/working/count`, { - params: { data} + this.http.get<{ total: number }>(`${API_PREFIX}/employee/working/count`, { + params: { data } }) ); } diff --git a/apps/gauzy/src/app/@core/validators/at-least-one-field.validator.ts b/apps/gauzy/src/app/@core/validators/at-least-one-field.validator.ts index 4508d081cea..895fa645eda 100644 --- a/apps/gauzy/src/app/@core/validators/at-least-one-field.validator.ts +++ b/apps/gauzy/src/app/@core/validators/at-least-one-field.validator.ts @@ -1,14 +1,27 @@ import { UntypedFormGroup } from '@angular/forms'; +import { isNotNullOrUndefined } from '@gauzy/common-angular'; +/** + * Validates that at least one field in the group has a valid, non-null, and non-undefined value. + * + * @param group - The form group to validate. + * @returns A validation error object if no valid value is found in the group, otherwise null. + */ export function AtLeastOneFieldValidator(group: UntypedFormGroup): { [key: string]: any } { let isAtLeastOne = false; + if (group && group.controls) { for (const control in group.controls) { - if (group.controls.hasOwnProperty(control) && group.controls[control].valid && group.controls[control].value) { + if ( + group.controls.hasOwnProperty(control) && + group.controls[control].valid && + isNotNullOrUndefined(group.controls[control].value) + ) { isAtLeastOne = true; break; } } } + return isAtLeastOne ? null : { requiredAtLeastOne: true }; } diff --git a/apps/gauzy/src/app/@theme/components/header/header.component.ts b/apps/gauzy/src/app/@theme/components/header/header.component.ts index c23d61654b7..90b3dc510eb 100644 --- a/apps/gauzy/src/app/@theme/components/header/header.component.ts +++ b/apps/gauzy/src/app/@theme/components/header/header.component.ts @@ -429,8 +429,7 @@ export class HeaderComponent extends TranslationBaseComponent implements OnInit, const { total: employeeCount } = await this.employeesService.getWorkingCount( organizationId, tenantId, - this.selectedDateRange, - true + this.selectedDateRange ); this.showEmployeesSelector = employeeCount > 0; if (this.showEmployeesSelector && !this.store.selectedEmployee) { diff --git a/apps/gauzy/src/app/pages/miscellaneous/not-found/not-found.component.html b/apps/gauzy/src/app/pages/miscellaneous/not-found/not-found.component.html index 6d47482d65a..df78c154b9b 100644 --- a/apps/gauzy/src/app/pages/miscellaneous/not-found/not-found.component.html +++ b/apps/gauzy/src/app/pages/miscellaneous/not-found/not-found.component.html @@ -3,13 +3,18 @@
-

+

404

+

{{ 'PAGE_NOT_FOUND.404_PAGE_NOT_FOUND' | translate }} -

- {{ - 'PAGE_NOT_FOUND.THE_PAGE_YOU_WERE_LOOKING_FOR_DOESNT_EXIST' - | translate - }} + + + {{ + 'PAGE_NOT_FOUND.THE_PAGE_YOU_WERE_LOOKING_FOR_DOESNT_EXIST' | translate + }} + +

+ {{ 'PAGE_NOT_FOUND.REDIRECT_TO_HOME' | translate }} +

diff --git a/apps/gauzy/src/app/pages/reports/manual-time/manual-time/manual-time.component.ts b/apps/gauzy/src/app/pages/reports/manual-time/manual-time/manual-time.component.ts index 382b2cc6244..868a374b95c 100644 --- a/apps/gauzy/src/app/pages/reports/manual-time/manual-time/manual-time.component.ts +++ b/apps/gauzy/src/app/pages/reports/manual-time/manual-time/manual-time.component.ts @@ -152,7 +152,7 @@ export class ManualTimeComponent extends BaseSelectorFilterComponent // Process the fetched logs and update the component's state this.dailyData = chain(logs) - .groupBy((log: ITimeLog) => moment(log.updatedAt).format('YYYY-MM-DD')) + .groupBy((log: ITimeLog) => moment(log.startedAt).format('YYYY-MM-DD')) .map((timeLogs, date) => ({ date, timeLogs })) .value(); } catch (error) { diff --git a/apps/gauzy/src/app/pages/teams/teams-mutation/teams-mutation.component.html b/apps/gauzy/src/app/pages/teams/teams-mutation/teams-mutation.component.html index fc00c118dc9..6f44ce851ed 100644 --- a/apps/gauzy/src/app/pages/teams/teams-mutation/teams-mutation.component.html +++ b/apps/gauzy/src/app/pages/teams/teams-mutation/teams-mutation.component.html @@ -61,16 +61,22 @@
- -
-
+ +
+
-