Skip to content

bump updates - #25

Merged
HardMax71 merged 13 commits into
mainfrom
bump_dependencies
Dec 21, 2025
Merged

bump updates#25
HardMax71 merged 13 commits into
mainfrom
bump_dependencies

Conversation

@HardMax71

@HardMax71 HardMax71 commented Dec 18, 2025

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • OpenAPI export + generated TypeScript API client and CLI commands
    • New toast-based notification system with persistent notification store
  • Improvements

    • Frontend migrated to Svelte 5 with broad TypeScript adoption
    • Updated styling: Tailwind v4, design tokens, refreshed UI components and animations
    • Improved auth, settings, and notification UX; safer API interactions
    • Updated base images and dependency/tooling bumps for frontend/backend
  • Chores

    • CI/workflow updates to support spec generation and build steps

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Dec 18, 2025

Copy link
Copy Markdown

Walkthrough

Migrates the frontend to TypeScript and Svelte 5, replaces routing and notification systems with a generated OpenAPI TypeScript SDK/client and new stores, updates CI workflows and Docker bases, bumps backend deps and introduces Pydantic auth responses, and reorganizes many frontend utilities, styles, and build tooling.

Changes

Cohort / File(s) Change Summary
GitHub Workflows
​.github/workflows/docs.yml, ​.github/workflows/mypy.yml, ​.github/workflows/ruff.yml, ​.github/workflows/security.yml, ​.github/workflows/tests.yml
Bumped astral-sh/setup-uv v5→v7; tests pre-pull image updated (uv:0.9.17→0.9.18); artifact/upload action versions bumped; docs workflow now installs backend deps and generates OpenAPI spec.
Backend deps & auth
backend/pyproject.toml, backend/app/api/routes/auth.py, backend/app/schemas_pydantic/user.py, backend/app/core/providers.py, backend/app/services/idempotency/redis_repository.py, backend/tests/...
Dependency bumps (multidict, redis, coverage, pytest-asyncio, ruff); auth endpoints now return Pydantic models (LoginResponse, TokenValidationResponse, MessageResponse); Redis health checks switched to execute_command("PING"); test converted from sync helper to async/await with added assertions.
Dockerfiles
cert-generator/Dockerfile, frontend/Dockerfile, frontend/Dockerfile.prod
cert-generator: Alpine base bumped and reproducible, arch-aware kubectl/mkcert pinning added; frontend base images bumped node:20→node:22 (including alpine variant).
Deploy / OpenAPI tooling
deploy.sh, frontend/openapi-ts.config.ts
Added openapi and types commands to generate OpenAPI JSON and TypeScript client; added @hey-api/openapi-ts config for client generation.
Frontend build & TS migration
frontend/rollup.config.js, frontend/package.json, frontend/tsconfig.json, frontend/scripts/setupTypeScript.js, frontend/src/main.ts
Project entry moved to src/main.ts; Rollup and plugins updated for TypeScript; Svelte upgraded to v5 and runes enabled; script for automated TS setup removed; new TS config and generate:api script added; main bootstraps generated client.
Tailwind / styles
frontend/postcss.config.cjs, frontend/src/app.css, frontend/src/styles/*.css, frontend/tailwind.config.cjs
PostCSS plugin changed to @tailwindcss/postcss; major CSS refactor for Tailwind v4/tokenized theming; new pages.css added; prior tailwind.config.cjs deleted.
Frontend routing & pages
frontend/src/App.svelte, frontend/src/routes/...
Many components/pages migrated to TypeScript and Svelte 5 runes ($state/$effect); router swapped svelte-routing → @mateothegreat/svelte5-router (Link/navigate → route/goto); replaced notifications with toast API and integrated generated API client calls.
Frontend admin & components
frontend/src/routes/admin/*, frontend/src/components/*
Admin pages converted to TS and SDK usage; accessibility and UI tweaks; Notifications replaced by ToastContainer; NotificationCenter, Spinner updated to TS/Svelte5 patterns.
Stores removed
frontend/src/stores/*.js, frontend/src/lib/*.js (many)
Removed legacy JS modules: auth, notifications, executions, theme, api wrapper, fetch-utils, request-manager, eventStreamClient, session-handler, auth-utils, user-settings.
Stores added / migrated
frontend/src/stores/auth.ts, frontend/src/stores/theme.ts, frontend/src/stores/toastStore.ts, frontend/src/stores/notificationStore.ts, frontend/src/lib/settings-cache.ts, frontend/src/lib/user-settings.ts
Added typed TS Svelte stores: auth (with persistence/verifyAuth), theme (typed, persisted), toastStore (new toast API), typed notificationStore, settings-cache and user-settings wrappers that use generated SDK.
Frontend lib replaced / generated
frontend/src/lib/api/... (many generated files: sdk.gen.ts, client.gen.ts, client/*, core/*, types.gen.ts, index.ts)
Replaced legacy api wrapper with a full OpenAPI-generated TypeScript SDK and client: client factory, typed endpoint functions (~100+), SSE support, serializers, interceptors, and utilities; index now exports generated types (and runtime SDK in sdk.gen.ts).
Main bootstrap & misc
frontend/src/config.js, frontend/src/utils/meta.ts, .gitignore, docs/architecture/*, mkdocs.yml
Removed empty backendUrl export; meta utilities typed; .gitignore lib paths anchored; added docs for frontend build and Svelte5 migration and updated mkdocs navigation.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant User
    participant Frontend as Svelte App
    participant Client as Generated Client/SDK
    participant Backend as FastAPI
    participant Redis as Redis

    User->>Frontend: UI action (login / execute / fetch)
    Frontend->>Client: call generated endpoint (e.g., loginApi..., createExecution...)
    Client->>Backend: HTTP request (/api/v1/...)
    Backend->>Redis: execute_command("PING") / data ops
    Redis-->>Backend: PONG / data response
    Backend-->>Client: JSON response (Pydantic models)
    Client-->>Frontend: typed data or error
    Frontend->>User: update UI / show toast notification
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

  • Files/areas needing extra attention:
    • frontend-wide Svelte 4→5 migration (runes: $state/$effect/$derived) and updated component lifecycle patterns.
    • Router replacement: ensure all navigate/Link → goto/route usages and route-action bindings are correct.
    • Generated SDK integration: verify runtime vs types-only exports, client configuration (baseUrl, credentials) and call sites in components.
    • Auth flow: removed legacy auth.js and added auth.ts + auth-init changes — validate persistence, verifyAuth caching, login/logout behaviors.
    • Notification transition: confirm all addNotification → addToast sites updated and timer/cleanup logic in toastStore + ToastContainer component.
    • SSE / streaming behavior: eventStreamClient and executions store removals vs generated client SSE support — ensure feature parity where required.
    • Backend Redis ping change: execute_command("PING") compatibility with redis client versions.

Poem

🐇
I hopped through diffs with nimble toes,
Swapped routes for runes and trimmed old bows.
An SDK bloomed from spec so bright,
Toasts now cheer each frontend flight.
Carrots, types, and build-time glows—hip hooray, compose!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'bump updates' is vague and generic, using a non-descriptive term that does not clearly convey meaningful information about the changeset. Consider using a more descriptive title that highlights the primary change, such as 'Upgrade frontend/backend dependencies and migrate to Svelte 5' or similar.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bump_dependencies

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (4)
.github/workflows/mypy.yml (1)

18-18: LGTM! Consistent with other workflow updates.

The setup-uv action version bump is consistent across all workflows in this PR.

.github/workflows/security.yml (1)

18-18: LGTM! Consistent with other workflow updates.

The setup-uv action version bump is consistent across all workflows in this PR.

.github/workflows/docs.yml (1)

35-35: LGTM! Consistent with other workflow updates.

The setup-uv action version bump is consistent across all workflows in this PR.

.github/workflows/tests.yml (1)

164-164: LGTM! Consistent with other workflow updates.

The setup-uv action version bump is consistent across all workflows in this PR.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f81caa and e64b605.

⛔ Files ignored due to path filters (1)
  • backend/uv.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • .github/workflows/docs.yml (2 hunks)
  • .github/workflows/mypy.yml (1 hunks)
  • .github/workflows/ruff.yml (1 hunks)
  • .github/workflows/security.yml (1 hunks)
  • .github/workflows/tests.yml (3 hunks)
  • backend/pyproject.toml (4 hunks)
  • backend/tests/unit/events/test_event_dispatcher.py (1 hunks)
  • cert-generator/Dockerfile (2 hunks)
  • frontend/Dockerfile (1 hunks)
  • frontend/Dockerfile.prod (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build Backend
  • GitHub Check: Build Frontend
  • GitHub Check: Backend Tests
🔇 Additional comments (13)
frontend/Dockerfile (1)

1-1: Verify Node.js 22 compatibility before merging.

The upgrade from Node 20 to Node 22 maintains consistency with production but introduces breaking changes that require testing:

  • Test all development dependencies work with Node 22
  • Verify HTTP header handling (Node 22 changes header casing)
  • Ensure unhandled promise rejections are properly caught (Node 22 terminates on unhandled rejections)
  • Run the full test suite and build scripts locally
frontend/Dockerfile.prod (1)

2-2: Node.js 22 is production-ready and LTS—ensure build and dependencies are compatible before upgrade.

Node.js 22 is in Active LTS and ready for production with support through April 2027. Before deploying this upgrade:

  • Verify all npm dependencies are compatible with Node 22 (check package.json and package-lock.json)
  • Run the full build and test suite locally to catch breaking changes early
  • Check if the engines field in package.json needs updating to reflect Node 22

Node.js 22 includes several breaking changes that directly impact application behavior, so testing is essential before production deployment.

cert-generator/Dockerfile (2)

18-20: LGTM - kubectl installation implementation is correct.

The kubectl installation uses appropriate curl flags (-fsSL) and correctly installs the binary to /usr/local/bin/kubectl with executable permissions. The implementation is sound, assuming the kubectl version is verified as current (see previous comment).


22-22: LGTM - mkcert installation implementation is correct.

The mkcert installation correctly downloads the binary to /usr/local/bin/mkcert and sets executable permissions. The implementation is sound, assuming the mkcert version is verified as current (see previous comment).

.github/workflows/tests.yml (2)

63-63: LGTM! Minor container image version bump.

The UV container image is being updated from 0.9.17 to 0.9.18, which is a patch-level change and should be safe.


219-219: Verify v6 compatibility with Node.js 24 runtime and runner version requirements.

The v5 release updated @actions/artifact to v4.0.0, and v6 now runs on Node.js 24 and requires a minimum Actions Runner version of 2.327.1, so self-hosted runners must be updated before upgrading. v5 had preliminary support for Node.js 24 but was by default still running on Node.js 20; v6 now defaults to Node.js 24. Breaking changes regarding artifact naming and hidden file exclusion were introduced in v4, not v6.

Likely an incorrect or invalid review comment.

backend/pyproject.toml (5)

60-60: LGTM! Minor version bump.

The multidict update from 6.6.3 to 6.7.0 is a minor version change that should maintain backward compatibility.


137-137: LGTM! Minor version bump within the same major version.

The coverage update from 7.6.2 to 7.13.0 maintains the same major version and should be backward compatible.


149-149: LGTM! Minor version bump.

The ruff update from 0.12.7 to 0.14.9 is within the 0.x series and should maintain compatibility, though new linting rules may be introduced.


104-104: Verify Python 3.10+ compatibility before upgrading redis-py from 5.2.1 to 7.1.0.

Version 7.1.0 of redis-py exists and is officially released. The codebase uses only async Redis operations (via redis.asyncio) with basic get/set/cache operations for rate limiting, idempotency, SSE bus, and coordination—no Redis Search commands.

The primary consideration for this upgrade is redis-py 7.1.0 requires Python 3.10+, which differs from 5.2.1. Standard async Redis operations remain compatible across versions 5.x through 7.x, so the version jump carries minimal breaking change risk for your codebase's usage patterns.


146-146: pytest-asyncio upgrade (0.24.0→1.3.0) is compatible—the codebase already follows required patterns.

The upgrade includes v1.0.0's major change: removal of the deprecated event_loop fixture. However, the codebase is already compatible because:

  • No custom event_loop fixture definitions exist
  • Async fixtures use explicit loop_scope configuration rather than event_loop fixture overrides
  • Configuration already includes asyncio_mode = "auto" and asyncio_default_fixture_loop_scope = "function"
  • Tests properly use @pytest.mark.asyncio decorator

The test_event_dispatcher.py and other async tests follow the modern pattern and require no changes.

backend/tests/unit/events/test_event_dispatcher.py (1)

38-56: LGTM! Excellent refactor to modern pytest-asyncio patterns.

The test has been properly converted to use the new pytest-asyncio 1.x style:

  • Removed the event_loop fixture parameter (no longer needed)
  • Changed to async def and uses await directly instead of event_loop.run_until_complete()
  • Added explicit metric assertions for better test coverage

This aligns perfectly with the pytest-asyncio upgrade from 0.24.0 to 1.3.0 in pyproject.toml.

.github/workflows/ruff.yml (1)

18-18: Review the node runtime upgrade in setup-uv v7 for self-hosted runner compatibility.

The action upgrade from v5 to v7 includes a breaking change: the runtime switched from node20 to node24, which requires self-hosted runners to be up to date. Additionally, the deprecated server-url input has been removed. Verify that any server-url configurations are removed from this workflow.

Comment thread .github/workflows/docs.yml
Comment thread cert-generator/Dockerfile Outdated
Comment thread cert-generator/Dockerfile
@codecov-commenter

codecov-commenter commented Dec 18, 2025

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Flag Coverage Δ
backend 80.12% <100.00%> (+0.10%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
backend/app/api/routes/auth.py 92.20% <100.00%> (-0.10%) ⬇️
backend/app/core/providers.py 94.09% <100.00%> (ø)
backend/app/schemas_pydantic/user.py 100.00% <100.00%> (ø)
...ckend/app/services/idempotency/redis_repository.py 89.41% <100.00%> (ø)

... and 6 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e64b605 and 5a74f4f.

📒 Files selected for processing (4)
  • backend/app/core/providers.py (1 hunks)
  • backend/app/services/idempotency/redis_repository.py (1 hunks)
  • backend/tests/fixtures/real_services.py (2 hunks)
  • frontend/package.json (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
backend/tests/fixtures/real_services.py (1)
backend/tests/conftest.py (1)
  • redis_client (184-186)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Scan Backend
  • GitHub Check: Build Frontend
  • GitHub Check: Backend Tests
🔇 Additional comments (6)
backend/app/services/idempotency/redis_repository.py (1)

140-141: LGTM: Redis health check updated to use explicit command execution.

The change from ping() to execute_command("PING") is functionally equivalent for health check purposes where the return value is not evaluated. This aligns with similar updates across the codebase.

backend/app/core/providers.py (1)

129-133: LGTM: Connection test updated consistently.

The Redis connection test now uses execute_command("PING") instead of the ping() helper, maintaining consistency with the health check pattern applied throughout the codebase.

backend/tests/fixtures/real_services.py (2)

43-58: LGTM: Redis connection verification updated.

The Redis connectivity check in connect_redis now uses execute_command("PING"), aligning with the pattern applied across production code.


328-339: LGTM: Service readiness checks updated consistently.

Both the immediate Redis health check and the wait_for_service lambda now use execute_command("PING"), maintaining consistency with the updated Redis interaction pattern throughout the codebase.

frontend/package.json (2)

36-36: dotenv v17.2.3 is secure and introduces minimal breaking changes.

The upgrade from ^16.4.5 to ^17.2.3 is a major bump but carries minimal risk. The primary change is that runtime logging now displays by default (previously hidden by quiet: true). If you want to suppress this informational output, set the quiet option to true or use the DOTENV_CONFIG_QUIET environment variable.


53-53: Verify Express 5 compatibility with dev tooling and build setup.

The express dependency has been bumped from ^4.21.1 to ^5.2.1, a major version change with documented breaking changes. While Express 5 maintains the same basic API, there are breaking changes that could cause applications built with Express 4 to fail. Notable changes include removal of app.del() requiring app.delete() instead and req.query becoming read-only.

Since this is in devDependencies, ensure any development server, build scripts, or test setup using Express is compatible with v5. Review the migration guide for required updates before merging.

Comment thread frontend/package.json

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/package.json (1)

12-12: Duplicate @babel/runtime in both dependencies and devDependencies.

@babel/runtime is listed in both dependencies (line 12, ^7.27.6) and devDependencies (line 49, ^7.24.7) with different versions. This can cause version conflicts and bloat.

🔎 Suggested fix

Keep it only in dependencies with the higher version, or consolidate based on actual usage:

  "devDependencies": {
-   "@babel/runtime": "^7.24.7",
    "@tailwindcss/forms": "^0.5.11",
♻️ Duplicate comments (1)
frontend/package.json (1)

43-43: Node.js 18+ requirement for sirv-cli v3.

This concern was already raised in a previous review. Ensure your CI/CD and development environments meet the Node 18+ requirement for sirv-cli v3.

🧹 Nitpick comments (10)
frontend/rollup.config.js (1)

176-179: Consider preserving console.error and console.warn in production.

Using drop_console: true removes all console.* calls including console.error and console.warn, which can be valuable for debugging production issues. If you only want to remove verbose logging, consider using pure_funcs instead:

🔎 Suggested change to preserve error/warning logs
             compress: {
                 passes: 2,
-                drop_console: true
+                pure_funcs: ['console.log', 'console.debug', 'console.info']
             },
frontend/src/styles/pages.css (1)

178-180: Consider a no-JS fallback for animation elements.

Elements matching [style*="--fly-delay"] are set to opacity: 0, relying on JavaScript to trigger the animation. If JS fails or delays, these elements remain invisible.

🔎 Optional: Add noscript fallback or inline visibility

You could add a <noscript> style block in your HTML to ensure visibility when JS is unavailable:

<noscript>
  <style>
    [style*="--fly-delay"] { opacity: 1 !important; }
  </style>
</noscript>
frontend/src/routes/admin/AdminUsers.svelte (1)

4-5: Toast migration and accessibility wiring look consistent

The swap from notifications to addToast is coherent across load/save/delete/rate‑limit paths, and the new id/for hookups on filters and user form fields correctly pair labels with controls. The updated bg-black/50 overlays are also consistent with the shared modal-backdrop style. I don’t see functional regressions here; any further DRY’ing (e.g., a shared modal backdrop or common API error helper) would be a nice‑to‑have, not a blocker.

Also applies to: 65-67, 82-83, 90-91, 98-99, 122-123, 138-139, 155-160, 384-387, 406-407, 410-412, 422-423, 469-480, 523-537, 541-549, 553-561, 593-624, 821-837, 851-853, 911-914, 1195-1219, 1223-1237, 1241-1258, 1262-1268

frontend/src/stores/toastStore.js (1)

1-16: Toast store works; consider minor robustness tweaks

The store implementation is correct and should work fine in practice. A couple of small refinements you might consider:

  • Prefer slice over legacy substr and slightly strengthen id generation (e.g., include Date.now() or crypto.randomUUID() when available) to minimise even theoretical collision risk.
  • Normalise the message argument before string interpolation so that undefined or opaque objects don’t surface as "undefined" or "[object Object]" in the UI.

These are polish items; the current code is functionally sound.

frontend/src/routes/admin/AdminSettings.svelte (1)

4-5: Settings toasts and form label wiring look good

The switch to addToast for load/save/reset feedback is consistent and preserves user messaging, and the new id/for attributes on numeric inputs and selects correctly associate labels without altering behaviour. If the backend ever becomes strict about numeric types, you might later normalise these bind:value fields to numbers before calling api.put, but that’s not required for this PR.

Also applies to: 27-28, 37-40, 53-56, 85-103, 112-125, 117-120, 122-130, 139-163

frontend/src/routes/admin/AdminSagas.svelte (1)

4-5: Saga toasts and accessibility tweaks are solid; consider de‑duplicating reloads

The migration to addToast for saga load/detail/error paths looks correct, and the added id/for labels plus refined focus styles and modal backdrop (bg-black/50 dark:bg-black/70) improve usability without changing behaviour.

One minor optimisation to consider: when stateFilter changes, you currently call loadSagas() both from the <select on:change={loadSagas}> handler and from the reactive block that resets currentPage and invokes loadSagas(). Dropping one of these would avoid firing two identical requests on each state change.

Also applies to: 120-121, 134-135, 147-148, 250-251, 271-282, 312-323, 327-337, 346-357, 361-373, 544-557, 635-636

frontend/src/styles/components.css (1)

25-28: Design‑system Tailwind updates are coherent

The updated @apply sets (e.g., bg-black/50 backdrops, focus:outline-hidden, unified pagination/dropdown styling, and the new skeleton/feature-card utilities) align with the Tailwind v4 style tokens and don’t change selector APIs. This should be a safe visual refresh; any further consolidation (like consistently using the .modal-backdrop utility in Svelte templates instead of repeating equivalent inline classes) would just be a nice clean‑up.

Also applies to: 43-48, 55-59, 105-106, 170-188, 191-210, 229-233, 236-250, 253-259, 339-358, 360-378

frontend/src/routes/admin/AdminEvents.svelte (1)

4-5: Event browser toasts and accessibility upgrades look solid

The transition from notifications to addToast is consistent across load/delete/replay/export/user‑overview flows, with clear messages and severities, and the added keyboard/ARIA hooks (focusable rows, Enter key handling, overlay close buttons with bg-black/50 backdrops) materially improve accessibility without changing business logic. Everything here looks functionally sound; reusing the shared .modal-backdrop utility instead of inlined backdrop classes would be a minor future clean‑up.

Also applies to: 96-99, 118-119, 136-144, 181-184, 208-209, 219-220, 262-265, 279-280, 688-795, 817-830, 917-924, 929-939, 1024-1030, 1114-1120, 1313-1321

frontend/src/routes/Settings.svelte (1)

596-596: Improved modal accessibility with button element.

Replacing the <div> overlay with a <button> element is better for keyboard accessibility and semantic correctness. The aria-label="Close modal" provides context for assistive technologies.

Consider adding type="button" to prevent unintended form submission if the modal is ever nested inside a form.

🔎 Suggested enhancement
-        <button class="fixed inset-0 bg-black/50 cursor-default" on:click={() => showHistory = false} aria-label="Close modal"></button>
+        <button type="button" class="fixed inset-0 bg-black/50 cursor-default" on:click={() => showHistory = false} aria-label="Close modal"></button>
frontend/src/components/ToastContainer.svelte (1)

14-38: Consider avoiding direct object mutation for cleaner reactivity.

The current pattern mutates the toast object directly (lines 19, 27, 37) and then forces a store update with toasts.update(n => n). While this works, it relies on reference semantics and the manual re-trigger pattern.

A more idiomatic Svelte approach would update through the store's update method with a new object spread. However, this is a minor consideration—the current implementation is functional and performant for the use case.

🔎 Alternative pattern (optional)
// Instead of:
toast.progress = progress;
toasts.update(n => n);

// Consider:
toasts.update(items => 
    items.map(t => t.id === toast.id ? { ...t, progress } : t)
);

This creates new object references, making reactivity explicit. Trade-off is slightly more allocation overhead, which is negligible for a small toast list.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5a74f4f and d203401.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (29)
  • frontend/package.json (1 hunks)
  • frontend/postcss.config.cjs (1 hunks)
  • frontend/rollup.config.js (1 hunks)
  • frontend/src/App.svelte (13 hunks)
  • frontend/src/app.css (4 hunks)
  • frontend/src/components/Footer.svelte (1 hunks)
  • frontend/src/components/Header.svelte (2 hunks)
  • frontend/src/components/ToastContainer.svelte (8 hunks)
  • frontend/src/config.js (0 hunks)
  • frontend/src/lib/session-handler.js (2 hunks)
  • frontend/src/main.js (0 hunks)
  • frontend/src/routes/Editor.svelte (24 hunks)
  • frontend/src/routes/Home.svelte (2 hunks)
  • frontend/src/routes/Login.svelte (4 hunks)
  • frontend/src/routes/Notifications.svelte (6 hunks)
  • frontend/src/routes/Privacy.svelte (2 hunks)
  • frontend/src/routes/Register.svelte (3 hunks)
  • frontend/src/routes/Settings.svelte (12 hunks)
  • frontend/src/routes/admin/AdminEvents.svelte (19 hunks)
  • frontend/src/routes/admin/AdminLayout.svelte (3 hunks)
  • frontend/src/routes/admin/AdminSagas.svelte (10 hunks)
  • frontend/src/routes/admin/AdminSettings.svelte (7 hunks)
  • frontend/src/routes/admin/AdminUsers.svelte (25 hunks)
  • frontend/src/stores/auth.js (0 hunks)
  • frontend/src/stores/notifications.js (0 hunks)
  • frontend/src/stores/toastStore.js (1 hunks)
  • frontend/src/styles/components.css (1 hunks)
  • frontend/src/styles/pages.css (1 hunks)
  • frontend/tailwind.config.cjs (0 hunks)
💤 Files with no reviewable changes (5)
  • frontend/src/config.js
  • frontend/src/main.js
  • frontend/src/stores/notifications.js
  • frontend/src/stores/auth.js
  • frontend/tailwind.config.cjs
🧰 Additional context used
🧬 Code graph analysis (1)
frontend/src/lib/session-handler.js (2)
frontend/src/stores/auth.js (10)
  • isAuthenticated (29-29)
  • isAuthenticated (29-29)
  • username (30-30)
  • username (30-30)
  • userId (31-31)
  • userId (31-31)
  • userRole (32-32)
  • userRole (32-32)
  • csrfToken (34-34)
  • csrfToken (34-34)
frontend/src/stores/toastStore.js (1)
  • addToast (7-12)
🪛 Biome (2.1.2)
frontend/src/app.css

[error] 9-9: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)


[error] 77-77: This @import is in the wrong position.

Any @import rules must precede all other valid at-rules and style rules in a stylesheet (ignoring @charset and @layer), or else the @import rule is invalid.
Consider moving import position.

(lint/correctness/noInvalidPositionAtImportRule)


[error] 80-80: This @import is in the wrong position.

Any @import rules must precede all other valid at-rules and style rules in a stylesheet (ignoring @charset and @layer), or else the @import rule is invalid.
Consider moving import position.

(lint/correctness/noInvalidPositionAtImportRule)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build Frontend
  • GitHub Check: Backend Tests
🔇 Additional comments (37)
frontend/src/routes/Privacy.svelte (2)

23-23: LGTM! Valid shadow utility refinement.

The change from shadow-sm to shadow-xs is a valid Tailwind v4 utility adjustment that creates a more subtle shadow effect on the container.


29-29: The prose-page custom class is properly defined and correctly implemented.

The class is defined in frontend/src/app.css with well-structured @apply directives for h2, p, and section elements. This approach successfully implements the centralized typography system using utility classes rather than inline styles.

frontend/src/components/Footer.svelte (1)

40-42: LGTM! Good migration to relative path.

Switching from a hardcoded localhost URL to a relative /grafana/... path improves deployment flexibility and allows the app to work across different environments without configuration changes.

frontend/src/routes/Notifications.svelte (2)

6-8: LGTM! Clean migration to toast-based feedback.

The switch from addNotification to addToast aligns with the broader toast system migration in this PR while maintaining the existing notificationStore for data operations.


135-147: Good accessibility improvement.

Adding id attributes to inputs and properly associating labels via for attributes improves form accessibility for screen readers and enables clicking on labels to focus inputs.

frontend/src/styles/pages.css (1)

1-5: Good centralization of page-specific styles.

Moving scattered inline styles to a central CSS file improves maintainability and reduces bundle duplication across route components.

frontend/package.json (1)

52-52: Review Express v5 compatibility and breaking changes.

Express v5 is not very different from Express 4, but there are breaking changes that make applications built with Express 4 incompatible with v5. Key breaking changes include: deprecated API methods like router.param(fn) are no longer supported; route wildcards have breaking changes (e.g., "*" must be "/*splat"); promise rejections in async route handlers are automatically forwarded to error handlers; and method signatures for res.send() and res.json() require chaining with res.status(). Ensure your dev server code is updated accordingly.

frontend/postcss.config.cjs (1)

1-5: LGTM! Correct Tailwind v4 migration.

The PostCSS configuration has been properly updated to use the new @tailwindcss/postcss plugin, which replaces the previous separate tailwindcss and autoprefixer plugins. This aligns with Tailwind v4's built-in Lightning CSS integration.

frontend/src/routes/Register.svelte (2)

3-3: LGTM! Proper toast system migration.

The import has been correctly updated to use the new toast system.


25-43: LGTM! Consistent toast usage across all feedback scenarios.

All notification calls have been properly migrated to addToast, maintaining the same message content and feedback types (error, warning, success) for password validation, registration success, and error handling.

frontend/src/components/Header.svelte (3)

98-98: LGTM! Tailwind v4 shadow and styling updates.

The header styling has been correctly updated with shadow-xs (Tailwind v4 shadow scale) and modern backdrop blur effects.


101-101: LGTM! Proper Tailwind v4 flex utility migration.

The flex utilities have been correctly updated from flex-shrink-0 to shrink-0, which is the new Tailwind v4 syntax per the migration guide.

Also applies to: 149-149


144-144: LGTM! Correct Tailwind v4 opacity syntax.

The ring styling has been properly updated to use the slash opacity syntax (ring-black/5 and dark:ring-white/10), which is the correct Tailwind v4 approach for color opacity.

frontend/src/routes/Login.svelte (2)

4-4: LGTM! Toast system migration.

The import has been correctly updated to use the new toast system.


22-48: LGTM! Consistent toast usage across login flow.

All authentication feedback paths (redirected auth message, successful login, and error handling) have been properly migrated to use addToast, maintaining the same user experience.

frontend/src/routes/admin/AdminLayout.svelte (2)

4-4: LGTM! Toast system migration in admin layout.

The import has been correctly updated to use the new toast system.


40-59: LGTM! Consistent toast usage for admin authentication.

All admin authentication and authorization feedback paths have been properly migrated to use addToast, maintaining clear error messages for authentication failures and access control.

frontend/src/lib/session-handler.js (2)

2-2: LGTM! Toast system migration for session handling.

The import has been correctly updated to use the new toast system.


21-21: LGTM! Session expiration feedback migrated to toast.

The session expiration warning has been properly migrated to use addToast, maintaining the same user feedback with appropriate warning type.

frontend/src/App.svelte (2)

17-17: LGTM! Toast container component migration.

The import has been correctly updated to use the new ToastContainer component, replacing the previous Notifications component.


54-212: LGTM! Consistent toast container usage across all routes.

The ToastContainer component has been properly integrated across all route definitions (admin, public, and protected routes), ensuring consistent toast notification display throughout the application. The component placement within the layout structure is appropriate.

frontend/src/routes/Home.svelte (1)

30-63: Animation is properly defined in global styles.

The hero-animate-flyIn class is defined in frontend/src/styles/pages.css (line 173) with the flyInHome keyframe animation. The CSS variables --fly-y and --fly-delay are correctly configured to support the inline customization used throughout the component. The animation setup is correct and will work as expected.

frontend/src/routes/Settings.svelte (3)

6-6: LGTM - Toast store migration.

The import change from addNotification to addToast aligns with the new toast notification system introduced in this PR.


369-369: Correct Tailwind v4 shadow utility.

The change from shadow-sm to shadow-xs follows Tailwind v4 conventions where the shadow scale has been adjusted.


389-393: Good accessibility improvement.

Adding explicit id attributes to dropdowns and for attributes to labels creates proper programmatic associations. This improves screen reader support and allows clicking labels to focus inputs.

frontend/src/app.css (6)

4-13: Correct Tailwind CSS v4 setup.

The migration to Tailwind v4's CSS-first configuration is properly implemented:

  • @import "tailwindcss" replaces the old three-directive approach
  • @plugin "@tailwindcss/forms" with strategy: class is valid v4 syntax
  • @variant dark for class-based dark mode is correct

The static analysis warning about strategy: class is a false positive—this is valid Tailwind v4 plugin configuration syntax.


83-89: Good use of Tailwind v4 @Utility directive.

The @utility directive is the correct v4 approach for defining custom utilities, replacing the old @layer utilities pattern for single-class definitions.


105-105: Correct Tailwind v4 focus ring syntax.

focus:ring-3 follows v4's updated ring width utilities (default changed from 3px to 1px, so explicit ring-3 restores the previous behavior).


177-177: Correct use of focus:outline-hidden.

In Tailwind v4, outline-hidden replaces outline-none for completely removing outlines. This is the correct migration pattern.


227-274: LGTM - Form component styling.

The input group, stacked input, form control, and multi-select styles are well-organized with proper dark mode variants and consistent spacing.


414-508: Well-structured editor and admin component styles.

The new sections for editor-specific styles, prose typography, and admin components are cleanly organized with clear section headers. The custom scrollbar styling and output container classes provide good consistency for the code execution UI.

frontend/src/components/ToastContainer.svelte (6)

3-3: LGTM - Toast store import.

Clean import of the new toast store API with toasts, removeToast, and TOAST_DURATION.


47-55: LGTM - Reactive timer initialization.

The reactive block correctly initializes timers for new toasts and guards against duplicate timer creation with both timerStarted and timers[toast.id] checks.


57-60: Proper cleanup on component destruction.

The onDestroy handler correctly clears all interval timers and resets the registry, preventing memory leaks.


89-89: Correct Tailwind v4 focus utility.

focus:outline-hidden is the correct v4 replacement for focus:outline-none when you want to completely hide the outline.


111-148: Clean toast rendering implementation.

The template correctly handles:

  • Unique keys with toast.id for proper list reconciliation
  • Smooth fly transitions for enter/exit animations
  • Pause/resume behavior via mouseenter/mouseleave
  • Accessible role="alert" and aria-label on close button
  • Conditional timer bar rendering with progress scaling

150-190: LGTM - Scoped styles.

The CSS is well-structured with proper fixed positioning, responsive breakpoints, and the timer animation using transform-origin for smooth countdown visualization.

Comment thread frontend/package.json
Comment thread frontend/src/app.css Outdated
Comment thread frontend/src/routes/Editor.svelte Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/routes/admin/AdminSagas.svelte (1)

101-123: Client-side filtering may cause inconsistent pagination.

The API call at Lines 101-107 uses limit and offset for server-side pagination, but the subsequent client-side filtering (Lines 112-123 for executionIdFilter and searchQuery) operates on the already-paginated results. This means:

  1. If filtered items are excluded, fewer than itemsPerPage items may display
  2. totalItems from the server doesn't reflect client-side filtering

Consider either moving these filters to the API query or updating totalItems after client-side filtering.

🧹 Nitpick comments (10)
frontend/rollup.config.js (1)

183-183: Improved console removal strategy.

The change from pure_funcs: ['console.log'] to drop_console: true is an improvement as it removes all console.* calls in production builds, not just console.log. This is more comprehensive and explicit.

frontend/src/stores/notificationStore.ts (1)

44-49: Consider making the notification limit configurable.

Line 47 hard-codes a 100-notification limit with .slice(0, 100). Consider making this configurable to allow flexibility for different use cases.

🔎 Suggested improvement
+const MAX_NOTIFICATIONS = 100;
+
 function createNotificationStore() {
     const { subscribe, set, update } = writable<State>({
         notifications: [],
         loading: false,
         error: null
     });

     return {
         subscribe,

         async load(limit = 20, options: { include_tags?: string[]; exclude_tags?: string[]; tag_prefix?: string } = {}) {
             // ... existing code ...
         },

         add(notification: NotificationResponse) {
             update(s => ({
                 ...s,
-                notifications: [notification, ...s.notifications].slice(0, 100)
+                notifications: [notification, ...s.notifications].slice(0, MAX_NOTIFICATIONS)
             }));
         },
frontend/src/components/NotificationCenter.svelte (1)

257-273: Good accessibility improvements.

The additions of keyboard support (on:keydown), tabindex="0", role="button", and aria-label properly make the notification items accessible to keyboard users and screen readers.

Consider extracting the shared logic into a helper function to reduce duplication between the on:click and on:keydown handlers:

🔎 Optional: Extract shared handler logic
+                            function handleNotificationActivate(notification) {
+                                markAsRead(notification);
+                                if (notification.action_url) {
+                                    window.location.href = notification.action_url;
+                                }
+                            }

Then use it in both handlers:

-                            on:click={() => {
-                                markAsRead(notification);
-                                if (notification.action_url) {
-                                    window.location.href = notification.action_url;
-                                }
-                            }}
-                            on:keydown={(e) => {
-                                if (e.key === 'Enter') {
-                                    markAsRead(notification);
-                                    if (notification.action_url) {
-                                        window.location.href = notification.action_url;
-                                    }
-                                }
-                            }}
+                            on:click={() => handleNotificationActivate(notification)}
+                            on:keydown={(e) => e.key === 'Enter' && handleNotificationActivate(notification)}
frontend/src/routes/admin/AdminUsers.svelte (1)

475-491: Remove unnecessary async keyword from handleValidationError.

This function is declared async but contains no await expressions. The async keyword is unnecessary and misleading.

Proposed fix
-    async function handleValidationError(error, defaultMessage) {
+    function handleValidationError(error, defaultMessage) {

Also note: at line 156 and 448, this function is called with await, which is now unnecessary after removing async. Consider removing those await calls as well for consistency:

-            await handleValidationError(error, 'Failed to save rate limits');
+            handleValidationError(error, 'Failed to save rate limits');
frontend/src/stores/toastStore.ts (1)

5-9: Consider exporting the Toast interface.

The Toast interface is used internally but not exported. Components consuming the toasts store (like a ToastContainer) may need this type for proper TypeScript typing.

Proposed fix
-interface Toast {
+export interface Toast {
     id: string;
     message: string;
     type: ToastType;
 }
frontend/src/routes/admin/AdminEvents.svelte (1)

1122-1128: Consider using a <div> instead of <button> for the modal backdrop.

While this works functionally, using a <button> element for a modal backdrop overlay is semantically unusual. A <div> with role="presentation" or no role would be more appropriate since this isn't an actionable button in the traditional sense. The tabindex="-1" mitigates keyboard issues, but screen readers may still announce it as a button.

🔎 Suggested alternative
-            <button
-                class="fixed inset-0 bg-black/50 border-none cursor-default"
-                on:click={() => selectedEvent = null}
-                on:keydown={(e) => e.key === 'Escape' && (selectedEvent = null)}
-                aria-label="Close modal"
-                tabindex="-1"
-            ></button>
+            <div
+                class="fixed inset-0 bg-black/50 cursor-default"
+                on:click={() => selectedEvent = null}
+                on:keydown={(e) => e.key === 'Escape' && (selectedEvent = null)}
+                role="presentation"
+            ></div>
frontend/src/lib/settings-cache.ts (1)

58-76: Shallow copy in updateCachedSetting may cause unintended mutations.

The spread operator { ...current } creates only a shallow copy. When traversing nested paths like "notifications.execution_completed", the intermediate objects are mutated in place rather than cloned. This could lead to unexpected behavior if other code holds references to the original settings object.

🔎 Suggested fix with deep clone
 export function updateCachedSetting(path: string, value: unknown): void {
     const current = get(settingsCache);
     if (!current) return;

-    const updated = { ...current } as Record<string, unknown>;
+    const updated = JSON.parse(JSON.stringify(current)) as Record<string, unknown>;
     const pathParts = path.split('.');
     let target = updated;

     for (let i = 0; i < pathParts.length - 1; i++) {
         const part = pathParts[i];
         if (!target[part] || typeof target[part] !== 'object') {
             target[part] = {};
         }
         target = target[part] as Record<string, unknown>;
     }

     target[pathParts[pathParts.length - 1]] = value;
     setCachedSettings(updated as UserSettings);
 }

Alternatively, consider using a utility like structuredClone() for a more performant deep clone if browser support allows.

frontend/src/routes/Settings.svelte (1)

246-262: Redundant assignment before loadSettings() call.

Line 251 assigns settings = data, but then Line 255 calls loadSettings() which will overwrite settings with fresh data from the API. The intermediate assignment appears unnecessary.

🔎 Suggested simplification
             const { data, error } = await restoreSettingsApiV1UserSettingsRestorePost({
                 body: { timestamp, reason: 'User requested restore' }
             });
             if (error) throw error;

-            settings = data;
             historyCache = null;
             historyCacheTime = 0;

             await loadSettings();
frontend/src/components/ToastContainer.svelte (1)

14-38: Direct mutation of toast object may cause reactivity issues.

Lines 18-19, 27, and 37 directly mutate properties on the toast object (toast.progress, toast.timerStarted). While Line 28 calls toasts.update(n => n) to trigger reactivity, mutating the object directly is a Svelte anti-pattern that can lead to subtle bugs if the update call is missed or reordered.

🔎 Suggested approach using store update

Consider updating toast properties through the store's update method:

         const intervalId = setInterval(() => {
             const elapsed = Date.now() - start;
-            const currentDuration = TOAST_DURATION * (toast.progress ?? 1);
-            const progress = Math.max(0, (currentDuration - elapsed) / TOAST_DURATION);
-
-            toast.progress = progress;
-            toasts.update(n => n);
+            toasts.update(items => items.map(t => {
+                if (t.id === toast.id) {
+                    const currentDuration = TOAST_DURATION * (t.progress ?? 1);
+                    const progress = Math.max(0, (currentDuration - elapsed) / TOAST_DURATION);
+                    return { ...t, progress };
+                }
+                return t;
+            }));
frontend/src/lib/api/sdk.gen.ts (1)

21-1127: Consider adding a trailing newline.

The file ends without a trailing newline character, which many linters and formatters expect. Since this is an auto-generated file, consider checking the generator configuration (likely in frontend/openapi-ts.config.ts) to ensure proper formatting.

#!/bin/bash
# Check if the openapi-ts config has formatting options
cat frontend/openapi-ts.config.ts
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d203401 and 87d7970.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (49)
  • .github/workflows/docs.yml (1 hunks)
  • .gitignore (1 hunks)
  • backend/app/api/routes/auth.py (7 hunks)
  • backend/app/schemas_pydantic/user.py (1 hunks)
  • deploy.sh (4 hunks)
  • frontend/openapi-ts.config.ts (1 hunks)
  • frontend/package.json (2 hunks)
  • frontend/rollup.config.js (4 hunks)
  • frontend/scripts/setupTypeScript.js (0 hunks)
  • frontend/src/App.svelte (13 hunks)
  • frontend/src/components/Header.svelte (3 hunks)
  • frontend/src/components/NotificationCenter.svelte (1 hunks)
  • frontend/src/components/ProtectedRoute.svelte (1 hunks)
  • frontend/src/components/ToastContainer.svelte (8 hunks)
  • frontend/src/lib/api.js (0 hunks)
  • frontend/src/lib/api/client.gen.ts (1 hunks)
  • frontend/src/lib/api/index.ts (1 hunks)
  • frontend/src/lib/api/sdk.gen.ts (1 hunks)
  • frontend/src/lib/api/setup.ts (1 hunks)
  • frontend/src/lib/auth-init.ts (8 hunks)
  • frontend/src/lib/auth-utils.js (0 hunks)
  • frontend/src/lib/eventStreamClient.js (0 hunks)
  • frontend/src/lib/fetch-utils.js (0 hunks)
  • frontend/src/lib/request-manager.js (0 hunks)
  • frontend/src/lib/session-handler.js (0 hunks)
  • frontend/src/lib/settings-cache.ts (3 hunks)
  • frontend/src/lib/user-settings.js (0 hunks)
  • frontend/src/lib/user-settings.ts (1 hunks)
  • frontend/src/main.ts (1 hunks)
  • frontend/src/routes/Editor.svelte (26 hunks)
  • frontend/src/routes/Home.svelte (3 hunks)
  • frontend/src/routes/Login.svelte (4 hunks)
  • frontend/src/routes/Notifications.svelte (6 hunks)
  • frontend/src/routes/Register.svelte (2 hunks)
  • frontend/src/routes/Settings.svelte (13 hunks)
  • frontend/src/routes/admin/AdminEvents.svelte (16 hunks)
  • frontend/src/routes/admin/AdminSagas.svelte (9 hunks)
  • frontend/src/routes/admin/AdminSettings.svelte (5 hunks)
  • frontend/src/routes/admin/AdminUsers.svelte (19 hunks)
  • frontend/src/stores/auth.js (0 hunks)
  • frontend/src/stores/auth.ts (1 hunks)
  • frontend/src/stores/executions.js (0 hunks)
  • frontend/src/stores/notificationStore.js (0 hunks)
  • frontend/src/stores/notificationStore.ts (1 hunks)
  • frontend/src/stores/theme.js (0 hunks)
  • frontend/src/stores/theme.ts (1 hunks)
  • frontend/src/stores/toastStore.ts (1 hunks)
  • frontend/src/utils/meta.ts (2 hunks)
  • frontend/tsconfig.json (1 hunks)
💤 Files with no reviewable changes (12)
  • frontend/src/lib/eventStreamClient.js
  • frontend/src/stores/notificationStore.js
  • frontend/src/lib/api.js
  • frontend/scripts/setupTypeScript.js
  • frontend/src/lib/auth-utils.js
  • frontend/src/lib/request-manager.js
  • frontend/src/lib/fetch-utils.js
  • frontend/src/lib/session-handler.js
  • frontend/src/lib/user-settings.js
  • frontend/src/stores/auth.js
  • frontend/src/stores/theme.js
  • frontend/src/stores/executions.js
🚧 Files skipped from review as they are similar to previous changes (9)
  • frontend/src/routes/Home.svelte
  • frontend/src/routes/admin/AdminSettings.svelte
  • frontend/src/components/Header.svelte
  • frontend/src/routes/Notifications.svelte
  • frontend/src/routes/Login.svelte
  • .github/workflows/docs.yml
  • frontend/src/routes/Editor.svelte
  • frontend/package.json
  • frontend/src/App.svelte
🧰 Additional context used
🧬 Code graph analysis (9)
frontend/src/lib/user-settings.ts (6)
frontend/src/stores/theme.ts (2)
  • theme (39-51)
  • setTheme (77-79)
frontend/src/lib/auth-init.ts (1)
  • isAuthenticated (160-166)
frontend/src/stores/auth.ts (1)
  • isAuthenticated (43-43)
frontend/src/lib/api/sdk.gen.ts (3)
  • updateThemeApiV1UserSettingsThemePut (862-871)
  • getUserSettingsApiV1UserSettingsGet (838-843)
  • updateEditorSettingsApiV1UserSettingsEditorPut (890-899)
frontend/src/lib/api/types.gen.ts (3)
  • Theme (1157-1157)
  • UserSettings (1239-1253)
  • EditorSettings (199-211)
frontend/src/lib/settings-cache.ts (2)
  • getCachedSettings (15-35)
  • setCachedSettings (37-50)
frontend/src/lib/api/client.gen.ts (1)
frontend/src/lib/api/types.gen.ts (1)
  • ClientOptions (3678-3680)
frontend/src/stores/theme.ts (1)
frontend/src/lib/user-settings.ts (1)
  • saveThemeSetting (14-36)
frontend/src/stores/notificationStore.ts (2)
frontend/src/lib/api/types.gen.ts (1)
  • NotificationResponse (655-666)
frontend/src/lib/api/sdk.gen.ts (4)
  • getNotificationsApiV1NotificationsGet (942-947)
  • markNotificationReadApiV1NotificationsNotificationIdReadPut (952-957)
  • markAllReadApiV1NotificationsMarkAllReadPost (962-967)
  • deleteNotificationApiV1NotificationsNotificationIdDelete (1006-1011)
frontend/src/lib/settings-cache.ts (1)
frontend/src/lib/api/types.gen.ts (1)
  • UserSettings (1239-1253)
backend/app/api/routes/auth.py (2)
backend/app/schemas_pydantic/user.py (5)
  • LoginResponse (135-142)
  • MessageResponse (126-132)
  • TokenValidationResponse (145-152)
  • UserCreate (22-28)
  • UserResponse (58-71)
backend/app/api/dependencies.py (1)
  • current_user (10-15)
frontend/src/lib/api/setup.ts (2)
frontend/src/lib/api/client.gen.ts (1)
  • client (16-16)
frontend/src/stores/auth.ts (1)
  • csrfToken (48-48)
frontend/src/lib/auth-init.ts (2)
frontend/src/stores/auth.ts (2)
  • verifyAuth (107-145)
  • isAuthenticated (43-43)
frontend/src/lib/user-settings.ts (1)
  • loadUserSettings (38-65)
frontend/src/lib/api/sdk.gen.ts (1)
frontend/src/lib/api/types.gen.ts (5)
  • ClientOptions (3678-3680)
  • LoginApiV1AuthLoginPostData (1287-1292)
  • LoginApiV1AuthLoginPostResponse (1310-1310)
  • LoginApiV1AuthLoginPostError (1301-1301)
  • GetCurrentUserProfileApiV1AuthMeGetData (1337-1342)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Backend Tests
🔇 Additional comments (49)
.gitignore (1)

16-17: Improve pattern specificity by root-anchoring paths.

Converting lib/ and lib64/ to /lib/ and /lib64/ restricts matching to the repository root, preventing over-ignoring of legitimate lib/ or lib64/ directories that may exist in subdirectories (e.g., backend/lib/, frontend/lib/). This is a sensible refinement.

Verify that this change aligns with your intent—i.e., you want to ignore only root-level lib/ and lib64/, not nested ones in subdirectories.

backend/app/schemas_pydantic/user.py (2)

135-142: LGTM! Type-safe response model improves API contract.

The LoginResponse model is well-structured and provides clear type safety for the login endpoint response.


145-152: LGTM! Clear contract for token validation responses.

The TokenValidationResponse model properly types the token verification endpoint response with appropriate fields.

backend/app/api/routes/auth.py (5)

14-20: LGTM! Imports correctly reference the new response models.

The updated imports properly include the typed response models needed for the endpoint refactoring.


29-35: LGTM! Type-safe login response properly implemented.

The login endpoint now returns a strongly-typed LoginResponse instead of a dict, improving API contract clarity and type safety. All required fields are correctly populated.

Also applies to: 120-125


230-234: LGTM! Token validation response properly typed.

The verify_token endpoint now returns a strongly-typed TokenValidationResponse, providing clear type safety for token validation results. All fields are correctly populated.

Also applies to: 257-262


283-287: LGTM! Logout response now properly typed.

The logout endpoint returns a strongly-typed MessageResponse instead of a dict, maintaining consistency with the other endpoint improvements.

Also applies to: 317-317


1-7: These dependency versions are compatible with no identified issues.

Pydantic includes tests for FastAPI with its own tests, so new versions of Pydantic (above 1.0.0) are always compatible with FastAPI. Dishka features automatic REQUEST and SESSION scope management using middleware, passing Request object as context data to providers, and automatic injection of dependencies into handler function, indicating stable FastAPI integration. FastAPI 0.124.0 (Dec 2025) has no known security advisories or critical issues that would affect these dependencies together.

frontend/tsconfig.json (1)

1-23: LGTM! Well-configured TypeScript setup.

The TypeScript configuration is appropriate for a Svelte + Rollup project:

  • Modern target (ES2020) and module settings
  • Bundler resolution mode for Rollup compatibility
  • Strict mode for type safety
  • Path alias $lib/* follows Svelte conventions
  • Appropriate includes/excludes
frontend/rollup.config.js (2)

116-116: LGTM! TypeScript integration is properly configured.

The changes correctly integrate TypeScript into the build pipeline:

  • Entry point updated from .js to .ts
  • TypeScript plugin configured with source maps for development
  • Configuration follows Rollup + TypeScript best practices

Also applies to: 158-161


8-8: @rollup/plugin-typescript is compatible with TypeScript 5.7.2.

The plugin requires at least TypeScript 3.7, so the TypeScript version specified is compatible. No action needed on this import.

frontend/src/utils/meta.ts (1)

1-39: LGTM! Excellent TypeScript migration.

The changes add proper type safety to the metadata utilities:

  • PageMetaInfo interface provides clear structure
  • Optional parameters allow flexible usage
  • setAttribute is more explicit and safer than direct property assignment
  • Typed pageMeta ensures consistency across page definitions
frontend/src/stores/notificationStore.ts (1)

1-14: LGTM! Well-structured store initialization.

The imports and state interface are properly defined:

  • Correct Svelte store imports
  • Uses generated API client functions
  • Clear state structure with appropriate types
frontend/src/components/ProtectedRoute.svelte (1)

4-5: LGTM! Import path normalization for TypeScript.

The import paths have been updated to remove .js extensions, aligning with TypeScript module resolution and the broader migration across the project.

frontend/src/main.ts (1)

1-9: The migration from Axios to the generated API client is complete and properly configured. No breaking changes exist. The new API setup correctly handles credentials with credentials: 'include' (equivalent to the removed axios.defaults.withCredentials = true) and adds CSRF token handling for mutation requests. All Axios usage has been removed from the codebase.

frontend/openapi-ts.config.ts (1)

1-14: OpenAPI specification path is correctly configured.

The configuration references ../docs/reference/openapi.json, which correctly resolves to the OpenAPI 3.1.0 specification file at docs/reference/openapi.json in the repository root. The file exists and is valid.

frontend/src/lib/api/index.ts (1)

1-3: LGTM! Auto-generated index correctly aggregates API exports.

This index file properly re-exports the generated API types and SDK. The generated .gen files are committed to version control, which is a valid and common strategy for projects using code generation tools like @hey-api/openapi-ts.

frontend/src/lib/api/setup.ts (1)

1-16: Well-structured CSRF protection setup.

The implementation correctly:

  • Configures credentials for cookie-based auth
  • Injects CSRF token only for state-mutating HTTP methods
  • Uses Svelte's get() to read store value synchronously in the interceptor
frontend/src/routes/Register.svelte (1)

36-42: Clean migration to generated API client and toast notifications.

The error handling pattern correctly:

  • Destructures the error from the API response
  • Throws to trigger the catch block on API errors
  • Extracts error details with appropriate fallback chain
deploy.sh (1)

363-378: Sensible fallback pattern for spec generation.

The function correctly ensures the OpenAPI spec exists before generating the TypeScript client. The set -e at the top of the script will handle failures from npm run generate:api.

frontend/src/lib/api/client.gen.ts (1)

1-16: Auto-generated file — no manual changes needed.

This file is generated by @hey-api/openapi-ts and correctly sets up the API client. Configuration is applied separately in setup.ts. Ensure this file is regenerated via ./deploy.sh types when the backend API changes, rather than edited manually.

frontend/src/routes/admin/AdminUsers.svelte (4)

3-12: LGTM - Clean API and notification system migration.

The imports are well-organized, shifting to the generated OpenAPI client functions and the new toastStore for notifications. This aligns with the broader refactoring across the frontend.


67-80: Good error handling pattern with fallback.

The API call pattern correctly handles both the data extraction and error throwing. The fallback to empty array on error is appropriate for a list view.


533-547: Good accessibility improvement.

Adding explicit id and for attributes on input/label pairs improves form accessibility for screen readers and assistive technologies.

Also applies to: 551-559, 563-571


862-862: Consistent modal backdrop styling.

The updated bg-black/50 backdrop styling is cleaner than the previous opacity-based approach and aligns with modern Tailwind patterns.

Also applies to: 923-923, 1206-1206

frontend/src/stores/toastStore.ts (1)

14-23: Solid implementation with good message normalization.

The message normalization logic correctly handles various error shapes (message, detail properties, or stringification). The auto-removal pattern is clean and appropriate for toast notifications.

frontend/src/stores/theme.ts (3)

26-37: Lazy loading pattern handles circular dependencies well.

The dynamic import of user-settings and auth modules prevents potential circular dependency issues during module initialization. The nullable references with guards at line 46 ensure safe access.


61-68: System theme listener properly handles 'auto' mode.

The matchMedia listener correctly re-applies the theme only when the current preference is 'auto'. The update pattern ensures the store value is preserved while triggering the side effect.


71-75: Theme toggle cycles through all three options.

The toggle cycles light → dark → auto → light, which provides users with the full range of theme options. This is a nice UX touch.

frontend/src/lib/user-settings.ts (1)

14-36: Consistent save pattern with proper error handling.

Both saveThemeSetting and saveEditorSettings follow a consistent pattern: auth guard, API call, cache update, and proper error handling. The return types (true, false, undefined) clearly communicate success, failure, and not-applicable states.

Also applies to: 67-89

frontend/src/stores/auth.ts (4)

19-31: Auth state persistence with expiry is well-implemented.

The 24-hour expiry for persisted auth state is reasonable, and the error handling with silent failure is appropriate for localStorage operations.


50-52: Good use of promise deduplication for auth verification.

The verifyPromise guard prevents concurrent verification requests, which avoids race conditions and unnecessary API calls. The 30-second cache duration is appropriate for reducing verification overhead.


136-139: Returning cached auth state on network error may be misleading.

When verifyAuth catches an exception (likely a network error), it returns the cached value if available (line 137). This could return true even though the server might have invalidated the session. Consider whether failing closed (returning false) is more appropriate for security.

Please verify this is the intended behavior. If the network is temporarily unavailable, should the user remain "authenticated" based on cached state, or should they be prompted to re-authenticate?


64-89: Login flow is well-structured with proper state management.

The login function correctly updates all stores, persists state, updates the cache, and attempts to fetch the user profile. The fire-and-forget profile fetch (line 87) is acceptable since the essential auth data is already available from the login response.

frontend/src/routes/admin/AdminEvents.svelte (3)

3-12: LGTM! Clean API client and toast store migration.

The imports are well-organized, switching from legacy API calls to typed API client functions and from addNotification to addToast. This aligns with the PR's modernization goals.


85-112: Solid error handling pattern with the new API client.

The refactored loadEvents function properly destructures { data, error } from the API response, throws on error to trigger the catch block, and uses optional chaining for safe property access. The toast notification provides user feedback on failure.


834-837: Good accessibility improvement for table rows.

Adding keyboard interaction (on:keydown for Enter), tabindex="0", role="button", and aria-label makes the clickable rows accessible to keyboard and screen reader users.

frontend/src/lib/settings-cache.ts (1)

8-13: Well-structured typed cache interface.

The CacheData interface properly types the localStorage structure with data and timestamp, and the settingsCache store is correctly typed as UserSettings | null.

frontend/src/routes/Settings.svelte (2)

3-11: LGTM! Consistent API client and toast migration.

The imports follow the same pattern as other admin components, using dedicated API wrapper functions and the centralized toast store for user feedback.


333-344: Good accessibility improvement with id/for association.

Adding id="theme-select" and using for="theme-select" on the label properly associates the label with the button, improving screen reader support.

frontend/src/routes/admin/AdminSagas.svelte (2)

3-8: LGTM! Clean API client imports.

The saga-related API functions are properly imported and the toast store integration is consistent with other admin components.


321-332: Good accessibility improvements for filter inputs.

Adding id attributes and associated for labels on the search input improves form accessibility for screen readers and keyboard users.

frontend/src/components/ToastContainer.svelte (3)

3-3: LGTM! Clean migration to toast store.

The import correctly switches from the notifications store to the new toastStore, bringing in toasts, removeToast, and TOAST_DURATION.


111-148: LGTM! Well-structured toast rendering.

The template correctly iterates over $toasts, uses keyed each blocks for proper identity tracking, and implements mouse enter/leave for pause/resume functionality. The accessibility attributes (role="alert", aria-label) are appropriate.


151-172: LGTM! Clean CSS migration from notifications to toasts.

The .toasts-container and .toast classes are properly renamed and styled consistently with the component's new naming convention.

frontend/src/lib/auth-init.ts (3)

5-13: LGTM! Well-structured persistence interface and logic.

The PersistedAuth interface properly models the authentication state with appropriate types, and the persistence logic includes sensible expiry windows (24 hours for stored auth, 5 minutes for network error grace period).

Also applies to: 127-144


19-53: LGTM! Robust initialization pattern.

The initialization flow properly handles concurrent calls with Promise tracking, includes appropriate error handling, and uses the finally block to clean up the Promise reference. The separation into _performInitialization keeps the code clean.


55-96: LGTM! Auth verification flow is well-designed.

The distinction between persisted and non-persisted auth paths is clear, and the force refresh (verifyAuth(true)) for persisted auth ensures validation. The fallback logic with _handleVerificationError provides good resilience for transient network issues.

frontend/src/lib/api/sdk.gen.ts (1)

1-19: LGTM! Well-structured auto-generated SDK.

The Options type definition properly extends ClientOptions and provides flexibility for custom client instances and metadata. The file is correctly marked as auto-generated by @hey-api/openapi-ts.

Comment thread backend/app/schemas_pydantic/user.py Outdated
Comment thread deploy.sh
Comment thread frontend/src/lib/user-settings.ts
Comment thread frontend/src/stores/auth.ts Outdated
Comment thread frontend/src/stores/notificationStore.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
frontend/src/lib/user-settings.ts (1)

38-65: Past issue resolved: no redundant API call.

Good use of setThemeLocal at lines 42 and 58 to apply theme without triggering saveThemeSetting, avoiding the redundant PUT request that was flagged in the previous review.

🧹 Nitpick comments (8)
backend/app/schemas_pydantic/user.py (2)

135-142: Consider using UserRole enum for the role field to improve type safety.

The role field is typed as str, which is inconsistent with other models in this file (e.g., UserBase, User, UserUpdate) that use the UserRole enum. Using the enum would provide better type safety and prevent invalid role values from being constructed. Pydantic 2.9.2 will automatically serialize the enum to a string in API responses, maintaining compatibility with the frontend TypeScript types.

🔎 Proposed refactor
 class LoginResponse(BaseModel):
     """Response model for successful login"""
     message: str
     username: str
-    role: str
+    role: UserRole
     csrf_token: str

145-152: Consider using UserRole enum for the role field to improve type safety.

Similar to LoginResponse, the role field should use the UserRole enum instead of str for consistency with other models in this file and to ensure type safety.

🔎 Proposed refactor
 class TokenValidationResponse(BaseModel):
     """Response model for token validation"""
     valid: bool
     username: str
-    role: str
+    role: UserRole
     csrf_token: str
docs/architecture/frontend-build.md (1)

263-286: Specify language for fenced code block.

The directory structure code block should specify a language identifier to comply with Markdown linting standards and ensure consistent rendering.

🔎 Proposed fix
-```
+```text
 frontend/
 ├── public/
 │   ├── index.html          # HTML shell
frontend/src/stores/theme.ts (2)

29-37: Consider adding error handling to dynamic imports.

If these imports fail (e.g., bundling issue), the variables remain null and backend persistence silently fails. Adding a .catch() would help with debugging.

🔎 Suggested improvement
 if (browser) {
     Promise.all([
         import('../lib/user-settings'),
         import('./auth')
     ]).then(([userSettings, auth]) => {
         saveThemeSetting = userSettings.saveThemeSetting;
         isAuthenticatedStore = auth.isAuthenticated;
+    }).catch((err) => {
+        console.warn('Failed to load theme persistence modules:', err);
     });
 }

39-51: The exposed update method bypasses persistence logic.

The raw update function is exposed directly, allowing external code to change the theme without triggering localStorage or backend persistence. Currently this is only used internally for the system theme listener (where the value doesn't actually change), but external usage could cause state inconsistency.

🔎 Suggested fix - wrap update to also persist
 export const theme = {
     subscribe,
     set: (value: ThemeValue) => {
         internalSet(value);
         if (browser) {
             localStorage.setItem(storageKey, value);
         }
         if (saveThemeSetting && isAuthenticatedStore && get(isAuthenticatedStore)) {
             saveThemeSetting(value);
         }
     },
-    update
+    update: (fn: (current: ThemeValue) => ThemeValue) => {
+        update((current) => {
+            const newValue = fn(current);
+            if (newValue !== current) {
+                if (browser) {
+                    localStorage.setItem(storageKey, newValue);
+                }
+                if (saveThemeSetting && isAuthenticatedStore && get(isAuthenticatedStore)) {
+                    saveThemeSetting(newValue);
+                }
+            }
+            return newValue;
+        });
+    }
 };
frontend/src/lib/user-settings.ts (1)

14-36: Consider validating theme value before API call.

The theme as Theme assertion at line 21 bypasses type safety. While callers currently pass valid values, explicit validation would catch issues at runtime rather than relying on API rejection.

🔎 Suggested improvement
+const VALID_THEMES: Theme[] = ['light', 'dark', 'auto'];
+
 export async function saveThemeSetting(theme: string): Promise<boolean | undefined> {
     if (!get(isAuthenticated)) {
         return;
     }

+    if (!VALID_THEMES.includes(theme as Theme)) {
+        console.error('Invalid theme value:', theme);
+        return false;
+    }
+
     try {
         const { error } = await updateThemeApiV1UserSettingsThemePut({
             body: { theme: theme as Theme }
         });
frontend/src/stores/auth.ts (2)

19-31: Consider extracting the 24-hour expiry as a named constant.

The magic number 24 * 60 * 60 * 1000 on line 25 could be extracted to a named constant (e.g., AUTH_STATE_EXPIRY_MS) for improved readability and maintainability.

🔎 Proposed refactor
+const AUTH_STATE_EXPIRY_MS = 24 * 60 * 60 * 1000; // 24 hours
+
 function getPersistedAuthState(): AuthState | null {
     if (typeof window === 'undefined') return null;
     try {
         const data = localStorage.getItem('authState');
         if (!data) return null;
         const parsed = JSON.parse(data) as AuthState;
-        if (Date.now() - parsed.timestamp > 24 * 60 * 60 * 1000) {
+        if (Date.now() - parsed.timestamp > AUTH_STATE_EXPIRY_MS) {
             localStorage.removeItem('authState');
             return null;
         }
         return parsed;
     } catch { return null; }
 }

64-89: Consider logging profile fetch failures for debugging.

The fetchUserProfile() call on line 87 silently swallows errors with an empty catch block. While graceful degradation is appropriate (allowing login to succeed even if profile fetch fails), the complete absence of error logging could make debugging issues difficult.

🔎 Proposed improvement
     authCache = { valid: true, timestamp: Date.now() };
-    try { await fetchUserProfile(); } catch {}
+    try { 
+        await fetchUserProfile(); 
+    } catch (error) {
+        console.warn('Failed to fetch user profile after login:', error);
+    }
     return true;
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 87d7970 and b12c195.

📒 Files selected for processing (8)
  • backend/app/schemas_pydantic/user.py (1 hunks)
  • docs/architecture/frontend-build.md (1 hunks)
  • frontend/rollup.config.js (4 hunks)
  • frontend/src/lib/user-settings.ts (1 hunks)
  • frontend/src/stores/auth.ts (1 hunks)
  • frontend/src/stores/notificationStore.ts (1 hunks)
  • frontend/src/stores/theme.ts (1 hunks)
  • mkdocs.yml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • frontend/rollup.config.js
  • frontend/src/stores/notificationStore.ts
🧰 Additional context used
🧬 Code graph analysis (4)
frontend/src/lib/user-settings.ts (4)
frontend/src/stores/auth.ts (1)
  • isAuthenticated (43-43)
frontend/src/lib/api/sdk.gen.ts (3)
  • updateThemeApiV1UserSettingsThemePut (862-871)
  • getUserSettingsApiV1UserSettingsGet (838-843)
  • updateEditorSettingsApiV1UserSettingsEditorPut (890-899)
frontend/src/lib/api/types.gen.ts (3)
  • Theme (1157-1157)
  • UserSettings (1239-1253)
  • EditorSettings (199-211)
frontend/src/lib/settings-cache.ts (3)
  • updateCachedSetting (58-76)
  • getCachedSettings (15-35)
  • setCachedSettings (37-50)
frontend/src/stores/auth.ts (3)
frontend/src/lib/auth-init.ts (1)
  • isAuthenticated (160-166)
backend/app/api/routes/auth.py (2)
  • login (30-125)
  • logout (284-317)
frontend/src/lib/api/sdk.gen.ts (4)
  • loginApiV1AuthLoginPost (24-34)
  • getCurrentUserProfileApiV1AuthMeGet (53-58)
  • logoutApiV1AuthLogoutPost (73-78)
  • verifyTokenApiV1AuthVerifyTokenGet (63-68)
backend/app/schemas_pydantic/user.py (2)
frontend/src/lib/api/types.gen.ts (2)
  • LoginResponse (595-600)
  • TokenValidationResponse (1169-1174)
frontend/src/stores/auth.ts (1)
  • username (44-44)
frontend/src/stores/theme.ts (1)
frontend/src/lib/user-settings.ts (1)
  • saveThemeSetting (14-36)
🪛 markdownlint-cli2 (0.18.1)
docs/architecture/frontend-build.md

263-263: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build
  • GitHub Check: Backend Tests
🔇 Additional comments (9)
docs/architecture/frontend-build.md (1)

1-347: Excellent comprehensive documentation!

This documentation provides thorough coverage of the frontend architecture, build pipeline, and development workflow. The inclusion of Mermaid diagrams, code examples, and troubleshooting guidance makes it immediately valuable for developers working with the codebase.

mkdocs.yml (1)

106-106: LGTM!

The navigation entry is correctly placed in the Architecture section and properly links to the new frontend build documentation.

frontend/src/stores/theme.ts (4)

1-12: LGTM!

Clean setup with proper SSR guards. The browser detection and system theme detection are correctly implemented with defensive ?. chaining for matchMedia.


14-24: LGTM!

Proper validation of stored theme values before use, with sensible fallback to defaultTheme.


53-69: LGTM!

Good reactive pattern for applying theme changes. The system preference listener correctly triggers reapplication only when 'auto' is active, and returning current prevents infinite loops.


71-87: LGTM!

Good separation of concerns: setTheme for full persistence, setThemeLocal for local-only updates (addressing the redundant API call issue from user-settings loading).

frontend/src/lib/user-settings.ts (2)

1-12: LGTM!

Clean imports with proper type imports from the generated API.


67-89: LGTM!

Consistent pattern with saveThemeSetting: auth check, API call, cache update, and proper error handling.

frontend/src/stores/auth.ts (1)

101-110: Excellent - logout now handles API failures gracefully.

The try/catch/finally pattern ensures local state is always cleared even if the logout API call fails, addressing the concern from the previous review. The error logging provides useful debugging information.

Comment thread frontend/src/stores/auth.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (2)
frontend/package.json (2)

34-34: The dotenv ^17.x runtime logging behavior has already been flagged in a previous review.


41-41: The sirv-cli ^3.0.1 Node.js 18+ requirement has already been flagged in a previous review.

🧹 Nitpick comments (18)
frontend/src/components/Spinner.svelte (2)

8-20: Consider narrowing the Record key types for stricter type safety.

The Record<string, string> type allows any string key. Using the actual union types would catch typos at compile time and provide better IntelliSense.

🔎 Proposed type refinement
-  const sizeClasses: Record<string, string> = {
+  const sizeClasses: Record<'small' | 'medium' | 'large' | 'xlarge', string> = {
     small: 'h-4 w-4',
     medium: 'h-6 w-6',
     large: 'h-8 w-8',
     xlarge: 'h-12 w-12'
   };

-  const colorClasses: Record<string, string> = {
+  const colorClasses: Record<'primary' | 'white' | 'current' | 'muted', string> = {
     primary: 'text-primary dark:text-primary-light',
     white: 'text-white',
     current: 'text-current',
     muted: 'text-gray-400 dark:text-gray-500'
   };

22-23: Fallback logic is redundant due to prop defaults.

Since size defaults to 'medium' and color defaults to 'primary' in the destructuring, the fallback expressions (|| sizeClasses.medium and || colorClasses.primary) will never execute.

🔎 Simplified version
-  let sizeClass = $derived(sizeClasses[size] || sizeClasses.medium);
-  let colorClass = $derived(colorClasses[color] || colorClasses.primary);
+  let sizeClass = $derived(sizeClasses[size]);
+  let colorClass = $derived(colorClasses[color]);
frontend/src/routes/admin/AdminUsers.svelte (1)

315-333: Non-null assertions could cause runtime errors.

The non-null assertions (rateLimitConfig!.rules) assume rateLimitConfig is not null, but if called when it is null, this will throw. The guard on line 316 only checks rateLimitConfig?.rules, not rateLimitConfig itself.

🔎 Suggested safer implementation
     function addNewRule(): void {
-        if (!rateLimitConfig?.rules) {
-            rateLimitConfig!.rules = [];
+        if (!rateLimitConfig) return;
+        if (!rateLimitConfig.rules) {
+            rateLimitConfig.rules = [];
         }
-        rateLimitConfig!.rules = [...rateLimitConfig!.rules, {
+        rateLimitConfig.rules = [...rateLimitConfig.rules, {
             endpoint_pattern: '',
             group: 'api',
             requests: 60,
             window_seconds: 60,
             burst_multiplier: 1.5,
             algorithm: 'sliding_window',
             priority: 0,
             enabled: true
         }];
     }
     
     function removeRule(index: number): void {
-        rateLimitConfig!.rules = rateLimitConfig!.rules!.filter((_, i) => i !== index);
+        if (!rateLimitConfig?.rules) return;
+        rateLimitConfig.rules = rateLimitConfig.rules.filter((_, i) => i !== index);
     }
frontend/src/routes/admin/AdminSettings.svelte (1)

12-20: Settings type could benefit from stronger typing.

Using Record<string, unknown> for nested settings objects loses type safety. Consider defining explicit interfaces for each settings section to catch typos in property names at compile time.

🔎 Example of stronger typing
interface ExecutionLimits {
    max_timeout_seconds?: number;
    max_memory_mb?: number;
    max_cpu_cores?: number;
    max_concurrent_executions?: number;
}

interface SecuritySettings {
    password_min_length?: number;
    session_timeout_minutes?: number;
    max_login_attempts?: number;
    lockout_duration_minutes?: number;
}

interface MonitoringSettings {
    metrics_retention_days?: number;
    log_level?: 'DEBUG' | 'INFO' | 'WARNING' | 'ERROR';
    enable_tracing?: boolean;
    sampling_rate?: number;
}

let settings = $state<{
    execution_limits: ExecutionLimits;
    security_settings: SecuritySettings;
    monitoring_settings: MonitoringSettings;
}>({
    execution_limits: {},
    security_settings: {},
    monitoring_settings: {}
});
frontend/src/routes/admin/AdminEvents.svelte (2)

434-446: Return type mismatch in getActiveFilterSummary.

The function returns items (a string[]) but the implicit return type annotation shows string. This should be explicitly typed for clarity.

🔎 Proposed fix
-    function getActiveFilterSummary(): string {
+    function getActiveFilterSummary(): string[] {
         const items: string[] = [];
         // ...
         return items;
     }

478-481: Dropdown close race condition.

The setTimeout(() => showExportMenu = false, 200) in onblur can cause issues if the user clicks a menu item - the blur fires before the click, potentially closing the menu before the action executes. The 200ms delay mitigates this but isn't fully reliable.

Consider using a mousedown event on menu items instead, or implementing a more robust click-outside pattern.

frontend/src/routes/admin/AdminSagas.svelte (2)

99-132: Client-side filtering after API fetch is inefficient.

The loadSagas function fetches data with server-side state filter, but then applies executionIdFilter and searchQuery filters client-side (lines 114-125). If the API supports these filters, consider passing them to reduce data transfer.

🔎 Suggested optimization

If the API supports execution_id and search text filters:

             const { data, error } = await listSagasApiV1SagasGet({
                 query: {
                     state: stateFilter || undefined,
+                    execution_id: executionIdFilter || undefined,
+                    search: searchQuery || undefined,
                     limit: itemsPerPage,
                     offset: (currentPage - 1) * itemsPerPage
                 }
             });
             if (error) throw error;
             sagas = data?.sagas || [];
             totalItems = data?.total || 0;
-
-            if (executionIdFilter) {
-                sagas = sagas.filter(s => s.execution_id.includes(executionIdFilter));
-            }
-            if (searchQuery) {
-                const query = searchQuery.toLowerCase();
-                sagas = sagas.filter(s =>
-                    s.saga_id.toLowerCase().includes(query) ||
-                    // ...
-                );
-            }

Please verify if the saga API endpoint supports execution_id and search text query parameters for server-side filtering.


231-246: Effect dependency tracking may cause unnecessary re-runs.

The first $effect (lines 232-236) condition if (autoRefresh || refreshRate) will always be true since refreshRate defaults to 5. This means setupAutoRefresh runs on every render where either value is read, not just on changes.

🔎 Suggested fix using explicit dependency tracking
-    // Re-setup auto refresh when settings change
-    $effect(() => {
-        if (autoRefresh || refreshRate) {
-            setupAutoRefresh();
-        }
-    });
+    // Re-setup auto refresh when settings change
+    let prevAutoRefresh = autoRefresh;
+    let prevRefreshRate = refreshRate;
+    $effect(() => {
+        if (autoRefresh !== prevAutoRefresh || refreshRate !== prevRefreshRate) {
+            prevAutoRefresh = autoRefresh;
+            prevRefreshRate = refreshRate;
+            setupAutoRefresh();
+        }
+    });

Alternatively, if you want it to run on mount and changes, just call setupAutoRefresh() unconditionally in the effect - the function already handles clearing the previous interval.

frontend/src/components/NotificationCenter.svelte (1)

263-290: Consider extracting duplicated navigation logic.

The onclick and onkeydown handlers share identical navigation logic. Extracting this to a helper function would reduce duplication and improve maintainability.

Suggested refactor
+    function handleNotificationAction(notification: NotificationResponse): void {
+        markAsRead(notification);
+        if (notification.action_url) {
+            if (notification.action_url.startsWith('/')) {
+                showDropdown = false;
+                goto(notification.action_url);
+            } else {
+                window.location.href = notification.action_url;
+            }
+        }
+    }
+
     <!-- In template -->
     onclick={() => {
-        markAsRead(notification);
-        if (notification.action_url) {
-            if (notification.action_url.startsWith('/')) {
-                showDropdown = false;
-                goto(notification.action_url);
-            } else {
-                window.location.href = notification.action_url;
-            }
-        }
+        handleNotificationAction(notification);
     }}
     onkeydown={(e) => {
         if (e.key === 'Enter') {
-            markAsRead(notification);
-            if (notification.action_url) {
-                if (notification.action_url.startsWith('/')) {
-                    showDropdown = false;
-                    goto(notification.action_url);
-                } else {
-                    window.location.href = notification.action_url;
-                }
-            }
+            handleNotificationAction(notification);
         }
     }}
frontend/src/routes/Register.svelte (1)

36-42: Consider typing the caught error.

The error handling works but uses implicit any typing. For better type safety:

🔎 Suggested improvement
         } catch (err) {
-            error = err?.detail || err?.message || "Registration failed. Please try again.";
+            const e = err as { detail?: string; message?: string };
+            error = e?.detail || e?.message || "Registration failed. Please try again.";
             addToast(error, "error");
frontend/src/routes/Notifications.svelte (1)

224-234: Consider adding use:route for SPA navigation.

The "View result" link uses a plain anchor without the router directive, which will cause a full page reload instead of client-side navigation.

🔎 Suggested fix
+                                            import { route } from '@mateothegreat/svelte5-router';
...
                                             <a
                                                 href={`/editor?execution=${execTag.split(':')[1]}`}
+                                                use:route
                                                 class="btn btn-ghost btn-sm text-blue-600 dark:text-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/20 ml-2"
                                                 onclick={(e) => e.stopPropagation()}
                                             >
frontend/src/App.svelte (2)

24-30: Consider using Svelte 5's $derived rune for theme reactivity.

The manual subscription with cleanup works correctly, but Svelte 5's $derived rune offers a more concise and idiomatic approach that automatically handles reactivity without explicit cleanup.

🔎 Simplified approach using $derived
-    // Theme value derived from store with proper cleanup
-    let themeValue = $state('auto');
-    const unsubscribeTheme = theme.subscribe(value => { themeValue = value; });
-
-    onDestroy(() => {
-        unsubscribeTheme();
-    });
+    // Theme value derived from store with proper cleanup
+    let themeValue = $derived($theme);

Note: This assumes the theme store is being used with Svelte 5's auto-subscription syntax ($theme).


98-187: Reduce route snippet boilerplate.

The current pattern creates two snippets per route (a wrapper snippet and a content snippet), resulting in ~90 lines of repetitive code. This can be consolidated by passing the component directly to the layout wrapper or using a factory function.

🔎 Proposed simplification

Instead of creating two snippets per route, you could define route configurations that combine the component with layout options:

+// Helper to create route snippets
+function createRouteSnippet(Component: any, isProtected = false, isFullWidth = false) {
+    return () => layoutWrapper(() => <Component />, isProtected, isFullWidth);
+}
+
 const publicRoutes: Route[] = [
-    { path: "/", component: homeSnippet },
-    { path: "/login", component: loginSnippet },
+    { path: "/", component: createRouteSnippet(Home, false) },
+    { path: "/login", component: createRouteSnippet(Login, false) },
     // ... etc
 ];

 const protectedRoutes: Route[] = [
-    { path: "/editor", component: editorSnippet },
-    { path: "/admin/events", component: adminEventsSnippet },
+    { path: "/editor", component: createRouteSnippet(Editor, true) },
+    { path: "/admin/events", component: createRouteSnippet(AdminEvents, true, true) },
     // ... etc
 ];
-
-<!-- All the individual snippet declarations can be removed -->

This reduces the code by ~70 lines while maintaining the same functionality.

frontend/src/routes/Settings.svelte (3)

17-17: Replace any types with proper type definitions.

Using any defeats the purpose of TypeScript and removes type safety. Consider defining proper interfaces or importing types from your API client.

🔎 Suggested type definitions
+interface UserSettings {
+    theme?: string;
+    notifications?: {
+        execution_completed?: boolean;
+        execution_failed?: boolean;
+        system_updates?: boolean;
+        security_alerts?: boolean;
+        channels?: string[];
+    };
+    editor?: {
+        theme?: string;
+        font_size?: number;
+        tab_size?: number;
+        use_tabs?: boolean;
+        word_wrap?: boolean;
+        show_line_numbers?: boolean;
+    };
+}
+
+interface HistoryItem {
+    timestamp: string | number;
+    field: string;
+    displayField?: string;
+    old_value: unknown;
+    new_value: unknown;
+    reason?: string;
+    isRestore?: boolean;
+}
+
-    let settings = $state<any>(null);
+    let settings = $state<UserSettings | null>(null);
-    let history = $state<any[]>([]);
+    let history = $state<HistoryItem[]>([]);

Also applies to: 22-22


132-133: Replace JSON-based deep equality check with a proper implementation.

Using JSON.stringify for deep equality comparison has several issues:

  • Property order affects comparison (same object, different order = not equal)
  • Doesn't handle undefined values consistently
  • Fails on circular references
  • Doesn't properly compare Date objects, functions, or other non-JSON types
🔎 More robust alternatives

Option 1: Use a library like lodash.isequal:

+import isEqual from 'lodash.isequal';
+
-    const deepEqual = (a: object | null | undefined, b: object | null | undefined): boolean =>
-        JSON.stringify(a) === JSON.stringify(b);
+    const deepEqual = (a: object | null | undefined, b: object | null | undefined): boolean =>
+        isEqual(a, b);

Option 2: Implement a proper deep equality function:

-    const deepEqual = (a: object | null | undefined, b: object | null | undefined): boolean =>
-        JSON.stringify(a) === JSON.stringify(b);
+    const deepEqual = (a: any, b: any): boolean => {
+        if (a === b) return true;
+        if (a == null || b == null) return false;
+        if (typeof a !== 'object' || typeof b !== 'object') return false;
+        
+        const keysA = Object.keys(a);
+        const keysB = Object.keys(b);
+        
+        if (keysA.length !== keysB.length) return false;
+        
+        for (const key of keysA) {
+            if (!keysB.includes(key) || !deepEqual(a[key], b[key])) {
+                return false;
+            }
+        }
+        
+        return true;
+    };

523-523: Reconsider modal overlay implementation.

Using a full-screen button as the modal overlay is unconventional. While the cursor-default class attempts to indicate it's not a typical button, this pattern can create accessibility and UX issues:

  • Screen readers will announce it as a button
  • The button covers the entire viewport, which may interfere with child interactions
  • Users might be confused by the clickable area
🔎 Alternative approach

Consider using a standard div with proper click handling:

-        <button class="fixed inset-0 bg-black/50 cursor-default" onclick={() => showHistory = false} aria-label="Close modal"></button>
+        <div 
+            class="fixed inset-0 bg-black/50 cursor-pointer" 
+            onclick={() => showHistory = false}
+            role="button"
+            tabindex="-1"
+            aria-label="Close modal"
+        ></div>

Or keep the button but make it positioned differently:

-        <button class="fixed inset-0 bg-black/50 cursor-default" onclick={() => showHistory = false} aria-label="Close modal"></button>
+        <button 
+            class="fixed inset-0 bg-black/50 -z-10" 
+            onclick={() => showHistory = false}
+            aria-label="Close modal backdrop"
+            tabindex="-1"
+        ></button>
frontend/src/routes/Editor.svelte (2)

510-551: Consider improving SSE event error handling.

Lines 548-550 catch errors during SSE event processing but only log them. If JSON parsing or event processing fails, the SSE connection remains open and may receive subsequent events that also fail. Consider whether to:

  • Close the SSE connection on repeated processing errors
  • Update the UI to indicate a processing issue
  • Fall back to the polling endpoint

This is not a blocker since there's a timeout and error fallback in place, but it could improve resilience.


807-810: Optional: Consider breaking down the indentation logic for clarity.

Lines 808-810 perform complex indentation detection and removal in tightly chained expressions. While functionally correct, extracting this into intermediate variables or a helper function would improve readability:

🔎 Suggested refactor
 if (example) {
     const lines = example.split('\n');
-    const firstLine = lines.find((line: string) => line.trim().length > 0);
-    const indentation = firstLine ? (firstLine.match(/^\s*/) ?? [''])[0] : '';
-    const cleanedScript = lines.map((line: string) => line.startsWith(indentation) ? line.substring(indentation.length) : line).join('\n').trim();
+    
+    // Detect common indentation from first non-empty line
+    const firstLine = lines.find((line: string) => line.trim().length > 0);
+    const indentation = firstLine?.match(/^\s*/)?.[0] ?? '';
+    
+    // Remove common indentation from all lines
+    const dedentedLines = lines.map((line: string) => 
+        line.startsWith(indentation) ? line.substring(indentation.length) : line
+    );
+    const cleanedScript = dedentedLines.join('\n').trim();
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b12c195 and 85b39fb.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (29)
  • docs/architecture/frontend-build.md (1 hunks)
  • docs/architecture/svelte5-migration.md (1 hunks)
  • frontend/package.json (2 hunks)
  • frontend/rollup.config.js (5 hunks)
  • frontend/src/App.svelte (3 hunks)
  • frontend/src/components/Header.svelte (8 hunks)
  • frontend/src/components/NotificationCenter.svelte (9 hunks)
  • frontend/src/components/ProtectedRoute.svelte (1 hunks)
  • frontend/src/components/Spinner.svelte (1 hunks)
  • frontend/src/components/ToastContainer.svelte (8 hunks)
  • frontend/src/lib/auth-init.ts (7 hunks)
  • frontend/src/lib/settings-cache.ts (1 hunks)
  • frontend/src/lib/user-settings.ts (1 hunks)
  • frontend/src/main.ts (1 hunks)
  • frontend/src/routes/Editor.svelte (35 hunks)
  • frontend/src/routes/Home.svelte (3 hunks)
  • frontend/src/routes/Login.svelte (3 hunks)
  • frontend/src/routes/Notifications.svelte (6 hunks)
  • frontend/src/routes/Register.svelte (3 hunks)
  • frontend/src/routes/Settings.svelte (18 hunks)
  • frontend/src/routes/admin/AdminEvents.svelte (43 hunks)
  • frontend/src/routes/admin/AdminLayout.svelte (4 hunks)
  • frontend/src/routes/admin/AdminSagas.svelte (18 hunks)
  • frontend/src/routes/admin/AdminSettings.svelte (4 hunks)
  • frontend/src/routes/admin/AdminUsers.svelte (42 hunks)
  • frontend/src/stores/auth.ts (1 hunks)
  • frontend/src/stores/toastStore.ts (1 hunks)
  • frontend/tsconfig.json (1 hunks)
  • mkdocs.yml (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/architecture/svelte5-migration.md
🚧 Files skipped from review as they are similar to previous changes (6)
  • frontend/src/components/ProtectedRoute.svelte
  • frontend/src/stores/auth.ts
  • frontend/src/routes/Login.svelte
  • frontend/src/lib/user-settings.ts
  • frontend/tsconfig.json
  • frontend/src/stores/toastStore.ts
🧰 Additional context used
🧬 Code graph analysis (2)
frontend/src/lib/settings-cache.ts (1)
frontend/src/lib/api/types.gen.ts (1)
  • UserSettings (1239-1253)
frontend/src/lib/auth-init.ts (2)
frontend/src/stores/auth.ts (2)
  • verifyAuth (112-150)
  • isAuthenticated (43-43)
frontend/src/lib/user-settings.ts (1)
  • loadUserSettings (38-65)
🪛 markdownlint-cli2 (0.18.1)
docs/architecture/frontend-build.md

127-127: Spaces inside code span elements

(MD038, no-space-in-code)


129-129: Code block style
Expected: fenced; Actual: indented

(MD046, code-block-style)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build Frontend
  • GitHub Check: Backend Tests
🔇 Additional comments (53)
frontend/src/components/Spinner.svelte (2)

1-6: LGTM! Clean migration to Svelte 5 runes.

The migration from export let to the $props() rune with TypeScript types is correctly implemented. Props are properly typed with union literals and sensible defaults.


26-47: LGTM! Proper accessibility and styling.

The SVG markup correctly applies the derived classes and includes appropriate accessibility attributes (role="status" and aria-label="Loading"). The Tailwind classes are compatible with v4.

frontend/src/routes/admin/AdminLayout.svelte (3)

1-14: LGTM! TypeScript and Svelte 5 migration looks correct.

The migration to TypeScript, Svelte 5 $state runes, and the new router/toast imports is properly implemented. The typed state declarations for user and loading are appropriate.


23-65: Auth flow implementation is solid.

The authentication verification logic correctly:

  • Verifies auth with backend first
  • Checks store values after verification
  • Saves redirect path before navigating to login
  • Handles both unauthenticated and non-admin cases appropriately

87-103: Router migration with use:route directive looks correct.

The navigation items correctly use the use:route action for client-side routing, and the conditional styling based on path prop is maintained.

frontend/src/routes/admin/AdminUsers.svelte (4)

1-66: State management and derived values are well-structured.

The TypeScript typing with $state and $derived runes is correctly implemented. The order of derived values (filteredUsers → totalPages → paginatedUsers) is correct to avoid dependency issues.


71-85: Robust API response handling.

The defensive handling of the API response (Array.isArray(data) ? data : data?.users || []) properly accounts for different response shapes.


503-533: Well-implemented validation error handler.

The handleValidationError function properly handles 422 validation errors with field-level messages, and provides fallback handling for other error types.


493-501: Effect for filter reset uses a good pattern.

The $effect correctly tracks previous filter values and resets pagination when filters change. This prevents stale pagination state.

frontend/src/routes/admin/AdminSettings.svelte (2)

29-75: API integration is cleanly implemented.

The load, save, and reset functions correctly use the new typed API client with proper error handling and toast notifications.


185-198: Event handler migration looks correct.

The onclick handlers properly reference the async functions without issues.

frontend/src/routes/admin/AdminEvents.svelte (4)

1-52: Well-typed state management with proper API types.

The typed state declarations using the imported API types (EventResponse[], EventDetailResponse, etc.) provide excellent type safety. The interval type declarations are correct.


90-118: Event loading with proper filter handling.

The date conversion to ISO format and defensive response handling (data?.events || []) are correctly implemented.


841-849: Good accessibility implementation on table rows.

Adding tabindex, role="button", aria-label, and keyboard event handling makes the interactive rows properly accessible.


1131-1139: Modal overlay close pattern works but is unconventional.

Using a <button> for the overlay backdrop works for accessibility and click handling. The tabindex="-1" correctly prevents focus, and Escape key handling is included.

frontend/src/routes/admin/AdminSagas.svelte (2)

1-30: Clean TypeScript migration with proper API types.

The imports and state declarations correctly use the generated API types (SagaStatusResponse, SagaState). The interval typing is correct.


662-877: Saga detail modal is well-structured.

The modal correctly displays saga information with good visual hierarchy, step visualization for execution sagas, and proper error/context data display.

docs/architecture/frontend-build.md (1)

1-376: Well-structured documentation for the frontend build system.

This comprehensive documentation covers the build pipeline, TypeScript configuration, API SDK generation, Tailwind CSS v4 integration, and development workflow. The mermaid diagrams and tables enhance readability.

One minor clarification could help in the troubleshooting section:

Suggested clarification
-Ensure the class exists in Tailwind's default utilities or is defined in `app.css`. Check for typos in semantic token names (e.g., `bg-default` vs `bg-bg-default`).
+Ensure the class exists in Tailwind's default utilities or is defined in `app.css`. Check for typos in semantic token names — the correct pattern is `bg-bg-default` (utility prefix + token name), not `bg-default`.
mkdocs.yml (1)

106-107: LGTM!

Navigation entries for the new architecture documentation are properly added and logically positioned within the Architecture section.

frontend/src/components/NotificationCenter.svelte (3)

10-16: Good use of Svelte 5 runes for component state.

The $state runes are correctly applied to showDropdown and loading which are UI-reactive. Keeping eventSource and reconnectTimeout as plain variables is appropriate since they're internal references that don't need to trigger template updates.


71-165: SSE reconnection logic is well-implemented.

The exponential backoff (5s, 10s, 20s) with max attempts, proper cleanup on auth changes, and reconnect guards are solid patterns for resilient SSE connections.


288-290: Good accessibility improvements.

The addition of tabindex="0", role="button", and aria-label attributes improves keyboard navigation and screen reader support for notification items.

frontend/src/components/ToastContainer.svelte (3)

60-64: LGTM — proper cleanup on destroy.

The onDestroy correctly unsubscribes from the store and clears all active timers to prevent memory leaks.


93-93: Correct Tailwind v4 syntax for outline removal.

Using focus:outline-hidden is the correct Tailwind v4 approach (replacing the v3 focus:outline-none which now only removes the style, not the outline entirely). Based on library documentation for Tailwind v4.


115-152: Toast rendering and interaction looks good.

The component properly handles mouse enter/leave for pause/resume functionality, uses appropriate ARIA attributes, and the transition effects are smooth.

frontend/package.json (1)

42-44: Svelte 5 is a major upgrade with breaking API changes.

The upgrade from Svelte 4 to Svelte 5 introduces significant breaking changes including the runes API ($state, $derived, $effect) replacing the reactive $: syntax, and mount() replacing component instantiation. The documentation in frontend-build.md and svelte5-migration.md should guide the transition.

The @mateothegreat/svelte5-router package is actively maintained with recent releases and appears suitable for your routing needs.

frontend/src/main.ts (1)

1-10: LGTM!

Clean Svelte 5 entry point setup. The import order correctly places the side-effect module (./lib/api/setup) first to ensure API configuration runs before the app mounts. The mount() API usage follows Svelte 5 patterns correctly.

frontend/rollup.config.js (4)

8-8: LGTM!

TypeScript plugin import added to support the TypeScript migration.


116-116: LGTM!

Entry point correctly updated to TypeScript.


151-163: LGTM!

Solid configuration for Svelte 5 with TypeScript:

  • runes: true correctly enables Svelte 5's runes mode for $state, $derived, etc.
  • TypeScript plugin configured with source maps and conditional inline sources for debugging.

185-185: Good improvement with drop_console.

Using drop_console: true is cleaner than the previous pure_funcs: ['console.log'] approach as it removes all console methods (log, warn, error, etc.) in production builds.

Verify this is the intended behavior—if you need console.error or console.warn to remain in production for debugging purposes, consider using a more selective approach.

frontend/src/routes/Register.svelte (2)

1-15: LGTM!

Clean migration to Svelte 5 with TypeScript:

  • Proper $state() rune usage for reactive state
  • New router imports (goto, route) correctly replace svelte-routing
  • Toast system integration via addToast

56-56: LGTM!

Proper migration from Link component to anchor with use:route directive for the new router.

frontend/src/routes/Home.svelte (3)

1-21: LGTM!

Clean TypeScript migration with proper Svelte 5 patterns:

  • $state() rune correctly used for the ready flag
  • Router integration with route action
  • Meta utilities import path updated to drop .js extension (aligns with TS module resolution)

30-44: LGTM!

Good animation setup using CSS custom properties (--fly-y, --fly-delay) for staggered animations. The CTA button correctly uses use:route for client-side navigation.


62-63: shadow-xs is only available in Tailwind CSS v4.

The v3 shadow-sm utility was renamed to shadow-xs in v4. If this project uses Tailwind v3, this utility will not be available and would require custom configuration to define.

frontend/src/routes/Notifications.svelte (4)

1-16: LGTM!

Well-structured TypeScript migration:

  • Proper type imports (NotificationResponse)
  • $state() with generic type annotation for complex state ($state<Record<string, boolean>>({}))
  • Clean imports from new router and toast system

50-75: LGTM!

Good function signatures with explicit return types (Promise<void>). The toast notifications provide clear user feedback for success/failure cases.


93-107: LGTM!

Correct use of getTime() for date arithmetic. The timestamp formatting logic handles various time ranges appropriately.


135-150: Good accessibility improvement.

Adding id attributes to inputs and proper for associations on labels improves screen reader support. The migration from on:click to onclick aligns with Svelte 5 patterns.

frontend/src/components/Header.svelte (4)

1-12: LGTM!

Clean TypeScript migration with proper typing:

  • resizeListener correctly typed as (() => void) | null
  • $state() runes properly initialized
  • Store imports updated to drop .js extensions

49-74: Well-structured lifecycle management.

Good practices here:

  • SSR guard (typeof window === 'undefined') prevents errors during server-side rendering
  • Consolidated event listener setup in onMount
  • Proper cleanup in onDestroy for both resize and click-outside listeners

94-100: LGTM!

Proper router integration on the logo link with use:route and onclick={closeMenu} to handle menu state on navigation.


228-244: Consider semantic consistency for mobile navigation.

The admin panel link (line 228) and logout button (line 235) use flex items-center but are styled differently—one is an anchor, the other a button. Both render inline SVG icons. This is fine functionally, but ensure the visual styling is intentional.

frontend/src/lib/auth-init.ts (1)

1-177: LGTM! Excellent type safety and encapsulation improvements.

This refactoring significantly improves the code quality through:

  • Type safety: The PersistedAuth interface provides clear typing for persisted authentication state
  • Encapsulation: Private methods (_performInitialization, _handlePersistedAuth, etc.) hide implementation details
  • Explicitness: All methods now have explicit return types (Promise<boolean>, void, etc.)
  • Maintainability: The clear structure with typed parameters and returns makes the code easier to understand and modify

The authentication initialization flow is well-structured with proper error handling, fallback logic for network errors, and appropriate logging throughout.

frontend/src/lib/settings-cache.ts (7)

8-11: LGTM!

The CacheData interface is well-structured and clearly defines the cache format with typed data and timestamp for TTL management.


13-13: LGTM!

The settingsCache store is properly typed as writable<UserSettings | null>, which correctly represents the cache state.


15-35: LGTM!

The function correctly implements cache retrieval with TTL validation, proper error handling, and type-safe JSON parsing using the CacheData interface.


37-50: LGTM!

The function properly persists settings to both localStorage and the Svelte store with appropriate error handling and type safety.


52-56: LGTM!

The cache clearing logic correctly removes the entry from localStorage and resets the store.


78-83: LGTM!

The initialization logic correctly hydrates the settings cache from localStorage when the module loads in a browser environment.


2-2: The import path './api' is correct and resolves properly. A barrel export already exists in frontend/src/lib/api/index.ts that re-exports UserSettings from types.gen.ts.

Likely an incorrect or invalid review comment.

frontend/src/routes/Editor.svelte (1)

101-123: LGTM: Well-implemented persistent store with proper error handling.

The generic createPersistentStore function correctly handles localStorage unavailability, JSON parsing errors, and maintains type safety throughout.

Comment thread frontend/package.json Outdated
Comment thread frontend/src/components/ToastContainer.svelte
Comment thread frontend/src/lib/settings-cache.ts
Comment thread frontend/src/routes/Editor.svelte Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
cert-generator/Dockerfile (1)

1-1: Consider pinning the full Alpine patch version for reproducibility.

Using alpine:3.23 will pull the latest patch release (currently 3.23.2), which could change over time. For fully reproducible builds, pin to alpine:3.23.2.

🔎 Proposed change
-FROM alpine:3.23
+FROM alpine:3.23.2
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 85b39fb and 6ec4103.

📒 Files selected for processing (1)
  • cert-generator/Dockerfile (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Backend Tests
🔇 Additional comments (1)
cert-generator/Dockerfile (1)

3-7: Version pins address previous feedback appropriately.

The kubectl version (v1.33.6) falls within the supported release window, and mkcert v1.4.4 is the latest stable release. The inline comments explaining the N-2 support policy are helpful for future maintenance.

Comment thread cert-generator/Dockerfile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (3)
frontend/src/app.css (3)

80-87: Inconsistent timing functions between theme variables and utility definitions.

The animation timing functions differ between the theme variables and the @utility definitions:

Animation Theme Variable (lines 66-67) Utility Definition
fadeIn ease-out ease-in-out (line 82)
flyIn var(--ease-out-expo) ease-out (line 86)

Consider aligning these for consistency:

🔎 Proposed fix to align timing functions
 @utility animate-fadeIn {
-  animation: fadeIn 0.3s ease-in-out;
+  animation: var(--animate-fadeIn);
 }

 @utility animate-flyIn {
-  animation: flyIn 0.3s ease-out;
+  animation: var(--animate-flyIn);
 }

274-391: Consider extracting shared form control styles to reduce repetition.

Multiple form control classes (form-input-standard, form-input-number, form-textarea, form-select-standard, form-dropdown-button, form-input-date) share nearly identical base styles:

@apply w-full px-3 py-1.5 text-sm border border-neutral-300 dark:border-dark-border-input
       bg-white dark:bg-dark-bg-alt text-fg-default dark:text-dark-fg-default
       rounded-md focus:outline-hidden focus:ring-2 focus:ring-primary focus:border-primary
       hover:bg-neutral-50 dark:hover:bg-neutral-700 transition-colors;

You could reduce duplication by creating a base class and extending it, or by using CSS custom properties for the shared properties. This is optional given the current scope works correctly.


502-507: Inconsistent color palette: gray-* vs neutral-*.

The .input-sm class uses gray-300, gray-600, and gray-700, while the rest of the file consistently uses neutral-* colors. This could cause visual inconsistencies if the gray and neutral palettes differ in your Tailwind configuration.

🔎 Proposed fix for consistency
   .input-sm {
-    @apply px-2 py-1 text-sm border border-gray-300 dark:border-gray-600
-           rounded bg-white dark:bg-gray-700 text-fg-default dark:text-dark-fg-default;
+    @apply px-2 py-1 text-sm border border-neutral-300 dark:border-neutral-600
+           rounded bg-white dark:bg-neutral-700 text-fg-default dark:text-dark-fg-default;
   }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ec4103 and ac12fd7.

📒 Files selected for processing (1)
  • frontend/src/app.css (4 hunks)
🧰 Additional context used
🪛 Biome (2.1.2)
frontend/src/app.css

[error] 13-13: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Backend Tests
🔇 Additional comments (4)
frontend/src/app.css (4)

4-9: LGTM! Import ordering issue resolved.

The @import statements are now correctly positioned after @import "tailwindcss" and before other directives (@plugin, @variant, @theme), which addresses the previous review concern about CSS specification compliance.


11-14: Static analysis false positive - Tailwind v4 plugin syntax is valid.

Biome flags strategy: class; as an unknown property, but this is valid Tailwind CSS v4 @plugin configuration syntax. The strategy: class option configures @tailwindcss/forms to use class-based form styling instead of global base styles, which is the intended behavior here.


19-68: Well-structured theme configuration with comprehensive design tokens.

The theme defines a complete token system with:

  • Primary/secondary color palettes with light/dark variants
  • Semantic colors for backgrounds, foregrounds, and borders in both modes
  • Typography, shadow, and animation tokens

This CSS-first approach aligns well with Tailwind v4's design philosophy.


89-170: LGTM! Comprehensive base layer with good accessibility patterns.

The base layer properly implements:

  • Smooth color transitions for theme switching
  • Consistent focus states with ring utilities for keyboard accessibility
  • CodeMirror integration that respects the design system tokens
  • Custom scrollbar styling for both light and dark modes

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
frontend/src/routes/Editor.svelte (1)

542-564: Duplicate condition checks create unreachable code.

Lines 555-564 contain condition checks that duplicate earlier checks (lines 542-554). When execution_failed, execution_timeout, or failed/error/timeout status is detected, the code at lines 542-554 already calls eventSource.close() and resolve(), making the subsequent checks at lines 555-564 unreachable within the same onmessage handler invocation.

🔎 Suggested fix: Remove duplicate dead code
                         } else if (data.event_type === 'execution_completed' || data.type === 'execution_completed' || data.status === 'completed') {
                             result = { ...(result || {}), status: 'completed' };
-                        } else if (data.event_type === 'execution_failed' || data.type === 'execution_failed' || data.status === 'failed' || data.status === 'error') {
-                            result = { ...(result || {}), status: 'failed' };
-                        } else if (data.event_type === 'execution_timeout' || data.type === 'execution_timeout' || data.status === 'timeout') {
-                            result = { ...(result || {}), status: 'timeout' };
                         } else if (data.status) {
                             // Update intermediate status
                             result = {...result, status: data.status};
                         }
♻️ Duplicate comments (2)
frontend/package.json (2)

34-34: dotenv v17.x runtime logging concern already noted.


41-41: sirv-cli v3.x Node 18+ requirement already noted.

🧹 Nitpick comments (1)
frontend/package.json (1)

44-44: Package is actively maintained, but monitor adoption levels.

The @mateothegreat/svelte5-router package is actively maintained, with version 2.16.19 published 3 months ago. It is built for Svelte 5. Community adoption is limited (2 known dependents), so monitor for alternative solutions if significant issues emerge.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ac12fd7 and c176398.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (19)
  • frontend/package.json (2 hunks)
  • frontend/src/lib/api/client.gen.ts (1 hunks)
  • frontend/src/lib/api/client/client.gen.ts (1 hunks)
  • frontend/src/lib/api/client/index.ts (1 hunks)
  • frontend/src/lib/api/client/types.gen.ts (1 hunks)
  • frontend/src/lib/api/client/utils.gen.ts (1 hunks)
  • frontend/src/lib/api/core/auth.gen.ts (1 hunks)
  • frontend/src/lib/api/core/bodySerializer.gen.ts (1 hunks)
  • frontend/src/lib/api/core/params.gen.ts (1 hunks)
  • frontend/src/lib/api/core/pathSerializer.gen.ts (1 hunks)
  • frontend/src/lib/api/core/queryKeySerializer.gen.ts (1 hunks)
  • frontend/src/lib/api/core/serverSentEvents.gen.ts (1 hunks)
  • frontend/src/lib/api/core/types.gen.ts (1 hunks)
  • frontend/src/lib/api/core/utils.gen.ts (1 hunks)
  • frontend/src/lib/api/index.ts (1 hunks)
  • frontend/src/lib/api/sdk.gen.ts (1 hunks)
  • frontend/src/main.ts (1 hunks)
  • frontend/src/routes/Editor.svelte (34 hunks)
  • frontend/src/stores/auth.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (8)
frontend/src/lib/api/core/types.gen.ts (2)
frontend/src/lib/api/core/auth.gen.ts (2)
  • Auth (5-20)
  • AuthToken (3-3)
frontend/src/lib/api/core/bodySerializer.gen.ts (3)
  • BodySerializer (11-11)
  • QuerySerializer (9-9)
  • QuerySerializerOptions (19-25)
frontend/src/lib/api/core/queryKeySerializer.gen.ts (1)
frontend/src/lib/api/client/index.ts (1)
  • serializeQueryKeyValue (11-11)
frontend/src/lib/api/core/serverSentEvents.gen.ts (1)
frontend/src/lib/api/core/types.gen.ts (1)
  • Config (41-104)
frontend/src/lib/api/client/types.gen.ts (7)
frontend/src/lib/api/core/types.gen.ts (2)
  • Config (41-104)
  • Client (21-39)
frontend/src/lib/api/types.gen.ts (1)
  • ClientOptions (3-5)
frontend/src/lib/api/core/serverSentEvents.gen.ts (2)
  • ServerSentEventsOptions (5-68)
  • ServerSentEventsResult (77-87)
frontend/src/lib/api/core/auth.gen.ts (1)
  • Auth (5-20)
frontend/src/lib/api/sdk.gen.ts (1)
  • Options (7-19)
frontend/src/lib/api/client/utils.gen.ts (1)
  • Middleware (291-295)
frontend/src/lib/api/client.gen.ts (1)
  • CreateClientConfig (14-14)
frontend/src/main.ts (2)
frontend/src/lib/api/client.gen.ts (1)
  • client (16-16)
backend/tests/conftest.py (1)
  • app (130-138)
frontend/src/lib/api/client/client.gen.ts (5)
frontend/src/lib/api/client/index.ts (7)
  • mergeHeaders (25-25)
  • createClient (12-12)
  • Config (16-16)
  • Client (14-14)
  • createConfig (25-25)
  • ResolvedRequestOptions (21-21)
  • RequestOptions (19-19)
frontend/src/lib/api/client/utils.gen.ts (5)
  • mergeHeaders (195-227)
  • mergeConfigs (178-185)
  • createConfig (324-332)
  • setAuthParams (128-164)
  • buildUrl (166-176)
frontend/src/lib/api/client/types.gen.ts (4)
  • Config (16-65)
  • Client (200-208)
  • ResolvedRequestOptions (99-105)
  • RequestOptions (67-97)
frontend/src/lib/api/core/types.gen.ts (3)
  • Config (41-104)
  • Client (21-39)
  • HttpMethod (10-19)
frontend/src/lib/api/core/utils.gen.ts (1)
  • getValidRequestBody (116-143)
frontend/src/lib/api/client.gen.ts (5)
frontend/src/lib/api/client/types.gen.ts (3)
  • CreateClientConfig (218-220)
  • ClientOptions (152-156)
  • Config (16-65)
frontend/src/lib/api/types.gen.ts (1)
  • ClientOptions (3-5)
frontend/src/lib/api/core/types.gen.ts (1)
  • Config (41-104)
frontend/src/lib/api/client/client.gen.ts (1)
  • createClient (27-301)
frontend/src/lib/api/client/utils.gen.ts (1)
  • createConfig (324-332)
frontend/src/lib/api/core/bodySerializer.gen.ts (1)
frontend/src/lib/api/client/index.ts (4)
  • QuerySerializerOptions (4-4)
  • formDataBodySerializer (6-6)
  • jsonBodySerializer (7-7)
  • urlSearchParamsBodySerializer (8-8)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Scan Frontend
  • GitHub Check: Backend Tests
🔇 Additional comments (43)
frontend/package.json (5)

9-10: LGTM!

The generate:api script cleanly integrates with the OpenAPI-driven API SDK workflow. It relies on the openapi-ts.config.ts configuration file mentioned in the PR context.


48-48: LGTM on TypeScript tooling additions.

The additions of @rollup/plugin-typescript, tslib, and typescript properly support the TypeScript integration mentioned in the PR summary.

Also applies to: 56-57


53-53: Good: @hey-api/openapi-ts correctly pinned.

The exact version pinning (0.89.1 without caret) is appropriate since this package does not follow semantic versioning, as noted in the previous review.


42-42: Svelte 5 migration is complete.

Verification confirms all components have been properly migrated to Svelte 5. No legacy Svelte 4 patterns (on: directives, $: reactive statements, or export let props) were found. Components are already using Svelte 5 runes ($state) and features (Snippet types).


51-51: Express 5.x introduces breaking changes that require code verification.

While Express 5 maintains the same basic API, it has breaking changes that may prevent Express 4 applications from working with Express 5. If your frontend uses Express for development server middleware or proxy configuration, verify that any code using Express APIs—particularly res.send(status) syntax, which now requires res.status(code).send()—has been updated for v5 compatibility. Check for any custom dev server setup, proxy middleware, or middleware configurations that directly use Express APIs.

frontend/src/stores/auth.ts (7)

1-17: LGTM! Clean interface and imports.

The AuthState interface appropriately models the nullable states during authentication lifecycle, and the imports are well-organized.


19-40: Solid persistence layer with appropriate SSR guards.

The 24-hour localStorage TTL is a reasonable default that balances UX with security for most web applications.


42-62: Well-structured store initialization and state management.

The cache setup and clearAuth helper follow Svelte best practices.


64-93: Login flow is robust and user-friendly.

The pattern of logging in first and then asynchronously fetching the profile (lines 87-91) provides good UX—users see immediate feedback even if profile details load slightly delayed. The warning log aids debugging without blocking authentication.


95-103: Profile fetching logic is straightforward and correct.

The function appropriately updates both the reactive stores and persisted state.


105-114: Excellent fix from previous review!

The try/catch/finally pattern ensures local state is always cleared even if the logout API call fails, eliminating the inconsistent state issue that was previously flagged.


116-174: Outstanding implementation with clear security trade-off documentation.

The comprehensive JSDoc (lines 116-128) transparently communicates the offline-first behavior and its implications. The catch block (lines 162-168) now includes proper logging and explicitly documents why stale cache is tolerated. The in-flight request deduplication (line 133) prevents race conditions. Previous review concerns have been thoroughly addressed.

frontend/src/lib/api/core/types.gen.ts (1)

1-118: LGTM - Well-structured auto-generated type definitions.

The type definitions are correctly structured:

  • HttpMethod covers all standard HTTP methods
  • Client type uses proper conditional typing for optional SSE support
  • Config interface is comprehensive with proper documentation
  • OmitNever utility type correctly filters out never types from records
frontend/src/lib/api/core/params.gen.ts (2)

1-176: Auto-generated parameter builder looks correct.

The implementation correctly:

  • Builds a key map for efficient lookups
  • Handles body, headers, path, and query slots
  • Supports field mapping/aliasing via map property
  • Routes prefixed fields ($body_, $headers_, etc.) to appropriate slots
  • Strips empty slots before returning

160-166: Consider: Verify allowExtra behavior with multiple allowed slots.

The break statement causes extra fields to be assigned to only the first slot with allowed: true, even if multiple slots have allowExtra enabled. If this behavior is unintended, extra parameters may silently go to the wrong slot. Confirm whether this single-assignment-per-field design is intentional or if it should allow distribution across all enabled slots.

frontend/src/lib/api/core/serverSentEvents.gen.ts (2)

111-114: Orphaned AbortController when no signal is provided.

When options.signal is undefined, a new AbortController().signal is created but the controller itself is not retained. This means:

  1. The SSE stream cannot be aborted by the caller if they didn't provide a signal
  2. The stream will run until completion or error (no external cancellation possible)

This is likely intentional for the auto-generated client (callers should provide their own signal for cancellation), but worth noting that streams started without a signal can only terminate naturally or via error.


89-265: SSE client implementation is well-structured.

The implementation correctly handles:

  • Configurable fetch and request interception
  • SSE protocol parsing (data, event, id, retry fields)
  • Line ending normalization (CRLF → LF → CR)
  • Last-Event-ID propagation for reconnection
  • Exponential backoff with configurable max delay and attempts
  • Proper reader cleanup in finally block
  • Abort signal handling with event listener cleanup
frontend/src/lib/api/core/pathSerializer.gen.ts (1)

1-181: LGTM - Path/query serialization utilities are correctly implemented.

The serialization functions properly handle:

  • Multiple OpenAPI parameter styles (form, spaceDelimited, pipeDelimited, label, matrix, simple, deepObject)
  • Exploded and non-exploded parameter formats
  • Reserved character encoding via allowReserved option
  • Date serialization to ISO strings
  • Clear error messaging for unsupported deeply-nested structures (line 123-125)

The type assertions to string are acceptable given the documented limitation that deeply-nested structures require custom serializers.

frontend/src/lib/api/client/utils.gen.ts (2)

266-271: Minor: getInterceptorIndex returns -1 for out-of-bounds numeric id.

When id is a number and this.fns[id] is falsy (including when id >= this.fns.length), the function returns -1. However, accessing this.fns[id] where id is out of bounds returns undefined (falsy), so this correctly returns -1 for invalid indices. The logic is sound.


1-332: LGTM - Comprehensive client utilities.

The utilities are well-implemented:

  • createQuerySerializer handles arrays, objects, and primitives with configurable options
  • setAuthParams correctly handles header, query, and cookie auth placement
  • mergeHeaders properly handles null (delete), arrays (append), and objects (JSON stringify)
  • Interceptor infrastructure follows standard patterns (similar to axios)
  • createConfig provides sensible defaults with JSON body serializer
frontend/src/main.ts (1)

1-16: LGTM!

The Svelte 5 application bootstrap is correctly implemented:

  • Uses the new mount API (Svelte 5 pattern)
  • Configures the API client with appropriate credentials for cookie-based auth
  • Clean separation of concerns with client configuration before mounting
frontend/src/lib/api/client.gen.ts (1)

1-16: LGTM!

Auto-generated API client factory that correctly:

  • Exports a pre-configured client instance
  • Provides the CreateClientConfig type for initialization patterns
  • Works in concert with the runtime setConfig() call in main.ts
frontend/src/lib/api/index.ts (1)

1-4: LGTM!

Auto-generated barrel module that correctly re-exports:

  • Runtime API operation functions from sdk.gen
  • Type-only exports from types.gen using proper export type syntax
frontend/src/lib/api/core/queryKeySerializer.gen.ts (1)

1-136: LGTM!

Auto-generated query key serialization utilities with correct implementation:

  • queryKeyJsonReplacer properly handles non-JSON types (bigint→string, Date→ISO string)
  • serializeSearchParams provides deterministic serialization by sorting keys
  • serializeQueryKeyValue comprehensively normalizes all input types to JSON-friendly shapes
  • The isPlainObject helper correctly handles both standard objects and those with null prototype
frontend/src/lib/api/core/auth.gen.ts (1)

1-42: LGTM!

Auto-generated auth token handling with correct implementation:

  • Properly handles both sync and async token callbacks
  • Correctly formats Bearer and Basic auth schemes
  • btoa usage is appropriate for this browser-targeted code
  • Clean fallback to raw token for custom auth types
frontend/src/lib/api/core/utils.gen.ts (1)

1-143: Auto-generated utility module looks correct.

This is a well-structured auto-generated module from @hey-api/openapi-ts. The path serialization logic correctly handles OpenAPI 3.x path parameter styles (simple, label, matrix) with proper URL encoding. The getValidRequestBody function appropriately distinguishes between undefined (no body), null (empty body to send), and serialized body content.

frontend/src/lib/api/client/index.ts (1)

1-25: Clean barrel file for API client exports.

This auto-generated index correctly consolidates the public API surface. Type exports use export type appropriately, and runtime exports are separated. This provides a stable import path for consumers.

frontend/src/lib/api/client/client.gen.ts (3)

78-131: Request error handling is sound but uses type assertions.

The error handling flow correctly:

  1. Catches fetch exceptions (network errors, AbortError)
  2. Runs error interceptors
  3. Either throws or returns error based on throwOnError config

The undefined as any type assertions (lines 110, 129) are acceptable in auto-generated code to handle the discriminated union return types.


144-214: Response parsing logic handles edge cases well.

The parsing correctly:

  • Detects empty responses via status 204 or Content-Length: 0
  • Returns appropriate empty values per parseAs type (empty object for JSON, empty FormData, etc.)
  • Applies responseValidator and responseTransformer only for JSON responses
  • Returns raw stream for parseAs: 'stream'

253-272: SSE method factory applies interceptors correctly.

The SSE factory properly wires the onRequest callback to apply request interceptors before establishing the SSE connection. The type casts on lines 258-259 are necessary to bridge the generated types with the SSE client interface.

frontend/src/routes/Editor.svelte (7)

28-43: Error handling helper properly handles FastAPI error shapes.

The getErrorMessage function correctly handles:

  • String detail messages
  • Validation error arrays (FastAPI's {detail: [{loc, msg, type}]} format)
  • Generic Error instances
  • Fallback for unknown error shapes

This addresses the past review comment about error property access.


118-140: Persistent store implementation is sound.

The createPersistentStore<T> correctly:

  • Handles SSR by checking for localStorage availability
  • Catches and recovers from corrupted stored values
  • Synchronizes store changes to localStorage

Note: The internal subscription (line 136-138) persists for the lifetime of the store, which is expected for a persistent store pattern.


352-362: Proper cleanup of all subscriptions and editor instance.

The onDestroy handler correctly cleans up:

  • EditorView instance
  • All store subscriptions including the newly added unsubscribeScriptId and unsubscribeScriptName

This prevents memory leaks when the component is destroyed.


601-616: API error handling follows consistent patterns.

The loadSavedScripts function correctly:

  • Destructures {data, error, response} from the generated API call
  • Handles errors with appropriate toast messages
  • Triggers logout on 401 responses
  • Safely maps script data with fallback IDs

This pattern is consistently applied across other API functions.


670-712: Save operation correctly handles update-to-create fallback.

The update flow properly handles the edge case where a script no longer exists (404):

  1. Clears currentScriptId
  2. Falls back to create operation
  3. Sets the new ID on success

This prevents data loss when attempting to update a deleted script.


884-884: Event handlers correctly use Svelte 5 syntax.

The migration to Svelte 5's onclick attribute syntax (instead of on:click) is consistently applied throughout the component.


196-215: Svelte 5 reactivity pattern is correctly implemented.

The $effect block properly:

  • Accesses reactive state variables (currentScriptIdValue, scriptNameValue) to establish dependencies
  • Syncs with store values via subscriptions set up in onMount
  • Handles the script rename detection logic

This is the correct pattern for integrating writable stores with Svelte 5's runes.

frontend/src/lib/api/client/types.gen.ts (3)

107-150: RequestResult type correctly models all response scenarios.

The conditional type properly handles the matrix of:

  • ThrowOnError: true → Promise resolves to data (no error branch)
  • ThrowOnError: false → Promise resolves to discriminated union with data XOR error
  • ResponseStyle: 'data' → Returns just the data
  • ResponseStyle: 'fields' → Returns {data, request, response}

This provides strong type inference for API consumers.


200-208: Client type correctly composes the API surface.

The Client type:

  • Extends CoreClient with properly typed function generics (RequestFn, Config, MethodFn, BuildUrlFn, SseFn)
  • Adds typed interceptors property using the Middleware interface from utils.gen

This provides a complete, strongly-typed client interface.


230-241: Options type provides clean SDK function signatures.

The Options type elegantly:

  • Removes redundant fields that are defined by the SDK function itself (body, path, query, url)
  • Conditionally merges typed request data from TData
  • Enables SDK functions to have precise parameter types based on their OpenAPI specification
frontend/src/lib/api/core/bodySerializer.gen.ts (2)

1-100: Auto-generated serializers look well-structured.

The body serialization logic is clean and handles the common content types correctly:

  • FormData serializer properly handles Blobs, Dates (via ISO string), and falls back to JSON for complex objects
  • JSON serializer includes bigint handling
  • URLSearchParams serializer follows a similar pattern to FormData
  • All serializers appropriately skip null and undefined values

Since this is auto-generated code from @hey-api/openapi-ts, the implementation should be stable and well-tested by the library maintainers.

</invoke_comment_end -->


53-72: Verify that Object.entries() on array bodies aligns with your API's multipart/form-data serialization expectations.

When the body is an array, Object.entries() produces numeric string keys ('0', '1', etc.), but OpenAPI 3.0 multipart/form-data defaults to style: form, explode: true which uses a repeated-key pattern instead. For example, an array [{name: "a"}, {name: "b"}] via Object.entries() produces keys '0' and '1', not repeated field names.

Confirm your backend expects numeric indices for array request bodies rather than repeated keys or a different serialization format.

frontend/src/lib/api/sdk.gen.ts (1)

1-763: SDK provides comprehensive, type-safe API coverage with proper runtime parameter handling.

The generated file offers ~90 endpoint wrappers across auth, execution, events, admin, notifications, sagas, etc., with:

  • Proper typing via generated types from types.gen.ts
  • Consistent client fallback pattern (options?.client ?? client)
  • Correct Content-Type headers for different body formats
  • Appropriate use of body serializers (e.g., urlSearchParamsBodySerializer for form-urlencoded login)
  • Path parameter templates (e.g., {execution_id}, {user_id}) that the underlying client resolves at runtime

Generated by @hey-api/openapi-ts, the code stays in sync with your OpenAPI specification through regeneration. The client implementation handles path parameter substitution, ensuring type safety and correctness throughout the request flow.

Comment thread frontend/package.json
Comment thread frontend/src/lib/api/client/utils.gen.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c176398 and 92446ba.

📒 Files selected for processing (2)
  • frontend/src/app.css (6 hunks)
  • frontend/src/routes/Home.svelte (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • frontend/src/routes/Home.svelte
🧰 Additional context used
🪛 Biome (2.1.2)
frontend/src/app.css

[error] 13-13: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Backend Tests
🔇 Additional comments (7)
frontend/src/app.css (7)

4-9: Import order correctly resolved.

The import statements are now properly positioned after the Tailwind v4 migration, with component and page imports following @import "tailwindcss" and preceding other directives. This addresses the previously flagged CSS specification violation.


16-17: LGTM: Dark mode variant.

The class-based dark mode variant is properly configured using :where() for specificity control.


19-68: LGTM: Comprehensive theme configuration.

The design token system is well-organized with clear separation of light/dark semantic colors, typography, and custom properties. The CSS variable approach provides good maintainability.


172-249: LGTM: Button and form control styles.

The button variants and form control styles follow consistent patterns with proper theming integration. The use of the important flag on line 184 for .btn-icon padding is intentional to ensure icon-only buttons maintain specific dimensions.


412-507: LGTM: Editor, prose, and admin component styles.

The new editor component styles (form-input-bare, output-container, custom scrollbars), prose typography adjustments, and admin utilities are well-structured and follow the established design token system. Clear section comments improve maintainability.


11-14: Fix unquoted strategy value in @plugin directive.

The strategy: class; property is missing quotes. Correct syntax: strategy: "class";

Likely an incorrect or invalid review comment.


103-103: No issues found. The focus:ring-3 utility is standard Tailwind CSS v4 syntax designed to preserve the previous 3px ring width from v3.

Likely an incorrect or invalid review comment.

Comment thread frontend/src/app.css
@sonarqubecloud

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
frontend/src/app.css (1)

80-87: Animation utilities now correctly use theme variables.

The utilities now delegate to var(--animate-fadeIn) and var(--animate-flyIn), which reference the theme-defined animations with correct easing values (ease-out and var(--ease-out-expo) respectively). This resolves the easing inconsistency noted in a prior review.

🧹 Nitpick comments (2)
frontend/src/app.css (2)

438-444: Consider using CSS variables for scrollbar-color where supported.

Line 443 uses hardcoded hex values (#9ca3af #e5e7eb) while the webkit scrollbar styling uses theme tokens. For consistency, you could use CSS variables here, though note that scrollbar-color has broader browser support for variables now.

   .output-content,
   .output-pre,
   .custom-scrollbar {
     scrollbar-width: thin;
-    scrollbar-color: #9ca3af #e5e7eb; /* neutral-400 neutral-200 */
+    scrollbar-color: var(--color-fg-subtle) var(--color-bg-default);
   }

502-506: Inconsistent color class naming: gray-* vs neutral-*.

This section uses gray-300, gray-600, and gray-700 while the rest of the file consistently uses neutral-* variants. Consider aligning with the established pattern for maintainability.

   .input-sm {
-    @apply px-2 py-1 text-sm border border-gray-300 dark:border-gray-600
-           rounded bg-white dark:bg-gray-700 text-fg-default dark:text-dark-fg-default;
+    @apply px-2 py-1 text-sm border border-neutral-300 dark:border-neutral-600
+           rounded bg-white dark:bg-neutral-700 text-fg-default dark:text-dark-fg-default;
   }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 92446ba and 82dddce.

📒 Files selected for processing (1)
  • frontend/src/app.css (6 hunks)
🧰 Additional context used
🪛 Biome (2.1.2)
frontend/src/app.css

[error] 13-13: Unknown property is not allowed.

See CSS Specifications and browser specific properties for more details.
To resolve this issue, replace the unknown property with a valid CSS property.

(lint/correctness/noUnknownProperty)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Backend Tests
🔇 Additional comments (4)
frontend/src/app.css (4)

11-14: Static analysis warning is a false positive.

The strategy: class inside @plugin "@tailwindcss/forms" is valid Tailwind CSS v4 plugin configuration syntax, not a standard CSS property. This configures the forms plugin to use class-based styling (e.g., .form-input) rather than global element styles. The static analysis tool doesn't recognize Tailwind v4's @plugin directive syntax.


19-68: Well-structured theme configuration.

The semantic color token system with separate light (--color-*) and dark (--color-dark-*) variants provides a clean foundation for the design system. Animation variables encapsulate timing and easing in a single token.


89-170: LGTM!

Base layer correctly applies theme tokens for form inputs, scrollbars, and CodeMirror editor integration. The use of Tailwind v4 syntax (focus:ring-3, font-mono!) is appropriate.


172-411: Component layer is well-structured.

The button variants, form controls, and utility components consistently apply theme tokens and include proper focus states, dark mode support, and disabled states. The organization with section headers improves maintainability.

@HardMax71
HardMax71 merged commit 01330a8 into main Dec 21, 2025
15 of 16 checks passed
@HardMax71
HardMax71 deleted the bump_dependencies branch December 21, 2025 19:03
@coderabbitai coderabbitai Bot mentioned this pull request Dec 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants