Compare commits
74 Commits
067ba4a548
...
88abf11a14
Author | SHA1 | Date | |
---|---|---|---|
88abf11a14 | |||
f7e5ab8937 | |||
04ce91b459 | |||
fd8e832581 | |||
fa2091069a | |||
dddd5c3aab | |||
0fc54e699f | |||
a46afff48a | |||
e202d72331 | |||
296179a10b | |||
e5bfa8afa0 | |||
338f955c78 | |||
0203c9aa20 | |||
0480481f00 | |||
4d2f291e8f | |||
77819e873d | |||
522c09c32c | |||
5865d55392 | |||
1164b4358b | |||
c04e47b10e | |||
0ad7f1662e | |||
e105a76bf2 | |||
cd7cc29afd | |||
779177d39b | |||
498492bb91 | |||
c1fe5f2884 | |||
88e0e95e9f | |||
60ceb4f4ab | |||
899909a316 | |||
400a230ded | |||
97d917ae27 | |||
04156ae37e | |||
8952ec63d7 | |||
e4d00c890a | |||
78584c0ce8 | |||
8938bd2924 | |||
287912bd81 | |||
7e6c706369 | |||
8850516693 | |||
c09f27b16f | |||
beeed6ed7c | |||
8671f4e036 | |||
9d83a95912 | |||
58f1c651b4 | |||
98c25afd9f | |||
a53f15a491 | |||
81092225cf | |||
5d439c3ad6 | |||
aff4ef4209 | |||
4a2c6a83e6 | |||
98c52e5525 | |||
00462d9ed6 | |||
4d35ee4050 | |||
53607c791e | |||
1493295654 | |||
29a05e72a2 | |||
7e4978a9e0 | |||
a6a92b64e9 | |||
7545ee2066 | |||
1f7652863b | |||
dc76cf61d9 | |||
f8a6bccf14 | |||
b1656b2858 | |||
498e0cd9d6 | |||
0f9c1c85aa | |||
cf550906a8 | |||
3a476167a4 | |||
6841494806 | |||
748ed6a34b | |||
5cc9e2c1c2 | |||
ac9ce6fc62 | |||
0daa7b200a | |||
d4d7a60d1b | |||
e0833d17f1 |
2
.dockerignore
Normal file
@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
dist
|
28
.gitea/kubernetes/backend/deployment.yaml
Normal file
@ -0,0 +1,28 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: scoresaber-reloaded-backend
|
||||
namespace: public-services
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: scoresaber-reloaded-backend
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: scoresaber-reloaded-backend
|
||||
spec:
|
||||
containers:
|
||||
- name: scoresaber-reloaded-backend-container
|
||||
image: git.fascinated.cc/fascinated/scoresaber-reloaded-backend:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
cpu: 1000m # 1 vCPU
|
||||
memory: 512Mi
|
26
.gitea/kubernetes/backend/ingress.yaml
Normal file
@ -0,0 +1,26 @@
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: scoresaber-reloaded-backend-ingress
|
||||
namespace: public-services
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: traefik-external
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
routes:
|
||||
- match: Host(`ssr.fascinated.cc`) && PathPrefix(`/api`)
|
||||
kind: Rule
|
||||
middlewares:
|
||||
- name: default-headers
|
||||
namespace: traefik
|
||||
- name: compress
|
||||
namespace: traefik
|
||||
- name: scoresaber-reloaded-backend-strip-api-prefix
|
||||
namespace: public-services
|
||||
services:
|
||||
- name: scoresaber-reloaded-backend-service
|
||||
port: 8080
|
||||
tls:
|
||||
secretName: fascinated-cc
|
13
.gitea/kubernetes/backend/service.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: scoresaber-reloaded-backend-service
|
||||
namespace: public-services
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 8080
|
||||
selector:
|
||||
app: scoresaber-reloaded-backend
|
10
.gitea/kubernetes/backend/strip-api-prefix-middleware.yaml
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: Middleware
|
||||
metadata:
|
||||
name: scoresaber-reloaded-backend-strip-api-prefix
|
||||
namespace: public-services
|
||||
spec:
|
||||
stripPrefix:
|
||||
prefixes:
|
||||
- "/api"
|
@ -1,21 +1,21 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: scoresaber-reloaded-frontend
|
||||
name: scoresaber-reloaded-website
|
||||
namespace: public-services
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: scoresaber-reloaded-frontend
|
||||
app: scoresaber-reloaded-website
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: scoresaber-reloaded-frontend
|
||||
app: scoresaber-reloaded-website
|
||||
spec:
|
||||
containers:
|
||||
- name: scoresaber-reloaded-frontend-container
|
||||
image: git.fascinated.cc/fascinated/scoresaber-reloaded-frontend:latest
|
||||
- name: scoresaber-reloaded-website-container
|
||||
image: git.fascinated.cc/fascinated/scoresaber-reloaded-website:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 3000
|
@ -2,7 +2,7 @@
|
||||
apiVersion: traefik.io/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: scoresaber-reloaded-frontend-ingress
|
||||
name: scoresaber-reloaded-website-ingress
|
||||
namespace: public-services
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: traefik-external
|
||||
@ -18,7 +18,7 @@ spec:
|
||||
- name: compress
|
||||
namespace: traefik
|
||||
services:
|
||||
- name: scoresaber-reloaded-frontend-service
|
||||
- name: scoresaber-reloaded-website-service
|
||||
port: 3000
|
||||
tls:
|
||||
secretName: fascinated-cc
|
@ -3,7 +3,7 @@ apiVersion: bitnami.com/v1alpha1
|
||||
kind: SealedSecret
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: ssr-frontend-secret
|
||||
name: ssr-secret
|
||||
namespace: public-services
|
||||
spec:
|
||||
encryptedData:
|
||||
@ -15,6 +15,6 @@ spec:
|
||||
template:
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: ssr-frontend-secret
|
||||
name: ssr-secret
|
||||
namespace: public-services
|
||||
type: Opaque
|
@ -2,7 +2,7 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: scoresaber-reloaded-frontend-service
|
||||
name: scoresaber-reloaded-website-service
|
||||
namespace: public-services
|
||||
spec:
|
||||
type: ClusterIP
|
||||
@ -10,4 +10,4 @@ spec:
|
||||
- port: 3000
|
||||
targetPort: 3000
|
||||
selector:
|
||||
app: scoresaber-reloaded-frontend
|
||||
app: scoresaber-reloaded-website
|
63
.gitea/workflows/deploy-backend.yml
Normal file
@ -0,0 +1,63 @@
|
||||
name: "Deploy Backend"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- backend/**
|
||||
- common/**
|
||||
- .gitea/kubernetes/backend/**
|
||||
- .gitea/workflows/deploy-backend.yml
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||
registry: git.fascinated.cc
|
||||
|
||||
- name: Build Image
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./backend/Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
git.fascinated.cc/fascinated/scoresaber-reloaded-backend:${{ github.sha }}
|
||||
git.fascinated.cc/fascinated/scoresaber-reloaded-backend:latest
|
||||
build-args: |
|
||||
GIT_REV=${{ gitea.sha }}
|
||||
|
||||
- name: Install kubectl
|
||||
uses: azure/setup-kubectl@v4
|
||||
id: install
|
||||
|
||||
- name: Setup Kubernetes Context
|
||||
uses: azure/k8s-set-context@v4
|
||||
with:
|
||||
kubeconfig: ${{ secrets.KUBECONFIG }}
|
||||
|
||||
- name: Deploy to Kubernetes
|
||||
uses: Azure/k8s-deploy@v5
|
||||
with:
|
||||
action: deploy
|
||||
namespace: public-services
|
||||
manifests: |
|
||||
.gitea/kubernetes/backend/deployment.yaml
|
||||
.gitea/kubernetes/backend/service.yaml
|
||||
.gitea/kubernetes/backend/strip-api-prefix-middleware.yaml
|
||||
.gitea/kubernetes/backend/ingress.yaml
|
||||
images: |
|
||||
git.fascinated.cc/fascinated/scoresaber-reloaded-backend:${{ github.sha }}
|
@ -1,9 +1,15 @@
|
||||
name: "Deploy Frontend"
|
||||
name: "Deploy Website"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- website/**
|
||||
- common/**
|
||||
- .gitea/kubernetes/website/**
|
||||
- .gitea/workflows/deploy-website.yml
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
@ -26,11 +32,11 @@ jobs:
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./apps/frontend/Dockerfile
|
||||
file: ./website/Dockerfile
|
||||
push: true
|
||||
tags: |
|
||||
git.fascinated.cc/fascinated/scoresaber-reloaded-frontend:${{ github.sha }}
|
||||
git.fascinated.cc/fascinated/scoresaber-reloaded-frontend:latest
|
||||
git.fascinated.cc/fascinated/scoresaber-reloaded-website:${{ github.sha }}
|
||||
git.fascinated.cc/fascinated/scoresaber-reloaded-website:latest
|
||||
build-args: |
|
||||
GIT_REV=${{ gitea.sha }}
|
||||
SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
|
||||
@ -50,9 +56,9 @@ jobs:
|
||||
action: deploy
|
||||
namespace: public-services
|
||||
manifests: |
|
||||
.gitea/kubernetes/frontend/sealed-secrets.yaml
|
||||
.gitea/kubernetes/frontend/deployment.yaml
|
||||
.gitea/kubernetes/frontend/service.yaml
|
||||
.gitea/kubernetes/frontend/ingress.yaml
|
||||
.gitea/kubernetes/website/sealed-secrets.yaml
|
||||
.gitea/kubernetes/website/deployment.yaml
|
||||
.gitea/kubernetes/website/service.yaml
|
||||
.gitea/kubernetes/website/ingress.yaml
|
||||
images: |
|
||||
git.fascinated.cc/fascinated/scoresaber-reloaded-frontend:${{ github.sha }}
|
||||
git.fascinated.cc/fascinated/scoresaber-reloaded-website:${{ github.sha }}
|
107
.gitignore
vendored
@ -1,38 +1,79 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
lib-cov
|
||||
coverage
|
||||
*.lcov
|
||||
.nyc_output
|
||||
.grunt
|
||||
bower_components
|
||||
.lock-wscript
|
||||
build/Release
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
web_modules/
|
||||
*.tsbuildinfo
|
||||
.npm
|
||||
.eslintcache
|
||||
.stylelintcache
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
.node_repl_history
|
||||
*.tgz
|
||||
.yarn-integrity
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
.cache
|
||||
.parcel-cache
|
||||
.next
|
||||
out
|
||||
.nuxt
|
||||
dist
|
||||
.cache/
|
||||
.vuepress/dist
|
||||
.temp
|
||||
.docusaurus
|
||||
.serverless/
|
||||
.fusebox/
|
||||
.dynamodb/
|
||||
.tern-port
|
||||
.vscode-test
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
.DS_*
|
||||
**/*.backup.*
|
||||
**/*.back.*
|
||||
node_modules
|
||||
*.sublime*
|
||||
psd
|
||||
thumb
|
||||
sketch
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
/coverage
|
||||
/.next/
|
||||
/out/
|
||||
/build
|
||||
.DS_Store
|
||||
*.pem
|
||||
.env*.local
|
||||
.vercel
|
||||
next-env.d.ts
|
||||
.turbo
|
||||
|
||||
.idea
|
@ -1,7 +0,0 @@
|
||||
NEXT_PUBLIC_SITE_URL=http://localhost:3000
|
||||
NEXT_PUBLIC_TRIGGER_PUBLIC_API_KEY=
|
||||
|
||||
TRIGGER_API_KEY=
|
||||
TRIGGER_API_URL=https://trigger.example.com
|
||||
MONGO_URI=mongodb://root:jGZuYukpb9n4yDJJE8nMeUbj2ACE7DR3@10.0.50.37:27017/ssr-dev?authSource=admin
|
||||
SENTRY_AUTH_TOKEN=
|
@ -1,65 +0,0 @@
|
||||
FROM fascinated/docker-images:nodejs_20_with_pnpm AS base
|
||||
|
||||
FROM base AS builder
|
||||
RUN apk update
|
||||
RUN apk add --no-cache libc6-compat
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
RUN pnpm i -g turbo@^2
|
||||
COPY . .
|
||||
|
||||
# Generate a partial monorepo with a pruned lockfile for a target workspace.
|
||||
# Assuming "frontend" is the name entered in the project's package.json: { name: "frontend" }
|
||||
RUN turbo prune frontend --docker
|
||||
|
||||
# Add lockfile and package.json's of isolated subworkspace
|
||||
FROM base AS installer
|
||||
WORKDIR /app
|
||||
|
||||
# Add the commit hash
|
||||
ARG GIT_REV
|
||||
ENV GIT_REV=${GIT_REV}
|
||||
|
||||
# Add the sentry auth token
|
||||
ARG SENTRY_AUTH_TOKEN
|
||||
ENV SENTRY_AUTH_TOKEN=${SENTRY_AUTH_TOKEN}
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
RUN pnpm i -g turbo@^2
|
||||
|
||||
# First install the dependencies (as they change less often)
|
||||
COPY --from=builder /app/out/json/ .
|
||||
RUN pnpm install
|
||||
|
||||
# Build the project
|
||||
COPY --from=builder /app/out/full/ .
|
||||
|
||||
RUN ls -la
|
||||
|
||||
RUN pnpm turbo run build --filter=frontend...
|
||||
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
|
||||
# Add the commit hash
|
||||
ARG GIT_REV
|
||||
ENV GIT_REV=${GIT_REV}
|
||||
|
||||
# Don't run production as root
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
USER nextjs
|
||||
|
||||
# Automatically leverage output traces to reduce image size
|
||||
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/frontend/.next/standalone ./
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/frontend/.next/static ./apps/frontend/.next/static
|
||||
COPY --from=installer --chown=nextjs:nodejs /app/apps/frontend/public ./apps/frontend/public
|
||||
|
||||
CMD node apps/frontend/server.js
|
@ -1,32 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"plugins": [{ "name": "next" }],
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"incremental": true,
|
||||
"esModuleInterop": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "Bundler",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve",
|
||||
"composite": false,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": false,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"preserveWatchOutput": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*.ts", "./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "tailwind.config.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
{
|
||||
"extends": ["//"],
|
||||
"tasks": {
|
||||
"build": {
|
||||
"outputs": [".next/**", "!.next/cache/**"]
|
||||
}
|
||||
}
|
||||
}
|
2
backend/.dockerignore
Normal file
@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
dist
|
25
backend/.eslintrc.js
Normal file
@ -0,0 +1,25 @@
|
||||
module.exports = {
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
project: 'tsconfig.json',
|
||||
tsconfigRootDir: __dirname,
|
||||
sourceType: 'module',
|
||||
},
|
||||
plugins: ['@typescript-eslint/eslint-plugin'],
|
||||
extends: [
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:prettier/recommended',
|
||||
],
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
jest: true,
|
||||
},
|
||||
ignorePatterns: ['.eslintrc.js'],
|
||||
rules: {
|
||||
'@typescript-eslint/interface-name-prefix': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
'@typescript-eslint/no-explicit-any': 'off',
|
||||
},
|
||||
};
|
31
backend/Dockerfile
Normal file
@ -0,0 +1,31 @@
|
||||
FROM node:20-alpine3.17
|
||||
|
||||
# Install pnpm globally
|
||||
RUN npm install -g pnpm
|
||||
ENV PNPM_HOME=/usr/local/bin
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
ARG GIT_REV
|
||||
ENV GIT_REV=${GIT_REV}
|
||||
|
||||
# Copy necessary files for installation
|
||||
COPY package.json* pnpm-lock.yaml* pnpm-workspace.yaml* ./
|
||||
COPY common ./common
|
||||
COPY backend ./backend
|
||||
|
||||
# Install all dependencies (for common and backend)
|
||||
RUN pnpm install
|
||||
|
||||
# Run in production mode
|
||||
ENV NODE_ENV=production
|
||||
|
||||
# Build the common workspace first, then the backend
|
||||
RUN pnpm --filter ...common build
|
||||
RUN pnpm --filter ...backend build
|
||||
|
||||
# Expose the port your application runs on
|
||||
EXPOSE 8080
|
||||
|
||||
# Command to run your app
|
||||
CMD ["node", "backend/dist/main.js"]
|
8
backend/nest-cli.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/nest-cli",
|
||||
"collection": "@nestjs/schematics",
|
||||
"sourceRoot": "src",
|
||||
"compilerOptions": {
|
||||
"deleteOutDir": true
|
||||
}
|
||||
}
|
44
backend/package.json
Normal file
@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "backend",
|
||||
"version": "1.0.0",
|
||||
"author": "fascinated7",
|
||||
"license": "MIT",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "nest start --watch --webpack webpack-hmr.config.js",
|
||||
"build": "nest build",
|
||||
"start": "nest start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fastify/one-line-logger": "^2.0.0",
|
||||
"@nestjs/common": "^10.0.0",
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@nestjs/platform-fastify": "^10.4.4",
|
||||
"@ssr/common": "workspace:*",
|
||||
"reflect-metadata": "^0.2.0",
|
||||
"rxjs": "^7.8.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nestjs/cli": "^10.0.0",
|
||||
"@nestjs/schematics": "^10.0.0",
|
||||
"@nestjs/testing": "^10.0.0",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/node": "^20.3.1",
|
||||
"@types/supertest": "^6.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"concurrently": "^9.0.1",
|
||||
"eslint": "^8.42.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"nodemon": "^3.0.0",
|
||||
"prettier": "^3.0.0",
|
||||
"source-map-support": "^0.5.21",
|
||||
"supertest": "^7.0.0",
|
||||
"ts-loader": "^9.4.3",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsup": "^8.3.0",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
12
backend/src/app.module.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { AppController } from "./controller/app.controller";
|
||||
import { PlayerService } from "./service/player.service";
|
||||
import { PlayerController } from "./controller/player.controller";
|
||||
import { AppService } from "./service/app.service";
|
||||
|
||||
@Module({
|
||||
imports: [],
|
||||
controllers: [AppController, PlayerController],
|
||||
providers: [AppService, PlayerService],
|
||||
})
|
||||
export class AppModule {}
|
15
backend/src/controller/app.controller.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Controller, Get } from "@nestjs/common";
|
||||
import { AppService } from "../service/app.service";
|
||||
|
||||
@Controller()
|
||||
export class AppController {
|
||||
constructor(private readonly appService: AppService) {}
|
||||
|
||||
@Get("/")
|
||||
getHome() {
|
||||
return {
|
||||
message: "ScoreSaber Reloaded API",
|
||||
version: this.appService.getVersion(),
|
||||
};
|
||||
}
|
||||
}
|
12
backend/src/controller/player.controller.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { Controller, Get, Param } from "@nestjs/common";
|
||||
import { PlayerService } from "../service/player.service";
|
||||
|
||||
@Controller("/player")
|
||||
export class PlayerController {
|
||||
constructor(private readonly playerService: PlayerService) {}
|
||||
|
||||
@Get("/history/:id")
|
||||
getHistory(@Param("id") id: string) {
|
||||
return this.playerService.getHistory(id);
|
||||
}
|
||||
}
|
21
backend/src/main.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { NestFactory } from "@nestjs/core";
|
||||
import { FastifyAdapter, NestFastifyApplication } from "@nestjs/platform-fastify";
|
||||
import { AppModule } from "./app.module";
|
||||
|
||||
async function bootstrap() {
|
||||
const app = await NestFactory.create<NestFastifyApplication>(
|
||||
AppModule,
|
||||
new FastifyAdapter({
|
||||
logger: {
|
||||
transport: {
|
||||
target: "@fastify/one-line-logger",
|
||||
},
|
||||
},
|
||||
}),
|
||||
{
|
||||
logger: ["error", "warn", "log"],
|
||||
}
|
||||
);
|
||||
await app.listen(8080, "0.0.0.0");
|
||||
}
|
||||
bootstrap();
|
14
backend/src/service/app.service.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { isProduction } from "@ssr/common/dist";
|
||||
|
||||
@Injectable()
|
||||
export class AppService {
|
||||
/**
|
||||
* Gets the app version.
|
||||
*
|
||||
* @returns the app version
|
||||
*/
|
||||
getVersion(): string {
|
||||
return `1.0.0-${isProduction() ? process.env.GIT_REV.substring(0, 7) : "dev"}`;
|
||||
}
|
||||
}
|
16
backend/src/service/player.service.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
@Injectable()
|
||||
export class PlayerService {
|
||||
/**
|
||||
* Gets the statistic history for the given player
|
||||
*
|
||||
* @param id the id of the player
|
||||
* @returns the players statistic history
|
||||
*/
|
||||
getHistory(id: string) {
|
||||
return {
|
||||
id: id,
|
||||
};
|
||||
}
|
||||
}
|
4
backend/tsconfig.build.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
|
||||
}
|
21
backend/tsconfig.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "ES2021",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": false,
|
||||
"noImplicitAny": false,
|
||||
"strictBindCallApply": false,
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"noFallthroughCasesInSwitch": false
|
||||
}
|
||||
}
|
6
backend/webpack-hmr.config.js
Normal file
@ -0,0 +1,6 @@
|
||||
module.exports = function (options) {
|
||||
return {
|
||||
...options,
|
||||
stats: "minimal", // This disables the full-screen mode and simplifies the output
|
||||
};
|
||||
};
|
2
common/.dockerignore
Normal file
@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
dist
|
13
common/package.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "@ssr/common",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"dev": "tsup src/index.ts --watch",
|
||||
"build": "tsup src/index.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.7.4",
|
||||
"tsup": "^6.5.0",
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
1
common/src/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from "src/utils";
|
6
common/src/utils.ts
Normal file
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Checks if we're in production
|
||||
*/
|
||||
export function isProduction() {
|
||||
return process.env.NODE_ENV === "production";
|
||||
}
|
21
common/tsconfig.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"target": "ES2021",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": false,
|
||||
"noImplicitAny": false,
|
||||
"strictBindCallApply": false,
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"noFallthroughCasesInSwitch": false
|
||||
}
|
||||
}
|
9
common/tsup.config.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { defineConfig } from "tsup";
|
||||
|
||||
export default defineConfig({
|
||||
entry: ["src/index.ts"],
|
||||
splitting: false,
|
||||
sourcemap: true,
|
||||
clean: true,
|
||||
dts: true, // This line enables type declaration file generation
|
||||
});
|
29
package.json
@ -1,22 +1,15 @@
|
||||
{
|
||||
"name": "ssr",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"packages/*"
|
||||
],
|
||||
"name": "scoresaber-reloadedv3",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "turbo run build",
|
||||
"clean": "turbo run clean",
|
||||
"dev": "turbo run dev",
|
||||
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
|
||||
"lint": "turbo run lint",
|
||||
"test": "turbo run test"
|
||||
"dev": "pnpm --parallel --workspace-concurrency=4 run -r dev",
|
||||
|
||||
"build:website": "pnpm --filter website build",
|
||||
"build:backend": "pnpm --filter backend build",
|
||||
|
||||
"start:website": "pnpm --filter website start",
|
||||
"start:backend": "pnpm --filter backend start"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^3.2.5",
|
||||
"turbo": "^2.0.3"
|
||||
},
|
||||
"packageManager": "pnpm@9.12.0"
|
||||
"author": "fascinated7",
|
||||
"license": "MIT"
|
||||
}
|
||||
|
3571
pnpm-lock.yaml
generated
@ -1,3 +1,4 @@
|
||||
packages:
|
||||
- "apps/*"
|
||||
- "packages/*"
|
||||
- "common"
|
||||
- "website"
|
||||
- "backend"
|
||||
|
17
turbo.json
@ -1,17 +0,0 @@
|
||||
{
|
||||
"$schema": "https://turbo.build/schema.json",
|
||||
"tasks": {
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
"inputs": ["$TURBO_DEFAULT$", ".env*"],
|
||||
"outputs": [".next/**", "!.next/cache/**"]
|
||||
},
|
||||
"lint": {
|
||||
"dependsOn": ["^lint"]
|
||||
},
|
||||
"dev": {
|
||||
"cache": false,
|
||||
"persistent": true
|
||||
}
|
||||
}
|
||||
}
|
2
website/.dockerignore
Normal file
@ -0,0 +1,2 @@
|
||||
node_modules
|
||||
dist
|
@ -2,7 +2,7 @@
|
||||
"extends": ["next/core-web-vitals", "next/typescript"],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": "off",
|
||||
"@typescript-eslint/no-empty-object-type": "off",
|
||||
"@typescript-eslint/no-unused-expressions": "off"
|
||||
"@typescript-eslint/no-unused-expressions": "off",
|
||||
"@typescript-eslint/no-empty-object-type": "off"
|
||||
}
|
||||
}
|
25
website/Dockerfile
Normal file
@ -0,0 +1,25 @@
|
||||
FROM node:20-alpine3.17 AS base
|
||||
|
||||
# Install pnpm
|
||||
RUN npm install -g pnpm
|
||||
ENV PNPM_HOME=/usr/local/bin
|
||||
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
|
||||
# Copy website package and lock files only
|
||||
COPY package.json* pnpm-lock.yaml* pnpm-workspace.yaml* ./
|
||||
COPY website ./website
|
||||
|
||||
ARG GIT_REV
|
||||
ENV GIT_REV=${GIT_REV}
|
||||
|
||||
RUN pnpm install --filter website
|
||||
RUN pnpm run build:website
|
||||
|
||||
# Expose the app port and start it
|
||||
EXPOSE 3000
|
||||
ENV HOSTNAME="0.0.0.0"
|
||||
ENV PORT=3000
|
||||
|
||||
CMD ["pnpm", "start:website"]
|
@ -1,18 +1,8 @@
|
||||
import { withSentryConfig } from "@sentry/nextjs";
|
||||
import { format } from "@formkit/tempo";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url); // get the resolved path to the file
|
||||
const __dirname = path.dirname(__filename); // get the name of the directory
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
output: "standalone",
|
||||
webpack: (config) => {
|
||||
config.resolve.alias['@'] = path.join(__dirname, 'src');
|
||||
return config;
|
||||
},
|
||||
images: {
|
||||
remotePatterns: [
|
||||
{
|
||||
@ -24,8 +14,7 @@ const nextConfig = {
|
||||
],
|
||||
},
|
||||
env: {
|
||||
NEXT_PUBLIC_BUILD_ID:
|
||||
process.env.GIT_REV || "dev",
|
||||
NEXT_PUBLIC_BUILD_ID: process.env.GIT_REV || "dev",
|
||||
NEXT_PUBLIC_BUILD_TIME: new Date().toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "long",
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"name": "website",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
@ -8,10 +8,6 @@
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
"imports": {
|
||||
"@/*": "./src/*"
|
||||
},
|
||||
"packageManager": "pnpm@9.12.0",
|
||||
"dependencies": {
|
||||
"@formkit/tempo": "^0.1.2",
|
||||
"@heroicons/react": "^2.1.5",
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 841 B After Width: | Height: | Size: 841 B |
Before Width: | Height: | Size: 132 B After Width: | Height: | Size: 132 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 766 B After Width: | Height: | Size: 766 B |
Before Width: | Height: | Size: 659 B After Width: | Height: | Size: 659 B |
Before Width: | Height: | Size: 604 B After Width: | Height: | Size: 604 B |
Before Width: | Height: | Size: 121 B After Width: | Height: | Size: 121 B |
Before Width: | Height: | Size: 522 B After Width: | Height: | Size: 522 B |
Before Width: | Height: | Size: 445 B After Width: | Height: | Size: 445 B |
Before Width: | Height: | Size: 320 B After Width: | Height: | Size: 320 B |
Before Width: | Height: | Size: 909 B After Width: | Height: | Size: 909 B |
Before Width: | Height: | Size: 109 B After Width: | Height: | Size: 109 B |
Before Width: | Height: | Size: 554 B After Width: | Height: | Size: 554 B |
Before Width: | Height: | Size: 311 B After Width: | Height: | Size: 311 B |
Before Width: | Height: | Size: 179 B After Width: | Height: | Size: 179 B |
Before Width: | Height: | Size: 214 B After Width: | Height: | Size: 214 B |
Before Width: | Height: | Size: 339 B After Width: | Height: | Size: 339 B |
Before Width: | Height: | Size: 324 B After Width: | Height: | Size: 324 B |
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 282 B |
Before Width: | Height: | Size: 127 B After Width: | Height: | Size: 127 B |
Before Width: | Height: | Size: 254 B After Width: | Height: | Size: 254 B |
Before Width: | Height: | Size: 105 B After Width: | Height: | Size: 105 B |
Before Width: | Height: | Size: 326 B After Width: | Height: | Size: 326 B |
Before Width: | Height: | Size: 651 B After Width: | Height: | Size: 651 B |
Before Width: | Height: | Size: 127 B After Width: | Height: | Size: 127 B |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 132 B After Width: | Height: | Size: 132 B |
Before Width: | Height: | Size: 810 B After Width: | Height: | Size: 810 B |
Before Width: | Height: | Size: 792 B After Width: | Height: | Size: 792 B |
Before Width: | Height: | Size: 287 B After Width: | Height: | Size: 287 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 206 B After Width: | Height: | Size: 206 B |
Before Width: | Height: | Size: 139 B After Width: | Height: | Size: 139 B |
Before Width: | Height: | Size: 377 B After Width: | Height: | Size: 377 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 359 B After Width: | Height: | Size: 359 B |
Before Width: | Height: | Size: 561 B After Width: | Height: | Size: 561 B |
Before Width: | Height: | Size: 523 B After Width: | Height: | Size: 523 B |
Before Width: | Height: | Size: 286 B After Width: | Height: | Size: 286 B |
Before Width: | Height: | Size: 344 B After Width: | Height: | Size: 344 B |
Before Width: | Height: | Size: 135 B After Width: | Height: | Size: 135 B |
Before Width: | Height: | Size: 123 B After Width: | Height: | Size: 123 B |
Before Width: | Height: | Size: 717 B After Width: | Height: | Size: 717 B |
Before Width: | Height: | Size: 263 B After Width: | Height: | Size: 263 B |
Before Width: | Height: | Size: 215 B After Width: | Height: | Size: 215 B |
Before Width: | Height: | Size: 286 B After Width: | Height: | Size: 286 B |
Before Width: | Height: | Size: 135 B After Width: | Height: | Size: 135 B |