Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
ceb9324
perf(ci): implement prebuilt deployment strategy with Nx and Next.js …
Apr 17, 2026
b0004b7
fix(deploy): skip redundant npm install during vercel build in CI
Apr 17, 2026
6995bc0
chore(ci): finalize Nx Cloud integration and optimize hybrid caching
Apr 17, 2026
e3b00ae
perf(ci): apply prebuilt deployment strategy and caching to Website p…
Apr 17, 2026
fedfc42
feat: modernize guided learning & transition to milestone architecture
Apr 17, 2026
30c087f
fix: resolve CI blocks, modernize study plans, and fix formatting
Apr 18, 2026
f6e9a16
chore: resolve SonarCloud quality gate failures (duplication and cove…
Apr 18, 2026
77e183d
chore: resolve all remaining SonarCloud issues
Apr 18, 2026
27dc103
chore: resolve SonarCloud quality gate issues
Apr 18, 2026
779a26c
fix(ci): resolve SonarQube quality gate issues and improve accessibility
Apr 18, 2026
ab7d796
chore: sonar fixes for accessibility, coverage and security
Apr 18, 2026
ad3805a
fix(sonar): refine auth-config blocker and fix await non-promise in d…
Apr 18, 2026
c8de4f3
test(sonar): add comprehensive unit tests for API utilities and handlers
Apr 18, 2026
7698fb1
chore(sonar): fix linting warnings in new tests and validation logic
Apr 18, 2026
9d6b4d2
refactor: reduce cognitive complexity in questions API and dashboard
Apr 18, 2026
10d1015
refactor: resolve remaining SonarCloud blockers and consolidate dupli…
Apr 18, 2026
265732f
refactor: resolve all SonarCloud cognitive complexity blockers and li…
Apr 19, 2026
cedb687
refactor: reach SonarCloud 'Green' status and unblock CI pipeline
Apr 19, 2026
7329c34
feat: resolve CI pipeline failures for PR #12102
Apr 19, 2026
f5dc3f7
fix: resolve SonarCloud blockers and CI pipeline failures
Apr 19, 2026
4d5adba
fix: finalize SonarCloud fixes and resolve lint/format issues
Apr 19, 2026
1680482
fix(ci): resolve pipeline failures, migrate utilities to vitest, and …
Apr 19, 2026
63fab5c
perf(ci): resolve all SonarCloud findings and accessibility issues
Apr 22, 2026
0ff7d8a
perf(ci): resolve lint failures and harden deployment retry logic
Apr 22, 2026
64d2dda
ci: fix vercel deploy pipeline fallback to npm install
Apr 23, 2026
fcba180
fix: restore missing evaluateCSSHTML signature and add test
Apr 26, 2026
3371a42
fix: resolve typescript compilation errors
Apr 26, 2026
116b3a0
fix: resolve typescript and prettier issues blocking CI pipelines
Apr 28, 2026
c6b65df
test: fix failing vitest coverage test suites for frontend-task-valid…
Apr 28, 2026
47eb2c8
style: fix remaining sonarqube code smells and linting issues
Apr 28, 2026
0b1bf6c
test: add comprehensive unit tests for unified API routes, sync utili…
Apr 29, 2026
2a29b27
fix(sonarqube): resolve multiple code smells and increase unit test c…
May 4, 2026
2b5c845
fix(sonarqube): restore necessary variables used in component body
May 4, 2026
c853be6
fix(sonarqube): final cleanup of unused imports and improved sanitiza…
May 4, 2026
07d6426
perf(ci): optimize CI memory usage, reduce code duplication in editor…
May 4, 2026
066c663
refactor(admin): consolidate shared hooks and optimize validator logic
May 4, 2026
1ceab70
fix(admin): remove duplicate hook and resolve build error
May 4, 2026
e6a8855
refactor(api): modularize config and environment logic to reduce cogn…
May 4, 2026
57fd5d5
fix(sonarqube): resolve blocker S3516, accessibility S1082, and neste…
May 5, 2026
02717e7
fix(test): update import path and mock fluent API for questions-handler
May 5, 2026
2607394
test(coverage): add unit tests for auth-config and checkbox to satisf…
May 6, 2026
48ccc10
refactor(quality): reduce complexity and resolve deprecated API warni…
May 6, 2026
0e7518f
fix(quality): add missing import and finalize validation refactor
May 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 49 additions & 132 deletions .github/workflows/manual-deploy-parallel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,16 @@ jobs:
run: corepack enable

- name: Install root dependencies
run: pnpm install --no-frozen-lockfile
run: pnpm install --frozen-lockfile

- name: Setup Vercel and Next.js Caching
uses: actions/cache@v4
with:
path: |
apps/website/.next/cache
key: ${{ runner.os }}-website-next-cache-${{ github.sha }}
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Next.js cache key is based on github.sha, which effectively creates a new cache entry every commit and reduces cache hit rates across PR updates (restore-keys helps, but you still churn caches). For better CI performance and lower cache storage churn, consider keying on the lockfile (e.g., hashFiles('pnpm-lock.yaml')) plus an app identifier, and optionally include a Next.js/version component if needed.

Suggested change
key: ${{ runner.os }}-website-next-cache-${{ github.sha }}
key: ${{ runner.os }}-website-next-cache-${{ hashFiles('pnpm-lock.yaml') }}

Copilot uses AI. Check for mistakes.
restore-keys: |
${{ runner.os }}-website-next-cache-

- name: Validate Vercel token
run: |
Expand All @@ -79,57 +88,27 @@ jobs:
curl -fsS -X PATCH \
-H "Authorization: Bearer ${{ secrets.VERCEL_TOKEN }}" \
-H "Content-Type: application/json" \
-d '{"buildCommand":"npm run build","outputDirectory":"apps/website/.next"}' \
-d '{"buildCommand":"pnpm --filter website build","outputDirectory":"apps/website/.next","installCommand":"true"}' \
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Patching Vercel project settings to set installCommand to true will globally change the project behavior on Vercel (including dashboard/preview builds), not just this workflow. Since --prebuilt deployments don’t need Vercel to install dependencies anyway, consider avoiding changing installCommand (or restoring the previous value at the end) to prevent unexpected breakages for non-GitHub-Actions deployments.

Suggested change
-d '{"buildCommand":"pnpm --filter website build","outputDirectory":"apps/website/.next","installCommand":"true"}' \
-d '{"buildCommand":"pnpm --filter website build","outputDirectory":"apps/website/.next"}' \

Copilot uses AI. Check for mistakes.
"https://api.vercel.com/v9/projects/${{ secrets.VERCEL_PROJECT_ID_WEBSITE }}"
Comment on lines 88 to 92
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Vercel project settings installCommand skip install with prebuilt deploy

💡 Result:

To skip the install step in Vercel project settings for a prebuilt deployment, use the Install Command override in the Build & Development Settings. In the Vercel dashboard: 1. Go to your Project Settings > Build & Development. 2. Enable the Override toggle for Install Command. 3. Leave the Install Command field empty. This skips the install step entirely, similar to how leaving the Build Command empty skips the build step for static projects. For prebuilt deployments via CLI: - Run vercel build locally to generate .vercel/output (this may run install unless configured otherwise). - Then vercel deploy --prebuilt to upload prebuilt artifacts without re-running build/install on Vercel servers. In vercel.json, set "installCommand": null or "" (type allows null, likely skips). Note: Prebuilt deployments skip the build process on Vercel (including install), using local build output. For Git deployments with prebuilt assets already in repo (e.g., static site), empty installCommand + empty buildCommand + set Output Directory serves directly without install/build.

Citations:


Use null or empty string for installCommand instead of "true".

Vercel's documented pattern for skipping install is "installCommand": null or "installCommand": "". The current "true" works incidentally (as a shell no-op) but deviates from the recommended configuration and could become fragile if Vercel changes how it handles unrecognized commands. Update to match Vercel's API expectations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/manual-deploy-parallel.yml around lines 88 - 92, Update
the JSON payload in the curl PATCH request that sets Vercel project settings:
replace the current "installCommand":"true" with the recommended pattern
("installCommand": null) or an empty string ("installCommand": "") in the -d
'{"buildCommand":"pnpm --filter website
build","outputDirectory":"apps/website/.next","installCommand":"true"}' payload
so the API explicitly skips install per Vercel docs; ensure the modified payload
preserves buildCommand and outputDirectory exactly as shown.


- name: Validate build locally (optional build check)
- name: Validate and build (Local Vercel Build)
if: ${{ inputs.validate_build_website }}
run: pnpm --dir apps/website run build
run: |
npx vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
npx vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
env:
Comment on lines +94 to 99
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vercel deploy --prebuilt requires a locally generated .vercel/output (from vercel build). Right now the build step is conditional (if: inputs.validate_build_website), so disabling validation will make the deploy step fail on a fresh runner because there is no prebuilt output to upload. Consider always running vercel pull + vercel build (and keep an input only for skipping extra checks, not the build itself), or switch back to non-prebuilt deploy when validation is disabled.

Copilot uses AI. Check for mistakes.
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_WEBSITE }}
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
NEXT_PUBLIC_APP_ENV: production
NEXT_TELEMETRY_DISABLED: 1
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}

