diff --git a/.dockerignore b/.dockerignore index ee408d8..f4dee15 100644 --- a/.dockerignore +++ b/.dockerignore @@ -8,3 +8,8 @@ frontend/build/ .git/ .agents/ .vscode/ +**/.env +**/.env.docker +**/.env.prod +**/.env.* +!**/.env.example diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml new file mode 100644 index 0000000..3cdf029 --- /dev/null +++ b/.github/workflows/docker-release.yml @@ -0,0 +1,68 @@ +name: Build and Release Docker Images + +on: + push: + tags: + - 'v*' # Memicu alur kerja setiap kali melakukan push tag seperti v1.0.0, v2.1.3, dll. + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + # Login ke GitHub Container Registry menggunakan token otomatis bawaan GitHub + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + # ─── BUILD & PUSH BACKEND ────────────────────────────────────────────────── + - name: Extract Backend Metadata + id: meta-backend + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }}-backend + tags: | + type=semver,pattern={{version}} + type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') }} + + - name: Build and Push Backend Image + uses: docker/build-push-action@v5 + with: + context: ./backend + push: true + tags: ${{ id.meta-backend.outputs.tags }} + labels: ${{ id.meta-backend.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max + + # ─── BUILD & PUSH FRONTEND ───────────────────────────────────────────────── + - name: Extract Frontend Metadata + id: meta-frontend + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository }}-frontend + tags: | + type=semver,pattern={{version}} + type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') }} + + - name: Build and Push Frontend Image + uses: docker/build-push-action@v5 + with: + context: ./frontend + push: true + tags: ${{ id.meta-frontend.outputs.tags }} + labels: ${{ id.meta-frontend.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/.github/workflows/eslint.yml b/.github/workflows/eslint.yml index 222c372..2ff8b7c 100644 --- a/.github/workflows/eslint.yml +++ b/.github/workflows/eslint.yml @@ -30,24 +30,30 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Install ESLint - run: | - npm install eslint@8.10.0 - npm install @microsoft/eslint-formatter-sarif@3.1.0 + - name: Setup pnpm + uses: pnpm/action-setup@v3 + with: + version: 11 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + cache-dependency-path: backend/pnpm-lock.yaml + + - name: Install dependencies + run: pnpm install --frozen-lockfile + working-directory: backend - name: Run ESLint env: SARIF_ESLINT_IGNORE_SUPPRESSED: "true" - # fix: Menambahkan backslash (\) untuk menyambung perintah ke baris berikutnya - run: npx eslint . \ - --config .eslintrc.js \ - --ext .js,.jsx,.ts,.tsx \ - --format @microsoft/eslint-formatter-sarif \ - --output-file eslint-results.sarif + run: pnpm exec eslint "{src,apps,libs,test}/**/*.ts" --format @microsoft/eslint-formatter-sarif --output-file ../eslint-results.sarif + working-directory: backend continue-on-error: true - name: Upload analysis results to GitHub - # fix: Mengubah versi v3 menjadi v4 sesuai instruksi peringatan uses: github/codeql-action/upload-sarif@v4 with: sarif_file: eslint-results.sarif diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..b720b3b --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,7 @@ +node_modules +dist +.env +.env.docker +.env.prod +.env.* +!.env.example diff --git a/backend/package.json b/backend/package.json index 6871a3e..596da7f 100644 --- a/backend/package.json +++ b/backend/package.json @@ -36,7 +36,6 @@ "@nestjs/schedule": "^6.1.3", "@nestjs/websockets": "^11.1.19", "@prisma/client": "^6.19.3", - "prisma": "^6.19.3", "bcrypt": "^6.0.0", "bull": "^4.16.5", "cassandra-driver": "^4.9.0", @@ -47,6 +46,7 @@ "minio": "^8.0.7", "passport": "^0.7.0", "passport-jwt": "^4.0.1", + "prisma": "^6.19.3", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", "socket.io": "^4.8.3", @@ -55,6 +55,7 @@ "devDependencies": { "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.18.0", + "@microsoft/eslint-formatter-sarif": "^3.1.0", "@nestjs/cli": "^11.0.0", "@nestjs/schematics": "^11.0.0", "@nestjs/testing": "^11.0.1", diff --git a/backend/pnpm-lock.yaml b/backend/pnpm-lock.yaml index 0830e94..40205ea 100644 --- a/backend/pnpm-lock.yaml +++ b/backend/pnpm-lock.yaml @@ -83,6 +83,9 @@ importers: passport-jwt: specifier: ^4.0.1 version: 4.0.1 + prisma: + specifier: ^6.19.3 + version: 6.19.3(typescript@5.9.3) reflect-metadata: specifier: ^0.2.2 version: 0.2.2 @@ -92,6 +95,9 @@ importers: socket.io: specifier: ^4.8.3 version: 4.8.3 + tsx: + specifier: ^4.21.0 + version: 4.22.0 devDependencies: '@eslint/eslintrc': specifier: ^3.2.0 @@ -99,6 +105,9 @@ importers: '@eslint/js': specifier: ^9.18.0 version: 9.39.4 + '@microsoft/eslint-formatter-sarif': + specifier: ^3.1.0 + version: 3.1.0 '@nestjs/cli': specifier: ^11.0.0 version: 11.0.21(@types/node@24.12.2)(prettier@3.8.3) @@ -156,9 +165,6 @@ importers: prettier: specifier: ^3.4.2 version: 3.8.3 - prisma: - specifier: ^6.19.3 - version: 6.19.3(typescript@5.9.3) source-map-support: specifier: ^0.5.21 version: 0.5.21 @@ -177,9 +183,6 @@ importers: tsconfig-paths: specifier: ^4.2.0 version: 4.2.0 - tsx: - specifier: ^4.21.0 - version: 4.22.0 typescript: specifier: ^5.7.3 version: 5.9.3 @@ -670,10 +673,18 @@ packages: resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/eslintrc@3.3.5': resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/js@9.39.4': resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -721,10 +732,19 @@ packages: resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} engines: {node: '>=18.18.0'} + '@humanwhocodes/config-array@0.13.0': + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + '@humanwhocodes/retry@0.4.3': resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} @@ -995,6 +1015,10 @@ packages: resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} engines: {node: '>=8'} + '@microsoft/eslint-formatter-sarif@3.1.0': + resolution: {integrity: sha512-/mn4UXziHzGXnKCg+r8HGgPy+w4RzpgdoqFuqaKOqUVBT5x2CygGefIrO4SusaY7t0C4gyIWMNu6YQT6Jw64Cw==} + engines: {node: '>= 14'} + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==} cpu: [arm64] @@ -2228,6 +2252,10 @@ packages: resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} engines: {node: '>=0.3.1'} + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dotenv-expand@12.0.3: resolution: {integrity: sha512-uc47g4b+4k/M/SeaW1y4OApx+mtLWl92l5LMPP0GNXctZqELk+YGgOPIIC5elYmUH4OuoK3JLhuRUYegeySiFA==} engines: {node: '>=12'} @@ -2359,6 +2387,10 @@ packages: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@8.4.0: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2375,6 +2407,12 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} + eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + eslint@9.39.4: resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2389,6 +2427,10 @@ packages: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} @@ -2495,6 +2537,10 @@ packages: picomatch: optional: true + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -2523,6 +2569,10 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} @@ -2635,6 +2685,10 @@ packages: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} @@ -2650,6 +2704,9 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + graphql-tag@2.12.6: resolution: {integrity: sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==} engines: {node: '>=10'} @@ -2789,6 +2846,10 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + is-promise@4.0.0: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} @@ -2987,6 +3048,10 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + jschardet@3.1.4: + resolution: {integrity: sha512-/kmVISmrwVwtyYU40iQUOp3SUPk2dhNCMsZBQX0R1/jZ8maaXJ/oZIzUOiyOqcgtLnETFKYChbJ5iDC/eWmFHg==} + engines: {node: '>=0.1.90'} + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} @@ -3570,6 +3635,11 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + router@2.2.0: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} @@ -3835,6 +3905,9 @@ packages: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} engines: {node: '>=8'} + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + through2@4.0.2: resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} @@ -3943,6 +4016,10 @@ packages: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + type-fest@0.21.3: resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} engines: {node: '>=10'} @@ -4017,6 +4094,9 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + utf8@3.0.0: + resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -4638,6 +4718,11 @@ snapshots: '@esbuild/win32-x64@0.28.0': optional: true + '@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)': + dependencies: + eslint: 8.57.1 + eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': dependencies: eslint: 9.39.4(jiti@2.7.0) @@ -4661,6 +4746,20 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 + '@eslint/eslintrc@2.1.4': + dependencies: + ajv: 6.15.0 + debug: 4.4.3 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.5 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + '@eslint/eslintrc@3.3.5': dependencies: ajv: 6.15.0 @@ -4675,6 +4774,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@eslint/js@8.57.1': {} + '@eslint/js@9.39.4': {} '@eslint/object-schema@2.1.7': {} @@ -4721,8 +4822,18 @@ snapshots: '@humanfs/types@0.15.0': {} + '@humanwhocodes/config-array@0.13.0': + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.4.3 + minimatch: 3.1.5 + transitivePeerDependencies: + - supports-color + '@humanwhocodes/module-importer@1.0.1': {} + '@humanwhocodes/object-schema@2.0.3': {} + '@humanwhocodes/retry@0.4.3': {} '@inquirer/ansi@1.0.2': {} @@ -5094,6 +5205,15 @@ snapshots: '@lukeed/csprng@1.1.0': {} + '@microsoft/eslint-formatter-sarif@3.1.0': + dependencies: + eslint: 8.57.1 + jschardet: 3.1.4 + lodash: 4.18.1 + utf8: 3.0.0 + transitivePeerDependencies: + - supports-color + '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': optional: true @@ -6363,6 +6483,10 @@ snapshots: diff@4.0.4: {} + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + dotenv-expand@12.0.3: dependencies: dotenv: 16.6.1 @@ -6505,6 +6629,11 @@ snapshots: esrecurse: 4.3.0 estraverse: 4.3.0 + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + eslint-scope@8.4.0: dependencies: esrecurse: 4.3.0 @@ -6516,6 +6645,49 @@ snapshots: eslint-visitor-keys@5.0.1: {} + eslint@8.57.1: + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) + '@eslint-community/regexpp': 4.12.2 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.3.0 + ajv: 6.15.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.1 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.5 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + eslint@9.39.4(jiti@2.7.0): dependencies: '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) @@ -6563,6 +6735,12 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 4.2.1 + espree@9.6.1: + dependencies: + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) + eslint-visitor-keys: 3.4.3 + esprima@4.0.1: {} esquery@1.7.0: @@ -6694,6 +6872,10 @@ snapshots: optionalDependencies: picomatch: 4.0.4 + file-entry-cache@6.0.1: + dependencies: + flat-cache: 3.2.0 + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -6734,6 +6916,12 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 + flat-cache@3.2.0: + dependencies: + flatted: 3.4.2 + keyv: 4.5.4 + rimraf: 3.0.2 + flat-cache@4.0.1: dependencies: flatted: 3.4.2 @@ -6871,6 +7059,10 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + globals@14.0.0: {} globals@17.6.0: {} @@ -6879,6 +7071,8 @@ snapshots: graceful-fs@4.2.11: {} + graphemer@1.4.0: {} + graphql-tag@2.12.6(graphql@16.14.0): dependencies: graphql: 16.14.0 @@ -6994,6 +7188,8 @@ snapshots: is-number@7.0.0: {} + is-path-inside@3.0.3: {} + is-promise@4.0.0: {} is-stream@2.0.1: {} @@ -7379,6 +7575,8 @@ snapshots: dependencies: argparse: 2.0.1 + jschardet@3.1.4: {} + jsesc@3.1.0: {} json-buffer@3.0.1: {} @@ -7893,6 +8091,10 @@ snapshots: reusify@1.1.0: {} + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + router@2.2.0: dependencies: debug: 4.4.3 @@ -8204,6 +8406,8 @@ snapshots: glob: 7.2.3 minimatch: 3.1.5 + text-table@0.2.0: {} + through2@4.0.2: dependencies: readable-stream: 3.6.2 @@ -8314,6 +8518,8 @@ snapshots: type-detect@4.0.8: {} + type-fest@0.20.2: {} + type-fest@0.21.3: {} type-fest@4.41.0: {} @@ -8401,6 +8607,8 @@ snapshots: dependencies: punycode: 2.3.1 + utf8@3.0.0: {} + util-deprecate@1.0.2: {} utils-merge@1.0.1: {} diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index a6b09f0..f8dec02 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -51,7 +51,7 @@ services: # 4. BACKEND SERVICE (NestJS) backend: - image: ${DOCKER_REGISTRY_USER:-auttomus}/sotto-backend:latest + image: ghcr.io/${DOCKER_REGISTRY_USER:-untacorp}/sotto-backend:${IMAGE_TAG:-latest} container_name: sotto_backend restart: unless-stopped env_file: @@ -68,7 +68,7 @@ services: # 5. FRONTEND SERVICE (React Router) frontend: - image: ${DOCKER_REGISTRY_USER:-auttomus}/sotto-frontend:latest + image: ghcr.io/${DOCKER_REGISTRY_USER:-untacorp}/sotto-frontend:${IMAGE_TAG:-latest} container_name: sotto_frontend restart: unless-stopped env_file: diff --git a/frontend/.dockerignore b/frontend/.dockerignore index 9b8d514..014e929 100644 --- a/frontend/.dockerignore +++ b/frontend/.dockerignore @@ -1,4 +1,9 @@ .react-router build node_modules -README.md \ No newline at end of file +README.md +.env +.env.docker +.env.prod +.env.* +!.env.example \ No newline at end of file diff --git a/frontend/Dockerfile b/frontend/Dockerfile index f887579..2f3655e 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -19,10 +19,6 @@ FROM base AS build WORKDIR /app COPY . . COPY --from=dev-deps /app/node_modules ./node_modules -ARG VITE_MINIO_PUBLIC_URL=https://cdn.sotto.auttomus.xyz -ARG VITE_MIDTRANS_CLIENT_KEY=Mid-client-aKAogCe7B_Nui3nc -ENV VITE_MINIO_PUBLIC_URL=$VITE_MINIO_PUBLIC_URL -ENV VITE_MIDTRANS_CLIENT_KEY=$VITE_MIDTRANS_CLIENT_KEY RUN ./node_modules/.bin/react-router build FROM base AS deploy diff --git a/frontend/app/core/utils/resolveMediaUrl.ts b/frontend/app/core/utils/resolveMediaUrl.ts index 5a3f4c4..5f1714d 100644 --- a/frontend/app/core/utils/resolveMediaUrl.ts +++ b/frontend/app/core/utils/resolveMediaUrl.ts @@ -13,7 +13,10 @@ export function resolveMediaUrl(objectKeyOrUrl: string | null | undefined): stri return objectKeyOrUrl; } - const base = import.meta.env.VITE_MINIO_PUBLIC_URL || 'http://localhost:9000'; + const base = + (typeof window !== 'undefined' && (window as any).ENV?.VITE_MINIO_PUBLIC_URL) || + import.meta.env.VITE_MINIO_PUBLIC_URL || + 'http://localhost:9000'; // Ensure no double slash between base and key const cleanBase = base.endsWith('/') ? base.slice(0, -1) : base; const cleanKey = objectKeyOrUrl.startsWith('/') ? objectKeyOrUrl : `/${objectKeyOrUrl}`; diff --git a/frontend/app/features/settings/components/AboutCard.tsx b/frontend/app/features/settings/components/AboutCard.tsx index 1c79373..cec33d2 100644 --- a/frontend/app/features/settings/components/AboutCard.tsx +++ b/frontend/app/features/settings/components/AboutCard.tsx @@ -27,7 +27,7 @@ export function AboutCard() { {/* Version Badge */}