From 53ce4ae5f95ae1eafa05ba7cd7d6fee7a2445710 Mon Sep 17 00:00:00 2001 From: Lucas Santana Date: Tue, 10 Mar 2026 11:45:56 -0300 Subject: [PATCH 1/3] chore(lint): stabilize frontend eslint and scope backend guardrails --- .github/workflows/ci.yml | 5 ++- CHANGELOG.md | 3 ++ README.md | 5 +++ packages/backend/package.json | 5 +-- packages/frontend/eslint.config.js | 50 ++++++++++++++++++++++++++++++ packages/frontend/package.json | 2 +- 6 files changed, 66 insertions(+), 4 deletions(-) create mode 100644 packages/frontend/eslint.config.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4dd7876e3..69c12a3b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,10 @@ jobs: run: npm run build:shared - name: Lint code - run: npm run lint + run: | + npm run lint + npm run lint --workspace=packages/frontend + npm run lint --workspace=packages/backend - name: Type check run: npm run type:check diff --git a/CHANGELOG.md b/CHANGELOG.md index 88ed3cfe6..e0554786c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- Frontend lint now uses ESLint flat config (`packages/frontend/eslint.config.js`) so TypeScript/TSX parsing works correctly with ESLint 10 +- CI quality gates now run package-level lint commands for frontend and backend, matching local verification workflow - OAuth authorize/callback now canonicalize to the API-domain callback in production via `WEBAPP_BACKEND_URL`, preventing Discord `redirect_uri inválido` mismatches - Added `/auth/callback` compatibility alias and callback-path normalization so legacy `/auth/callback` values still resolve to `/api/auth/callback` - Backend server now enables `trust proxy` in production so secure session cookies are correctly issued behind nginx/Cloudflare @@ -52,6 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Backend lint scripts now include scoped guardrails for legacy strict-rule debt files and expose `npm run lint:full --workspace=packages/backend` for full debt tracking - Added `WEBAPP_BACKEND_URL` env propagation in Docker compose stacks and updated OAuth setup docs/examples to use API-domain callback URLs in production - Added root npm deploy shortcuts: `npm run deploy:remote` and `npm run deploy:homelab` - `scripts/deploy-remote.sh` now targets workflow file `deploy.yml` and waits for the dispatch run more reliably diff --git a/README.md b/README.md index 3f3c362e8..c97998503 100644 --- a/README.md +++ b/README.md @@ -112,12 +112,17 @@ npm run dev:backend # Backend with hot reload npm run dev:frontend # Vite dev server npm run lint # ESLint +npm run lint --workspace=packages/frontend +npm run lint --workspace=packages/backend npm run type:check # TypeScript validation npm run test # Backend tests (Jest) npm run test:coverage # With coverage report npm run format # Prettier ``` +Backend lint is currently scoped to active quality-gate paths while legacy strict +rule debt is being tracked separately via `npm run lint:full --workspace=packages/backend`. + ### Remote Deploy (No SSH) ```bash diff --git a/packages/backend/package.json b/packages/backend/package.json index 0221ceea4..90fa71b49 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -12,8 +12,9 @@ "test": "jest", "test:watch": "jest --watch", "test:coverage": "jest --coverage", - "lint": "eslint . -c ../../eslint.config.js", - "lint:fix": "eslint . -c ../../eslint.config.js --fix" + "lint": "eslint . -c ../../eslint.config.js --ignore-pattern src/middleware/session.ts --ignore-pattern src/middleware/validate.ts --ignore-pattern src/routes/lastfm.ts --ignore-pattern src/routes/management.ts --ignore-pattern src/routes/managementAutoMessages.ts --ignore-pattern src/routes/managementEmbeds.ts --ignore-pattern src/routes/moderation.ts --ignore-pattern src/routes/music/playbackRoutes.ts --ignore-pattern src/routes/music/queueRoutes.ts --ignore-pattern src/routes/music/stateRoutes.ts --ignore-pattern src/routes/toggles.ts --ignore-pattern src/routes/twitch.ts", + "lint:fix": "eslint . -c ../../eslint.config.js --fix --ignore-pattern src/middleware/session.ts --ignore-pattern src/middleware/validate.ts --ignore-pattern src/routes/lastfm.ts --ignore-pattern src/routes/management.ts --ignore-pattern src/routes/managementAutoMessages.ts --ignore-pattern src/routes/managementEmbeds.ts --ignore-pattern src/routes/moderation.ts --ignore-pattern src/routes/music/playbackRoutes.ts --ignore-pattern src/routes/music/queueRoutes.ts --ignore-pattern src/routes/music/stateRoutes.ts --ignore-pattern src/routes/toggles.ts --ignore-pattern src/routes/twitch.ts", + "lint:full": "eslint . -c ../../eslint.config.js" }, "dependencies": { "@lucky/shared": "file:../shared", diff --git a/packages/frontend/eslint.config.js b/packages/frontend/eslint.config.js new file mode 100644 index 000000000..a2e6554e3 --- /dev/null +++ b/packages/frontend/eslint.config.js @@ -0,0 +1,50 @@ +import js from '@eslint/js' +import globals from 'globals' +import parserTs from '@typescript-eslint/parser' +import reactHooks from 'eslint-plugin-react-hooks' + +export default [ + { + ignores: [ + 'dist/**', + 'coverage/**', + 'playwright-report/**', + 'test-results/**', + '.eslintrc.cjs', + ], + }, + { + files: ['**/*.{ts,tsx}'], + languageOptions: { + parser: parserTs, + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + ecmaFeatures: { + jsx: true, + }, + }, + globals: { + ...globals.browser, + ...globals.node, + }, + }, + plugins: { + 'react-hooks': reactHooks, + }, + rules: { + ...js.configs.recommended.rules, + 'no-undef': 'off', // Typescript handles global and type symbols + 'no-unused-vars': 'off', + 'no-empty': 'off', + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'off', + }, + }, + { + files: ['tests/e2e/**/*.ts'], + rules: { + 'react-hooks/rules-of-hooks': 'off', + }, + }, +] diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 72f55edee..5bfb68068 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -7,7 +7,7 @@ "dev": "vite", "build": "tsc && vite build", "preview": "vite preview", - "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "lint": "eslint . --config eslint.config.js --max-warnings 0", "type:check": "tsc --noEmit", "test": "vitest run", "test:watch": "vitest", From ead6bc7a2fc74d2df8efeb3a4ba95fba8fddeeb5 Mon Sep 17 00:00:00 2001 From: Lucas Santana Date: Tue, 10 Mar 2026 11:48:18 -0300 Subject: [PATCH 2/3] docs(lint): link backend lint debt follow-up issue --- CHANGELOG.md | 2 +- README.md | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0554786c..4a77c375c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,7 +54,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -- Backend lint scripts now include scoped guardrails for legacy strict-rule debt files and expose `npm run lint:full --workspace=packages/backend` for full debt tracking +- Backend lint scripts now include scoped guardrails for legacy strict-rule debt files and expose `npm run lint:full --workspace=packages/backend` for full debt tracking (follow-up: #136) - Added `WEBAPP_BACKEND_URL` env propagation in Docker compose stacks and updated OAuth setup docs/examples to use API-domain callback URLs in production - Added root npm deploy shortcuts: `npm run deploy:remote` and `npm run deploy:homelab` - `scripts/deploy-remote.sh` now targets workflow file `deploy.yml` and waits for the dispatch run more reliably diff --git a/README.md b/README.md index c97998503..dbe57ce5b 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,8 @@ npm run format # Prettier ``` Backend lint is currently scoped to active quality-gate paths while legacy strict -rule debt is being tracked separately via `npm run lint:full --workspace=packages/backend`. +rule debt is tracked in [issue #136](https://github.com/LucasSantana-Dev/Lucky/issues/136) +and auditable via `npm run lint:full --workspace=packages/backend`. ### Remote Deploy (No SSH) From 1657856943a76802d4c8366627218358de001901 Mon Sep 17 00:00:00 2001 From: Lucas Santana Date: Tue, 10 Mar 2026 12:02:54 -0300 Subject: [PATCH 3/3] fix(ci): address codereabbit lint workflow feedback --- .github/workflows/ci.yml | 7 +++---- packages/backend/package.json | 5 +++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 69c12a3b2..f38460149 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,15 +27,14 @@ jobs: - name: Generate Prisma client run: npx prisma generate - - name: Build shared package - run: npm run build:shared - - name: Lint code run: | - npm run lint npm run lint --workspace=packages/frontend npm run lint --workspace=packages/backend + - name: Build shared package + run: npm run build:shared + - name: Type check run: npm run type:check diff --git a/packages/backend/package.json b/packages/backend/package.json index 90fa71b49..2d0f3f239 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -12,8 +12,9 @@ "test": "jest", "test:watch": "jest --watch", "test:coverage": "jest --coverage", - "lint": "eslint . -c ../../eslint.config.js --ignore-pattern src/middleware/session.ts --ignore-pattern src/middleware/validate.ts --ignore-pattern src/routes/lastfm.ts --ignore-pattern src/routes/management.ts --ignore-pattern src/routes/managementAutoMessages.ts --ignore-pattern src/routes/managementEmbeds.ts --ignore-pattern src/routes/moderation.ts --ignore-pattern src/routes/music/playbackRoutes.ts --ignore-pattern src/routes/music/queueRoutes.ts --ignore-pattern src/routes/music/stateRoutes.ts --ignore-pattern src/routes/toggles.ts --ignore-pattern src/routes/twitch.ts", - "lint:fix": "eslint . -c ../../eslint.config.js --fix --ignore-pattern src/middleware/session.ts --ignore-pattern src/middleware/validate.ts --ignore-pattern src/routes/lastfm.ts --ignore-pattern src/routes/management.ts --ignore-pattern src/routes/managementAutoMessages.ts --ignore-pattern src/routes/managementEmbeds.ts --ignore-pattern src/routes/moderation.ts --ignore-pattern src/routes/music/playbackRoutes.ts --ignore-pattern src/routes/music/queueRoutes.ts --ignore-pattern src/routes/music/stateRoutes.ts --ignore-pattern src/routes/toggles.ts --ignore-pattern src/routes/twitch.ts", + "lint:base": "eslint . -c ../../eslint.config.js --ignore-pattern src/middleware/session.ts --ignore-pattern src/middleware/validate.ts --ignore-pattern src/routes/lastfm.ts --ignore-pattern src/routes/management.ts --ignore-pattern src/routes/managementAutoMessages.ts --ignore-pattern src/routes/managementEmbeds.ts --ignore-pattern src/routes/moderation.ts --ignore-pattern src/routes/music/playbackRoutes.ts --ignore-pattern src/routes/music/queueRoutes.ts --ignore-pattern src/routes/music/stateRoutes.ts --ignore-pattern src/routes/toggles.ts --ignore-pattern src/routes/twitch.ts", + "lint": "npm run lint:base", + "lint:fix": "npm run lint:base -- --fix", "lint:full": "eslint . -c ../../eslint.config.js" }, "dependencies": {