Comment thread
coderabbitai[bot] marked this conversation as resolved.
- name: Bypass Vercel Nx Plugin (website)
run: |
if [ -f nx.json ]; then
mv nx.json nx.json.bak
fi

- name: Prepare website package manifest for Vercel build
run: |
node -e 'const fs=require("fs");const root=JSON.parse(fs.readFileSync("package.json","utf8"));const p="apps/website/package.json";const pkg=JSON.parse(fs.readFileSync(p,"utf8"));const internal=["@elzatona/common-ui","@elzatona/contexts","@elzatona/database","@elzatona/types","@elzatona/utilities"];const required=["@sentry/nextjs"];pkg.dependencies=pkg.dependencies||{};for(const name of internal){if(pkg.dependencies) delete pkg.dependencies[name]; if(pkg.devDependencies) delete pkg.devDependencies[name];}for(const name of required){if(!pkg.dependencies[name]){const v=(root.dependencies&&root.dependencies[name])||(root.devDependencies&&root.devDependencies[name]);if(v) pkg.dependencies[name]=v;}}fs.writeFileSync(p, JSON.stringify(pkg, null, 2)+"\n");'

- name: Set root build script for website deployment
run: |
node -e 'const fs=require("fs");const p="package.json";const pkg=JSON.parse(fs.readFileSync(p,"utf8"));pkg.scripts=pkg.scripts||{};pkg.scripts.build="pnpm --dir apps/website build";fs.writeFileSync(p, JSON.stringify(pkg, null, 2)+"\n");'

- name: Deploy website to Vercel
- name: Deploy website to Vercel (Prebuilt)
run: |
set -euo pipefail

ensure_website_ready() {
local deployment_url="$1"

for ready_attempt in 1 2 3 4 5 6; do
ready_log="$(mktemp)"
if timeout 2m npx vercel inspect "${deployment_url}" --wait --timeout 2m --token=${{ secrets.VERCEL_TOKEN }} >"$ready_log" 2>&1; then
cat "$ready_log"
return 0
fi

cat "$ready_log"
echo "Deployment readiness check ${ready_attempt}/6 did not pass yet."

if [ "$ready_attempt" -lt 6 ]; then
sleep 10
fi
done

return 1
}

set_website_aliases() {
local deployment_url="$1"
echo "Setting website aliases for: ${deployment_url}"
Expand All @@ -141,51 +120,17 @@ jobs:
fi
}

timeout 8m npx vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
for attempt in 1 2 3 4 5 6; do
echo "Deploy website attempt ${attempt}/6"
deploy_log="$(mktemp)"
timeout 20m npx vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }} 2>&1 | tee "$deploy_log" || true
if grep -Eq 'Failed to process project graph|Could not find ".modules.yaml"|ENOENT: no such file or directory|Error: Command "npx nx build|Error: Command "npm run build" exited with 1|Error: Command "npm install" exited with 1' "$deploy_log"; then
echo "Deploy output indicates explicit build failure; failing deployment step."
exit 1
fi
prod_url="$(grep -Eo 'https://[^ ]+\.vercel\.app' "$deploy_log" | tail -n 1 || true)"
if [ -n "$prod_url" ]; then
echo "Deploy command produced URL: $prod_url"
inspect_log="$(mktemp)"
if timeout 12m npx vercel inspect "$prod_url" --wait --timeout 12m --token=${{ secrets.VERCEL_TOKEN }} >"$inspect_log" 2>&1; then
cat "$inspect_log"
deploy_output=$(npx vercel deploy --prebuilt --prod --yes --token=${{ secrets.VERCEL_TOKEN }})
if [ $? -eq 0 ]; then
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With set -euo pipefail, the assignment deploy_output=$(npx vercel deploy ...) will cause the script to exit immediately on a non-zero deploy, so the retry loop will never retry. Restructure to run the deploy in the if condition (e.g., if deploy_output=$(...); then ... else ... fi) or otherwise suppress errexit for that command so failures fall through to the retry logic.

Copilot uses AI. Check for mistakes.
# Extract URL from output if possible, or use standard prod URL for aliasing
prod_url=$(echo "$deploy_output" | grep -Eo 'https://[^ ]+\.vercel\.app' | tail -n 1 || echo "https://elzatona-web.com")
echo "Admin deployment is ready in production."
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This log line is in the website deploy job but says "Admin deployment is ready"; it should reference the website deployment to avoid confusing CI logs and on-call troubleshooting.

Suggested change
echo "Admin deployment is ready in production."
echo "Website deployment is ready in production."

Copilot uses AI. Check for mistakes.
set_website_aliases "$prod_url"
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the deploy output parsing fails, prod_url falls back to https://elzatona-web.com, but vercel alias set expects a deployment URL/id (not an existing alias/domain). This will likely make aliasing fail or point aliases at the wrong target. Better to fail fast when no deployment URL can be extracted (or query the deployment via vercel inspect/vercel ls to retrieve the actual deployment URL) before calling set_website_aliases.

Copilot uses AI. Check for mistakes.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated
echo "Website deployment is ready in production: $prod_url"
exit 0
fi
cat "$inspect_log"

if grep -Eq 'Failed to process project graph|Could not find ".modules.yaml"|ENOENT: no such file or directory|Error: Command "npx nx build|Error: Command "npm run build" exited with 1|Error: Command "npm install" exited with 1' "$inspect_log"; then
echo "Inspect indicates an explicit build failure; failing deployment step."
exit 1
fi
echo "Inspect did not confirm readiness; probing URL reachability as transient fallback..."
for probe in 1 2 3 4 5 6; do
http_code="$(curl -sS -o /dev/null -w '%{http_code}' --max-time 20 "$prod_url" || true)"
if [ "$http_code" != "000" ]; then
echo "Website deployment URL is reachable (HTTP $http_code): $prod_url"

if ensure_website_ready "$prod_url"; then
set_website_aliases "$prod_url"
echo "Website deployment is ready in production: $prod_url"
exit 0
fi

echo "Website URL is reachable but deployment is still not ready; continuing retries."
break
fi
echo "Website probe ${probe}/6 not reachable yet; retrying in 10s..."
sleep 10
done
echo "Inspect and reachability probe did not confirm readiness; retrying deployment attempt..."
fi

if [ "$attempt" -eq 6 ]; then
echo "Website deployment failed after 6 attempts"
exit 1
Expand All @@ -197,6 +142,7 @@ jobs:
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_WEBSITE }}
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}

deploy-admin:
name: Deploy Admin
Expand Down Expand Up @@ -227,7 +173,16 @@ jobs:
run: corepack enable

- name: Install root dependencies
run: pnpm install --no-frozen-lockfile
run: pnpm install --frozen-lockfile

- name: Setup Vercel and Next.js Caching
uses: actions/cache@v4
with:
path: |
apps/admin/.next/cache
key: ${{ runner.os }}-next-cache-${{ github.sha }}
restore-keys: |
${{ runner.os }}-next-cache-
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The admin Next.js cache key is also tied to github.sha, which causes frequent cache misses/churn. Consider using a lockfile-based key (e.g., hashFiles('pnpm-lock.yaml')) with an admin prefix so the cache is reusable across commits while still invalidating when deps change.

Suggested change
key: ${{ runner.os }}-next-cache-${{ github.sha }}
restore-keys: |
${{ runner.os }}-next-cache-
key: ${{ runner.os }}-admin-next-cache-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-admin-next-cache-

Copilot uses AI. Check for mistakes.
Comment on lines +188 to +195
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Admin cache key isn't scoped to "admin" — collision risk with any future ${runner.os}-next-cache-* entry.

The website job uses ${{ runner.os }}-website-next-cache-... (line 74-76), but the admin job uses the generic ${{ runner.os }}-next-cache-.... If another workflow/job ever writes under the same prefix, admin could restore a website (or other) .next/cache. Low severity today, but easy to fix and consistent with the website job.

🛠️ Proposed fix
-          key: ${{ runner.os }}-next-cache-${{ github.sha }}
+          key: ${{ runner.os }}-admin-next-cache-${{ github.sha }}
           restore-keys: |
-            ${{ runner.os }}-next-cache-
+            ${{ runner.os }}-admin-next-cache-
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Setup Vercel and Next.js Caching
uses: actions/cache@v4
with:
path: |
apps/admin/.next/cache
key: ${{ runner.os }}-next-cache-${{ github.sha }}
restore-keys: |
${{ runner.os }}-next-cache-
- name: Setup Vercel and Next.js Caching
uses: actions/cache@v4
with:
path: |
apps/admin/.next/cache
key: ${{ runner.os }}-admin-next-cache-${{ github.sha }}
restore-keys: |
${{ runner.os }}-admin-next-cache-
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/manual-deploy-parallel.yml around lines 178 - 185, The
cache key for the "Setup Vercel and Next.js Caching" step is too generic and may
collide with other jobs; update the cache key and restore-keys to include an
"admin" scope (e.g., change ${{ runner.os }}-next-cache-${{ github.sha }} and
${{ runner.os }}-next-cache- to include "admin" such as ${{ runner.os
}}-admin-next-cache-${{ github.sha }} and ${{ runner.os }}-admin-next-cache-) so
this job's cache is uniquely namespaced to admin.


- name: Validate Vercel token
run: |
Expand All @@ -242,70 +197,31 @@ jobs:
curl -fsS -X PATCH \
-H "Authorization: Bearer ${{ secrets.VERCEL_TOKEN }}" \
-H "Content-Type: application/json" \
-d '{"buildCommand":"npm run build","outputDirectory":".next"}' \
-d '{"buildCommand":"pnpm --filter admin build","outputDirectory":"apps/admin/.next","installCommand":"true"}' \
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same concern for the admin project: setting installCommand to true via the API PATCH changes the project’s global Vercel configuration and may break preview/dashboard builds that expect installs. Consider not mutating installCommand here (or resetting it), and rely on the local vercel build + vercel deploy --prebuilt path for this workflow.

Suggested change
-d '{"buildCommand":"pnpm --filter admin build","outputDirectory":"apps/admin/.next","installCommand":"true"}' \
-d '{"buildCommand":"pnpm --filter admin build","outputDirectory":"apps/admin/.next"}' \

Copilot uses AI. Check for mistakes.
"https://api.vercel.com/v9/projects/${{ secrets.VERCEL_PROJECT_ID_ADMIN }}"

- name: Validate build locally (optional build check)
- name: Validate and build (Local Vercel Build)
if: ${{ inputs.validate_build_admin }}
run: pnpm --dir apps/admin run build
run: |
npx vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
npx vercel build --prod --token=${{ secrets.VERCEL_TOKEN }}
env:
Comment on lines +213 to 218
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vercel deploy --prebuilt in the admin job also depends on .vercel/output from vercel build, but the build step is conditional (if: inputs.validate_build_admin). If validation is turned off, the deploy will fail on a clean runner. Consider always running vercel pull + vercel build when using --prebuilt, or falling back to a standard vercel deploy when skipping the build.

Copilot uses AI. Check for mistakes.
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_ADMIN }}
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
NEXT_PUBLIC_APP_ENV: production
NEXT_TELEMETRY_DISABLED: 1
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}

- name: Bypass Vercel Nx Plugin (admin)
run: |
if [ -f nx.json ]; then
mv nx.json nx.json.bak
fi

- name: Prepare admin package manifest for Vercel build
run: |
node -e 'const fs=require("fs");const root=JSON.parse(fs.readFileSync("package.json","utf8"));const p="apps/admin/package.json";const pkg=JSON.parse(fs.readFileSync(p,"utf8"));const internal=["@elzatona/common-ui","@elzatona/contexts","@elzatona/database","@elzatona/types","@elzatona/utilities"];const required=["@sentry/nextjs"];pkg.dependencies=pkg.dependencies||{};for(const name of internal){if(pkg.dependencies) delete pkg.dependencies[name]; if(pkg.devDependencies) delete pkg.devDependencies[name];}for(const name of required){if(!pkg.dependencies[name]){const v=(root.dependencies&&root.dependencies[name])||(root.devDependencies&&root.devDependencies[name]);if(v) pkg.dependencies[name]=v;}}fs.writeFileSync(p, JSON.stringify(pkg, null, 2)+"\n");'

- name: Set root build script for admin deployment
run: |
node -e 'const fs=require("fs");const p="package.json";const pkg=JSON.parse(fs.readFileSync(p,"utf8"));pkg.scripts=pkg.scripts||{};pkg.scripts.build="pnpm --dir apps/admin build";fs.writeFileSync(p, JSON.stringify(pkg, null, 2)+"\n");'

