Skip to content

[EPIC](apps): Migrate to Clean TypeScript ESLint Configuration #1565

@ArtieReus

Description

@ArtieReus

Description

Our current ESLint setup has accumulated technical debt from the JS-to-TS migration:

Problem: packages/config/eslint/juno-typescript.mjs mixes JavaScript and TypeScript rules (lines 35-36 use both pluginJs.configs.recommended and tseslint.configs.recommendedTypeCheckedOnly), causing rule conflicts. Each app works around this by disabling 15-20 TypeScript rules.

Solution: Create a clean, Vite-based TypeScript ESLint configuration (vite-react-ts.mjs) and migrate each app independently. This allows parallel work without coordination overhead and eliminates JS/TS rule interference.

Why it matters:

  • Improves type safety by re-enabling strict TypeScript checks
  • Better IDE support and autocomplete
  • Clearer distinction between intentional overrides vs. workarounds

Objectives

  • Eliminate JavaScript/TypeScript rule conflicts in shared config
  • Enable strict TypeScript checking across all apps (re-enable currently disabled rules)
  • Allow independent, parallelizable migration work per app
  • Improve developer experience with better type safety and IDE support
  • Establish clear ESLint conventions for future development

Acceptance Criteria

  • New packages/config/eslint/vite-react-ts.mjs config exists with pure TypeScript rules
  • All 7 apps migrated: carbon, doop, greenhouse, heureka, supernova, example, template
  • All 8 packages migrated: oauth, ui-components, greenhouse-auth-provider, template, communicator, k8s-client, url-state-provider, messages-provider
  • Each app/package has ≤5 rule overrides, all with justification comments
  • All apps and packages pass pnpm lint with new config (CI green)
  • Old juno-typescript.mjs and juno.mjs removed from packages/config
  • Migration documented in CLAUDE.md or ADR
  • Template PR created showing migration pattern for other apps/packages to follow

Tasks

Phase 1: Foundation

  • Research and document Vite's default ESLint setup for React-TS
  • Create packages/config/eslint/vite-react-ts.mjs with pure TypeScript rules
  • Export new config from @cloudoperators/juno-config package
  • Document baseline configuration

Phase 2: Migration

Each app/package follows this workflow:

  1. Switch to new config in eslint.config.mjs
  2. Remove all custom rule disables
  3. Fix violations category-by-category (separate PRs per category)
  4. Document any necessary exceptions with justification comments

Apps migration (simplest → most complex):

  • Migrate apps/example (template PR for others to follow)
  • Migrate apps/template
  • Migrate apps/doop
  • Migrate apps/heureka
  • Migrate apps/supernova
  • Migrate apps/greenhouse
  • Migrate apps/carbon

Packages migration (parallelizable with apps):

  • Migrate packages/communicator
  • Migrate packages/k8s-client
  • Migrate packages/messages-provider
  • Migrate packages/oauth
  • Migrate packages/template
  • Migrate packages/url-state-provider
  • Migrate packages/greenhouse-auth-provider
  • Migrate packages/ui-components (likely most complex, has Storybook plugin)

Phase 3: Cleanup

  • Verify all apps and packages using vite-react-ts.mjs
  • Remove packages/config/eslint/juno-typescript.mjs
  • Remove packages/config/eslint/juno.mjs (if unused)
  • Update packages/config/package.json exports
  • Update CLAUDE.md with new ESLint guidelines
  • Create ADR documenting the migration decision

Dependencies

  • Supersedes original epic [EPIC](apps): Migrate to Clean TypeScript ESLint Configuration #1565 (different approach to same problem)
  • No external dependencies - can start immediately
  • No blocking dependencies between app/package migrations (fully parallelizable)
  • Note: packages/ui-components uses eslint-plugin-storybook - the new config must be compatible

Additional Notes

Strategy: Create new config alongside old one, migrate apps independently, then remove old config.

Per-app workflow details:

  1. Switch app's eslint.config.mjs to import vite-react-ts.mjs
  2. Remove all custom rule disables
  3. Run pnpm --filter {app} lint to capture violations
  4. Fix violations by category (easy → medium → hard):
    • Easy: no-unused-vars, prefer-const, no-extra-boolean-cast
    • Medium: @typescript-eslint/no-unsafe-assignment, no-floating-promises
    • Hard: @typescript-eslint/no-unsafe-member-access, no-unsafe-call
  5. Each category = separate PR
  6. Document necessary exceptions with justification comments

Risk mitigation:

  • Old config stays until all apps migrated (rollback possible)
  • App-specific overrides allowed with mandatory justifications
  • Feature branches prevent CI blocking unrelated work
  • Template PR from apps/example provides pattern for team

Technical details:

Current problematic config structure:

// packages/config/eslint/juno-typescript.mjs (lines 35-36)
pluginJs.configs.recommended,  // JS rules
...tseslint.configs.recommendedTypeCheckedOnly,  // TS rules
// ☝️ These conflict with each other

Target clean structure:

// packages/config/eslint/vite-react-ts.mjs
...tseslint.configs.recommendedTypeChecked  // Only TS rules
// No JS/TS mixing

Questions to resolve before starting:

  1. Should we use Vite's exact ESLint config or customize slightly?
  2. Enforce stricter rules than Vite defaults (e.g., strict: true)?
  3. Which app for template/pilot PR (recommend apps/example)?
  4. ADR or just update CLAUDE.md?

Metadata

Metadata

Assignees

No one assigned

    Labels

    doopDoop related issuesgreenhouseGreenhouse core related taskheurekaHeureka related issuessupernovaAll tasks related to supernova

    Type

    Projects

    Status

    New

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions