mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-10 04:22:27 +10:00
chore(server): update dependencies and add API tags to
controllers
This commit is contained in:
63
.env.example
Normal file
63
.env.example
Normal file
@ -0,0 +1,63 @@
|
||||
# Environment
|
||||
NODE_ENV=development
|
||||
|
||||
# Ports
|
||||
PORT=3000
|
||||
|
||||
# Client Port & URL (for development)
|
||||
__DEV__CLIENT_PORT=5173 # Only used in development
|
||||
__DEV__CLIENT_URL=http://localhost:5173 # Only used in development
|
||||
|
||||
# URLs
|
||||
PUBLIC_URL=http://localhost:3000 # This must reference a publicly accessible domain or IP address, not a docker container ID
|
||||
STORAGE_URL=http://localhost:9000 # This must reference a publicly accessible domain or IP address, not a docker container ID
|
||||
CHROME_URL=ws://localhost:8080
|
||||
|
||||
# Database (Prisma/PostgreSQL)
|
||||
# This can be swapped out to use any other database, like MySQL
|
||||
# Note: This is used only in the compose.yml file
|
||||
POSTGRES_PORT=5432
|
||||
POSTGRES_DB=postgres
|
||||
POSTGRES_USER=postgres
|
||||
POSTGRES_PASSWORD=postgres
|
||||
|
||||
# Database (Prisma/PostgreSQL)
|
||||
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres?schema=public
|
||||
|
||||
# Authentication Secrets
|
||||
# generated with `openssl rand -base64 64`
|
||||
ACCESS_TOKEN_SECRET=access_token_secret
|
||||
REFRESH_TOKEN_SECRET=refresh_token_secret
|
||||
|
||||
# Chrome Browser (for printing)
|
||||
# generated with `openssl rand -hex 32`
|
||||
CHROME_PORT=8080
|
||||
CHROME_TOKEN=chrome_token
|
||||
|
||||
# Mail Server (for e-mails)
|
||||
# For testing, you can use https://ethereal.email/create
|
||||
# SMTP_URL=smtp://username:password@smtp.ethereal.email:587
|
||||
|
||||
# Storage
|
||||
STORAGE_ENDPOINT=localhost
|
||||
STORAGE_PORT=9000
|
||||
STORAGE_REGION=us-east-1
|
||||
STORAGE_BUCKET=default
|
||||
STORAGE_ACCESS_KEY=minioadmin
|
||||
STORAGE_SECRET_KEY=minioadmin
|
||||
|
||||
# Redis (for cache & server session management)
|
||||
REDIS_URL=redis://default:password@localhost:6379
|
||||
|
||||
# Sentry (for error reporting, Optional)
|
||||
# SENTRY_DSN=
|
||||
|
||||
# GitHub (OAuth, Optional)
|
||||
GITHUB_CLIENT_ID=
|
||||
GITHUB_CLIENT_SECRET=
|
||||
GITHUB_CALLBACK_URL=
|
||||
|
||||
# Google (OAuth, Optional)
|
||||
GOOGLE_CLIENT_ID=
|
||||
GOOGLE_CLIENT_SECRET=
|
||||
GOOGLE_CALLBACK_URL=
|
||||
25
.github/workflows/publish-docker-image.yml
vendored
25
.github/workflows/publish-docker-image.yml
vendored
@ -33,8 +33,7 @@ jobs:
|
||||
|
||||
- name: Extract version from package.json
|
||||
id: version
|
||||
run: |
|
||||
echo "version=$(jq -r '.version' package.json)" >> "$GITHUB_OUTPUT"
|
||||
run: echo "version=$(jq -r '.version' package.json)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3.0.0
|
||||
@ -48,6 +47,13 @@ jobs:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Login to Quay.io
|
||||
uses: docker/login-action@v3.0.0
|
||||
with:
|
||||
registry: quay.io
|
||||
username: ${{ secrets.QUAY_USERNAME }}
|
||||
password: ${{ secrets.QUAY_PASSWORD }}
|
||||
|
||||
- name: Login to GitHub Container Registery
|
||||
uses: docker/login-action@v3.0.0
|
||||
with:
|
||||
@ -59,8 +65,10 @@ jobs:
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5.0.0
|
||||
with:
|
||||
images: ${{ env.IMAGE }}
|
||||
tags: type=semver,pattern={{version}},prefix=v,value=${{ steps.version.outputs.version }}
|
||||
images: |
|
||||
${{ env.IMAGE }}
|
||||
ghcr.io/${{ env.IMAGE }}
|
||||
|
||||
- name: Build and Push by Digest
|
||||
uses: docker/build-push-action@v5.0.0
|
||||
@ -112,8 +120,10 @@ jobs:
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5.0.0
|
||||
with:
|
||||
images: ${{ env.IMAGE }}
|
||||
tags: type=semver,pattern={{version}},prefix=v,value=${{ needs.build.outputs.version }}
|
||||
images: |
|
||||
${{ env.IMAGE }}
|
||||
ghcr.io/${{ env.IMAGE }}
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3.0.0
|
||||
@ -121,6 +131,13 @@ jobs:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
|
||||
- name: Login to Quay.io
|
||||
uses: docker/login-action@v3.0.0
|
||||
with:
|
||||
registry: quay.io
|
||||
username: ${{ secrets.QUAY_USERNAME }}
|
||||
password: ${{ secrets.QUAY_PASSWORD }}
|
||||
|
||||
- name: Login to GitHub Container Registery
|
||||
uses: docker/login-action@v3.0.0
|
||||
with:
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -42,4 +42,5 @@ stats.html
|
||||
libs/prisma
|
||||
|
||||
# Environment Variables
|
||||
*.env*
|
||||
*.env*
|
||||
!.env.example
|
||||
@ -1,5 +1,6 @@
|
||||
import { CacheInterceptor, CacheKey, CacheTTL } from "@nestjs/cache-manager";
|
||||
import { Controller, Get, NotFoundException, UseInterceptors } from "@nestjs/common";
|
||||
import { ApiTags } from "@nestjs/swagger";
|
||||
import { HealthCheck, HealthCheckService } from "@nestjs/terminus";
|
||||
import { RedisService } from "@songkeys/nestjs-redis";
|
||||
import { RedisHealthIndicator } from "@songkeys/nestjs-redis-health";
|
||||
@ -9,6 +10,7 @@ import { BrowserHealthIndicator } from "./browser.health";
|
||||
import { DatabaseHealthIndicator } from "./database.health";
|
||||
import { StorageHealthIndicator } from "./storage.health";
|
||||
|
||||
@ApiTags("Health")
|
||||
@Controller("health")
|
||||
export class HealthController {
|
||||
constructor(
|
||||
|
||||
@ -7,12 +7,14 @@ import {
|
||||
UseInterceptors,
|
||||
} from "@nestjs/common";
|
||||
import { FileInterceptor } from "@nestjs/platform-express";
|
||||
import { ApiTags } from "@nestjs/swagger";
|
||||
|
||||
import { TwoFactorGuard } from "@/server/auth/guards/two-factor.guard";
|
||||
import { User } from "@/server/user/decorators/user.decorator";
|
||||
|
||||
import { StorageService } from "./storage.service";
|
||||
|
||||
@ApiTags("Storage")
|
||||
@Controller("storage")
|
||||
export class StorageController {
|
||||
constructor(private readonly storageService: StorageService) {}
|
||||
|
||||
@ -164,7 +164,7 @@
|
||||
"@songkeys/nestjs-redis": "^10.0.0",
|
||||
"@songkeys/nestjs-redis-health": "^10.0.0",
|
||||
"@swc/helpers": "~0.5.3",
|
||||
"@tanstack/react-query": "^5.7.1",
|
||||
"@tanstack/react-query": "^5.7.2",
|
||||
"@tiptap/extension-highlight": "^2.1.12",
|
||||
"@tiptap/extension-image": "^2.1.12",
|
||||
"@tiptap/extension-link": "^2.1.12",
|
||||
|
||||
14
pnpm-lock.yaml
generated
14
pnpm-lock.yaml
generated
@ -153,8 +153,8 @@ dependencies:
|
||||
specifier: ~0.5.3
|
||||
version: 0.5.3
|
||||
'@tanstack/react-query':
|
||||
specifier: ^5.7.1
|
||||
version: 5.7.1(react-dom@18.2.0)(react@18.2.0)
|
||||
specifier: ^5.7.2
|
||||
version: 5.7.2(react-dom@18.2.0)(react@18.2.0)
|
||||
'@tiptap/extension-highlight':
|
||||
specifier: ^2.1.12
|
||||
version: 2.1.12(@tiptap/core@2.1.12)
|
||||
@ -6381,12 +6381,12 @@ packages:
|
||||
- typescript
|
||||
dev: true
|
||||
|
||||
/@tanstack/query-core@5.4.3:
|
||||
resolution: {integrity: sha512-fnI9ORjcuLGm1sNrKatKIosRQUpuqcD4SV7RqRSVmj8JSicX2aoMyKryHEBpVQvf6N4PaBVgBxQomjsbsGPssQ==}
|
||||
/@tanstack/query-core@5.7.2:
|
||||
resolution: {integrity: sha512-vPYoNCOI8W+jFLnyEAYQL7/qURE7XzVE/TvkmNSko8LU55jFshee342p4GNFOTsYFgJty7Da5bw4m2P3vaKWMw==}
|
||||
dev: false
|
||||
|
||||
/@tanstack/react-query@5.7.1(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-7onwx519jOKh7/nspf70dOSejJSYfhFRnVsSicuPrmO8L6Iw05G1wwDpp1PjqFLsm7suixlHDXhcNfK0sy0kWg==}
|
||||
/@tanstack/react-query@5.7.2(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-NMsfz0Wd3VPDvSpX9sw2x07r0kf9HwuAlNNHQvwMUHM7EcuVN/LYmlmTe40dWER1c/92Jhc5LODdtW0PyvHsFg==}
|
||||
peerDependencies:
|
||||
react: ^18.0.0
|
||||
react-dom: ^18.0.0
|
||||
@ -6397,7 +6397,7 @@ packages:
|
||||
react-native:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@tanstack/query-core': 5.4.3
|
||||
'@tanstack/query-core': 5.7.2
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
@ -50,7 +50,7 @@ services:
|
||||
command: redis-server --requirepass password
|
||||
|
||||
app:
|
||||
image: amruthpillai/reactive-resume
|
||||
image: amruthpillai/reactive-resume:v4.0.0-alpha.0
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 3000:3000
|
||||
@ -63,19 +63,25 @@ services:
|
||||
# -- Environment Variables --
|
||||
PORT: 3000
|
||||
NODE_ENV: production
|
||||
|
||||
# -- URLs --
|
||||
PUBLIC_URL: http://localhost:3000
|
||||
STORAGE_URL: http://localhost:9000
|
||||
|
||||
# -- Printer (Chrome) --
|
||||
CHROME_URL: ws://chrome:3000
|
||||
CHROME_TOKEN: chrome_token
|
||||
|
||||
# -- Database (Postgres) --
|
||||
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres
|
||||
|
||||
# -- Auth --
|
||||
ACCESS_TOKEN_SECRET: access_token_secret
|
||||
REFRESH_TOKEN_SECRET: refresh_token_secret
|
||||
|
||||
# -- Emails --
|
||||
# SMTP_URL: smtp://user:pass@smtp:587 # Optional
|
||||
|
||||
# -- Storage (Minio) --
|
||||
STORAGE_ENDPOINT: minio
|
||||
STORAGE_PORT: 9000
|
||||
@ -83,14 +89,18 @@ services:
|
||||
STORAGE_BUCKET: default
|
||||
STORAGE_ACCESS_KEY: minioadmin
|
||||
STORAGE_SECRET_KEY: minioadmin
|
||||
|
||||
# -- Cache (Redis) --
|
||||
REDIS_URL: redis://default:password@redis:6379
|
||||
|
||||
# -- Sentry --
|
||||
# SENTRY_DSN: https://id.sentry.io # Optional
|
||||
|
||||
# -- GitHub --
|
||||
GITHUB_CLIENT_ID: github_client_id
|
||||
GITHUB_CLIENT_SECRET: github_client_secret
|
||||
GITHUB_CALLBACK_URL: http://localhost:3000/api/auth/github/callback
|
||||
|
||||
# -- Google --
|
||||
GOOGLE_CLIENT_ID: google_client_id
|
||||
GOOGLE_CLIENT_SECRET: google_client_secret
|
||||
|
||||
150
tools/compose/traefik-secure.yml
Normal file
150
tools/compose/traefik-secure.yml
Normal file
@ -0,0 +1,150 @@
|
||||
version: "3"
|
||||
|
||||
# In this Docker Compose example, we use Traefik to route requests to the app and storage containers in a secure manner (HTTPS).
|
||||
# This example assumes you have a domain name (example.com) and a wildcard DNS record pointing to your server.
|
||||
# The only exposed ports here are from Traefik (80 and 443). All non-secure requests are redirected to HTTPS.
|
||||
# Note: Please change `example.com` to your domain name where necessary.
|
||||
|
||||
services:
|
||||
# Database (Postgres)
|
||||
postgres:
|
||||
image: postgres
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_DB: postgres
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
healthcheck:
|
||||
test: ["CMD", "pg_isready -U postgres -d postgres"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
# Storage (for image uploads)
|
||||
minio:
|
||||
image: minio/minio
|
||||
restart: unless-stopped
|
||||
command: server /data
|
||||
volumes:
|
||||
- minio_data:/data
|
||||
environment:
|
||||
MINIO_ROOT_USER: minioadmin
|
||||
MINIO_ROOT_PASSWORD: minioadmin
|
||||
labels:
|
||||
- traefik.enable
|
||||
- traefik.http.routers.app.rule=Host(`storage.example.com`)
|
||||
- traefik.http.routers.app.entrypoints=websecure
|
||||
- traefik.http.routers.app.tls.certresolver=letsencrypt
|
||||
- traefik.http.services.app.loadbalancer.server.port=9000
|
||||
|
||||
# Chrome Browser (for printing and previews)
|
||||
chrome:
|
||||
image: browserless/chrome
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
TOKEN: chrome_token
|
||||
EXIT_ON_HEALTH_FAILURE: true
|
||||
PRE_REQUEST_HEALTH_CHECK: true
|
||||
|
||||
# Redis (for cache & server session management)
|
||||
redis:
|
||||
image: redis
|
||||
restart: unless-stopped
|
||||
command: redis-server --save 60 1 --loglevel warning --requirepass password
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
|
||||
app:
|
||||
image: amruthpillai/reactive-resume:v4.0.0-alpha.0
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- postgres
|
||||
- minio
|
||||
- redis
|
||||
- chrome
|
||||
environment:
|
||||
# -- Environment Variables --
|
||||
PORT: 3000
|
||||
NODE_ENV: production
|
||||
|
||||
# -- URLs --
|
||||
PUBLIC_URL: http://example.com
|
||||
STORAGE_URL: http://storage.example.com
|
||||
|
||||
# -- Printer (Chrome) --
|
||||
CHROME_URL: ws://chrome:3000
|
||||
CHROME_TOKEN: chrome_token
|
||||
|
||||
# -- Database (Postgres) --
|
||||
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres
|
||||
|
||||
# -- Auth --
|
||||
ACCESS_TOKEN_SECRET: access_token_secret
|
||||
REFRESH_TOKEN_SECRET: refresh_token_secret
|
||||
|
||||
# -- Emails --
|
||||
# SMTP_URL: smtp://user:pass@smtp:587 # Optional
|
||||
|
||||
# -- Storage (Minio) --
|
||||
STORAGE_ENDPOINT: minio
|
||||
STORAGE_PORT: 9000
|
||||
STORAGE_REGION: us-east-1 # Optional
|
||||
STORAGE_BUCKET: default
|
||||
STORAGE_ACCESS_KEY: minioadmin
|
||||
STORAGE_SECRET_KEY: minioadmin
|
||||
|
||||
# -- Cache (Redis) --
|
||||
REDIS_URL: redis://default:password@redis:6379
|
||||
|
||||
# -- Sentry --
|
||||
# SENTRY_DSN: https://id.sentry.io # Optional
|
||||
|
||||
# -- GitHub --
|
||||
GITHUB_CLIENT_ID: github_client_id
|
||||
GITHUB_CLIENT_SECRET: github_client_secret
|
||||
GITHUB_CALLBACK_URL: http://localhost:3000/api/auth/github/callback
|
||||
|
||||
# -- Google --
|
||||
GOOGLE_CLIENT_ID: google_client_id
|
||||
GOOGLE_CLIENT_SECRET: google_client_secret
|
||||
GOOGLE_CALLBACK_URL: http://localhost:3000/api/auth/google/callback
|
||||
labels:
|
||||
- traefik.enable
|
||||
- traefik.http.routers.app.rule=Host(`example.com`)
|
||||
- traefik.http.routers.app.entrypoints=websecure
|
||||
- traefik.http.routers.app.tls
|
||||
- traefik.http.routers.app.tls.certresolver=letsencrypt
|
||||
- traefik.http.services.app.loadbalancer.server.port=3000
|
||||
|
||||
traefik:
|
||||
image: traefik
|
||||
command:
|
||||
- --api
|
||||
- --providers.docker
|
||||
- --providers.docker.exposedbydefault=false
|
||||
- --entrypoints.web.address=:80
|
||||
- --entrypoints.websecure.address=:443
|
||||
- --certificatesresolvers.letsencrypt.acme.tlschallenge
|
||||
- --certificatesresolvers.letsencrypt.acme.email=noreply@example.com
|
||||
- --certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json
|
||||
|
||||
# Let's Encrypt Staging Server (for testing)
|
||||
- --certificatesResolvers.letsencrypt.acme.caServer=https://acme-staging-v02.api.letsencrypt.org/directory
|
||||
|
||||
# Redirect all HTTP requests to HTTPS
|
||||
- --entrypoints.web.http.redirections.entrypoint.to=websecure
|
||||
- --entrypoints.web.http.redirections.entrypoint.scheme=https
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
volumes:
|
||||
- letsencrypt_data:/letsencrypt
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
|
||||
volumes:
|
||||
minio_data:
|
||||
redis_data:
|
||||
postgres_data:
|
||||
letsencrypt_data:
|
||||
@ -53,7 +53,7 @@ services:
|
||||
command: redis-server --requirepass password
|
||||
|
||||
app:
|
||||
image: amruthpillai/reactive-resume
|
||||
image: amruthpillai/reactive-resume:v4.0.0-alpha.0
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- postgres
|
||||
@ -64,19 +64,25 @@ services:
|
||||
# -- Environment Variables --
|
||||
PORT: 3000
|
||||
NODE_ENV: production
|
||||
|
||||
# -- URLs --
|
||||
PUBLIC_URL: http://example.com
|
||||
STORAGE_URL: http://storage.example.com
|
||||
|
||||
# -- Printer (Chrome) --
|
||||
CHROME_URL: ws://chrome:3000
|
||||
CHROME_TOKEN: chrome_token
|
||||
|
||||
# -- Database (Postgres) --
|
||||
DATABASE_URL: postgresql://postgres:postgres@postgres:5432/postgres
|
||||
|
||||
# -- Auth --
|
||||
ACCESS_TOKEN_SECRET: access_token_secret
|
||||
REFRESH_TOKEN_SECRET: refresh_token_secret
|
||||
|
||||
# -- Emails --
|
||||
# SMTP_URL: smtp://user:pass@smtp:587 # Optional
|
||||
|
||||
# -- Storage (Minio) --
|
||||
STORAGE_ENDPOINT: minio
|
||||
STORAGE_PORT: 9000
|
||||
@ -84,14 +90,18 @@ services:
|
||||
STORAGE_BUCKET: default
|
||||
STORAGE_ACCESS_KEY: minioadmin
|
||||
STORAGE_SECRET_KEY: minioadmin
|
||||
|
||||
# -- Cache (Redis) --
|
||||
REDIS_URL: redis://default:password@redis:6379
|
||||
|
||||
# -- Sentry --
|
||||
# SENTRY_DSN: https://id.sentry.io # Optional
|
||||
|
||||
# -- GitHub --
|
||||
GITHUB_CLIENT_ID: github_client_id
|
||||
GITHUB_CLIENT_SECRET: github_client_secret
|
||||
GITHUB_CALLBACK_URL: http://localhost:3000/api/auth/github/callback
|
||||
|
||||
# -- Google --
|
||||
GOOGLE_CLIENT_ID: google_client_id
|
||||
GOOGLE_CLIENT_SECRET: google_client_secret
|
||||
|
||||
Reference in New Issue
Block a user