- name: Deploy admin to Vercel
- name: Deploy admin to Vercel (Prebuilt)
run: |
set -euo pipefail
timeout 8m npx vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }}
for attempt in 1 2 3 4 5 6; do
echo "Deploy admin attempt ${attempt}/6"
deploy_log="$(mktemp)"
timeout 20m npx vercel deploy --prod --yes --token=${{ secrets.VERCEL_TOKEN }} 2>&1 | tee "$deploy_log" || true
if grep -Eq 'Failed to process project graph|Could not find ".modules.yaml"|ENOENT: no such file or directory|Error: Command "npx nx build|Error: Command "npm run build" exited with 1|Error: Command "npm install" exited with 1' "$deploy_log"; then
echo "Deploy output indicates explicit build failure; failing deployment step."
exit 1
fi
prod_url="$(grep -Eo 'https://[^ ]+\.vercel\.app' "$deploy_log" | tail -n 1 || true)"
if [ -n "$prod_url" ]; then
echo "Deploy command produced URL: $prod_url"
inspect_log="$(mktemp)"
if timeout 12m npx vercel inspect "$prod_url" --wait --timeout 12m --token=${{ secrets.VERCEL_TOKEN }} >"$inspect_log" 2>&1; then
cat "$inspect_log"
echo "Admin deployment is ready in production: $prod_url"
exit 0
fi
cat "$inspect_log"

if grep -Eq 'Failed to process project graph|Could not find ".modules.yaml"|ENOENT: no such file or directory|Error: Command "npx nx build|Error: Command "npm run build" exited with 1|Error: Command "npm install" exited with 1' "$inspect_log"; then
echo "Inspect indicates an explicit build failure; failing deployment step."
exit 1
fi
echo "Inspect did not confirm readiness; probing URL reachability as transient fallback..."
for probe in 1 2 3 4 5 6; do
http_code="$(curl -sS -o /dev/null -w '%{http_code}' --max-time 20 "$prod_url" || true)"
if [ "$http_code" != "000" ]; then
echo "Admin deployment URL is reachable (HTTP $http_code): $prod_url"
exit 0
fi
echo "Admin probe ${probe}/6 not reachable yet; retrying in 10s..."
sleep 10
done
echo "Inspect and reachability probe did not confirm readiness; retrying deployment attempt..."
if npx vercel deploy --prebuilt --prod --yes --token=${{ secrets.VERCEL_TOKEN }}; then
echo "Admin deployment is ready in production."
exit 0
fi
if [ "$attempt" -eq 6 ]; then
echo "Admin deployment failed after 6 attempts"
Expand All @@ -318,3 +234,4 @@ jobs:
env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID_ADMIN }}
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

set -e

pnpm run check:staged
npm run check:staged
1 change: 1 addition & 0 deletions apps/website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"private": true,
"scripts": {
"dev": "next dev",
"dev:website:test": "next dev --port 3000",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Two scripts with the same name behave differently — Playwright will pick this one, which doesn't load .env.test.local explicitly.

Root package.json defines dev:website:test as ... dotenv -e .env.test.local -- nx serve website --port=3000 with explicit memory cap and env forcing. This app-level one is a plain next dev --port 3000. Playwright's webServer.command: "npm run dev:website:test" (run with cwd inside apps/website) resolves to this script, not the root one, so:

  • .env.test.local isn't loaded via dotenv-cli — you're relying on Next.js's built-in env cascade plus Playwright's webServer.env forcing NODE_ENV=test. That usually works, but silently diverges from the documented "loads .env.test.local" comment in playwright.config.ts (line 203).
  • No NODE_OPTIONS=--max-old-space-size=1536, so the 8GB-RAM guardrail mentioned elsewhere is lost in E2E runs.

Consider aligning one of the two (either drop this app-level script and point Playwright at the root script via npm run --prefix ../.. dev:website:test, or replicate the env loading + memory flag here).

🧰 Tools
🪛 GitHub Actions: CI Checks (Lint, Type Check, Build)

[error] format check failed: Code style issues found in 15 files. Command 'pnpm run format:check:tracked' (bash scripts/ci-quality-gate.sh format) exited with code 1.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/website/package.json` at line 7, The app-level npm script
"dev:website:test" diverges from the root script and prevents .env.test.local
and NODE_OPTIONS from being applied; either remove this app-level
"dev:website:test" so Playwright's npm run resolves to the root script, or
change the app-level "dev:website:test" to match the root behavior by invoking
dotenv to load .env.test.local and setting
NODE_OPTIONS=--max-old-space-size=1536 (so Playwright's webServer.command: "npm
run dev:website:test" and the comment in playwright.config.ts remain correct).
Ensure you update the script named dev:website:test and keep Playwright's
webServer.command and the env-loading semantics consistent.

"build": "next build --webpack",
"start": "next start",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
Expand Down
Loading
Loading