fixed css

This commit is contained in:
2025-12-20 23:33:47 +03:00
parent 9b7b743319
commit d05344e604
60 changed files with 939 additions and 227 deletions

View File

@@ -0,0 +1,34 @@
# Specification Quality Checklist: Fix UI Styling, WebSocket Port Mismatch, and URL Validation
**Purpose**: Validate specification completeness and quality before proceeding to planning
**Created**: 2025-12-20
**Feature**: [specs/001-fix-ui-ws-validation/spec.md](../spec.md)
## Content Quality
- [x] No implementation details (languages, frameworks, APIs)
- [x] Focused on user value and business needs
- [x] Written for non-technical stakeholders
- [x] All mandatory sections completed
## Requirement Completeness
- [x] No [NEEDS CLARIFICATION] markers remain
- [x] Requirements are testable and unambiguous
- [x] Success criteria are measurable
- [x] Success criteria are technology-agnostic (no implementation details)
- [x] All acceptance scenarios are defined
- [x] Edge cases are identified
- [x] Scope is clearly bounded
- [x] Dependencies and assumptions identified
## Feature Readiness
- [x] All functional requirements have clear acceptance criteria
- [x] User scenarios cover primary flows
- [x] Feature meets measurable outcomes defined in Success Criteria
- [x] No implementation details leak into specification
## Notes
- Initial validation passed. The specification has been refined to be technology-agnostic while addressing the specific issues reported (styling, real-time communication, and URL validation).

View File

@@ -0,0 +1,31 @@
# Data Model: Fix UI Styling, WebSocket Port Mismatch, and URL Validation
## Entities
### ServiceConnection
Represents the configuration for an external service.
| Field | Type | Description | Validation |
|-------|------|-------------|------------|
| `base_url` | `AnyHttpUrl` | The base URL of the service. | Normalized to include `/api/v1` if missing. |
| `name` | `string` | Friendly name for the connection. | Required. |
| `status` | `string` | Connection status (connected, failed, etc.). | Read-only. |
### TaskLogMessage
The structure of messages sent over the WebSocket for real-time logs.
| Field | Type | Description |
|-------|------|-------------|
| `task_id` | `string` | Unique identifier for the task. |
| `message` | `string` | The log message text. |
| `timestamp` | `datetime` | When the log was generated. |
| `level` | `string` | Log level (INFO, ERROR, etc.). |
## State Transitions
### Connection Validation
1. User inputs `base_url`.
2. System validates URL format.
3. System checks for `/api/v1` suffix.
4. If missing, system appends `/api/v1`.
5. System attempts connection and updates `status`.

View File

@@ -0,0 +1,74 @@
# Implementation Plan: Fix UI Styling, WebSocket Port Mismatch, and URL Validation
**Branch**: `001-fix-ui-ws-validation` | **Date**: 2025-12-20 | **Spec**: [specs/001-fix-ui-ws-validation/spec.md](specs/001-fix-ui-ws-validation/spec.md)
**Input**: Feature specification from `/specs/001-fix-ui-ws-validation/spec.md`
## Summary
This feature addresses three critical issues: unstyled UI due to missing Tailwind CSS imports, broken real-time logs caused by WebSocket port mismatches in development, and strict URL validation that prevents successful connections to external services. The technical approach involves importing Tailwind in the root layout, using environment variables for WebSocket URLs with a fallback, and relaxing URL validation to automatically append version suffixes.
## Technical Context
**Language/Version**: Python 3.9+, Node.js 18+
**Primary Dependencies**: FastAPI, SvelteKit, Tailwind CSS, Pydantic
**Storage**: N/A (Configuration based)
**Testing**: pytest
**Target Platform**: Linux server
**Project Type**: Web application (frontend + backend)
**Performance Goals**: Real-time updates within 500ms
**Constraints**: SPA-First Architecture (No Node.js in production)
**Scale/Scope**: Targeted fixes for UI, real-time communication, and validation logic.
## Constitution Check
*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
| Principle | Status | Notes |
|-----------|--------|-------|
| I. SPA-First Architecture | PASS | SvelteKit SPA will be built and served by FastAPI. Post-design: Confirmed. |
| II. API-Driven Communication | PASS | Real-time logs via WebSockets; configuration via REST. Post-design: Confirmed. |
| III. Modern Stack Consistency | PASS | Uses SvelteKit, FastAPI, and Tailwind CSS. Post-design: Confirmed. |
| IV. Semantic Protocol Adherence | PASS | Implementation will use anchors and contracts as per `semantic_protocol.md`. Post-design: Confirmed. |
## Project Structure
### Documentation (this feature)
```text
specs/001-fix-ui-ws-validation/
├── plan.md # This file
├── research.md # Phase 0 output
├── data-model.md # Phase 1 output
├── quickstart.md # Phase 1 output
├── contracts/ # Phase 1 output
└── tasks.md # Phase 2 output
```
### Source Code (repository root)
```text
backend/
├── src/
│ ├── models/ # URL validation logic in superset_tool/models.py (or equivalent)
│ ├── services/
│ └── api/ # WebSocket and REST endpoints
└── tests/
frontend/
├── src/
│ ├── components/
│ ├── pages/
│ └── routes/ # +layout.svelte for global styling
└── tests/
```
**Structure Decision**: Web application structure (Option 2) is used as both frontend and backend components are modified.
## Complexity Tracking
> **Fill ONLY if Constitution Check has violations that must be justified**
| Violation | Why Needed | Simpler Alternative Rejected Because |
|-----------|------------|-------------------------------------|
| None | N/A | N/A |

View File

@@ -0,0 +1,53 @@
# Quickstart: Fix UI Styling, WebSocket Port Mismatch, and URL Validation
## Development Setup
1. **Frontend Styling**:
- Ensure Tailwind CSS is initialized: `cd frontend && npm install`
- Verify `frontend/src/app.css` contains:
```css
@tailwind base;
@tailwind components;
@tailwind utilities;
```
- Import in `frontend/src/routes/+layout.svelte`:
```svelte
<script>
import '../app.css';
</script>
```
2. **WebSocket Configuration**:
- Create/Update `.env` in `frontend/`:
```env
PUBLIC_WS_URL=ws://localhost:8000
```
- Use in Svelte components:
```javascript
import { PUBLIC_WS_URL } from '$env/static/public';
const wsUrl = PUBLIC_WS_URL || `ws://${window.location.hostname}:8000`;
```
3. **Backend URL Validation**:
- Update `superset_tool/models.py` (or relevant model file):
```python
from pydantic import validator
class ServiceConnection(BaseModel):
base_url: str
@validator('base_url')
def normalize_url(cls, v):
if not v.endswith('/api/v1'):
return f"{v.rstrip('/')}/api/v1"
return v
```
## Verification Steps
1. Run backend: `cd backend && uvicorn src.app:app --reload`
2. Run frontend: `cd frontend && npm run dev`
3. Open browser and verify:
- UI is styled (Tailwind classes working).
- Logs appear in real-time (WebSocket connected).
- External service connection accepts base URLs.

View File

@@ -0,0 +1,41 @@
# Research: Fix UI Styling, WebSocket Port Mismatch, and URL Validation
## WebSocket Port Mismatch Resolution
### Decision
Use SvelteKit's `$env/static/public` for `PUBLIC_WS_URL` with a client-side fallback logic.
### Rationale
SvelteKit allows exposing environment variables to the frontend. By using a public environment variable, we can explicitly set the WebSocket URL in different environments (dev vs. prod).
### Alternatives Considered
- **Hardcoding**: Rejected as it breaks across different environments.
- **Relative URLs**: WebSockets (`ws://` or `wss://`) cannot be purely relative in all browser contexts without logic to determine the host and port.
---
## URL Validation Relaxation
### Decision
Modify the Pydantic model to use a `validator` (or `field_validator` in Pydantic v2) that checks for the `/api/v1` suffix and appends it if missing, while still ensuring the base URL is valid.
### Rationale
This provides a seamless user experience where they can provide just the base URL, and the system handles the API versioning internally.
### Alternatives Considered
- **Strict Validation with Error Message**: Rejected as it causes user frustration (as noted in the spec).
- **Manual Suffixing in Service Clients**: Rejected as it's better to have a normalized URL in the data model.
---
## Global Styling (Tailwind CSS)
### Decision
Import the global CSS file (which includes `@tailwind` directives) in `src/routes/+layout.svelte`.
### Rationale
This is the standard SvelteKit pattern for ensuring styles are applied globally across all routes.
### Alternatives Considered
- **Importing in each page**: Rejected as it's redundant and hard to maintain.
- **Importing in `app.html`**: Possible, but importing in `+layout.svelte` allows for better integration with Svelte's build pipeline.

View File

@@ -0,0 +1,94 @@
# Feature Specification: Fix UI Styling, WebSocket Port Mismatch, and URL Validation
**Feature Branch**: `001-fix-ui-ws-validation`
**Created**: 2025-12-20
**Status**: Draft
**Input**: User description: "UI Styling: Tailwind CSS is not imported in the root layout, causing the unstyled appearance. WebSocket Mismatch: Port mismatch in dev mode is breaking real-time logs. Validation Error: Strict URL validation in superset_tool/models.py requires /api/v1, which caused the connection failure reported in your feedback."
## User Scenarios & Testing *(mandatory)*
### User Story 1 - Consistent UI Styling (Priority: P1)
As a user, I want the application to have a professional and styled appearance so that I can easily navigate and use the interface.
**Why this priority**: Unstyled UI makes the application look broken and difficult to use, impacting user trust and usability.
**Independent Test**: Can be fully tested by opening the application in a browser and verifying that consistent styling is applied globally across all routes.
**Acceptance Scenarios**:
1. **Given** the application is running, **When** I navigate to the home page or settings page, **Then** I should see professional styling applied (e.g., correct fonts, colors, and layout).
2. **Given** a new component is added, **When** it uses standard styling classes, **Then** those classes should be rendered correctly without additional imports.
---
### User Story 2 - Real-time Log Monitoring (Priority: P1)
As a developer or operator, I want to see real-time logs for running tasks so that I can monitor progress and debug issues effectively.
**Why this priority**: Real-time feedback is essential for long-running tasks like migrations or backups; without it, users are left wondering if the process is stuck.
**Independent Test**: Can be tested by starting a task and verifying that logs appear in the UI in real-time without requiring a page refresh.
**Acceptance Scenarios**:
1. **Given** a task is running, **When** I view the task details page, **Then** I should see live log updates streamed via real-time communication.
2. **Given** the application is running in development mode, **When** a real-time connection is initiated, **Then** it should correctly target the backend service port.
---
### User Story 3 - Flexible External Service Connection (Priority: P2)
As an administrator, I want to connect to external services using their base URL so that I don't have to worry about specific API version paths during configuration.
**Why this priority**: Strict validation currently prevents successful connection to valid service instances if the user doesn't provide a very specific suffix, leading to configuration frustration.
**Independent Test**: Can be tested by configuring a service connection with a standard base URL and verifying it connects successfully.
**Acceptance Scenarios**:
1. **Given** a valid service base URL, **When** I save the connection settings, **Then** the system should validate and accept the URL even if it doesn't explicitly end in a specific API version suffix.
2. **Given** a service URL that already includes an API version suffix, **When** I save the settings, **Then** the system should not duplicate the suffix or fail validation.
---
### Edge Cases
- **Connection Disconnection**: How does the system handle a real-time connection drop during a long-running task? (Assumption: It should attempt to reconnect or show a "Connection Lost" message).
- **Invalid URL Formats**: How does the system handle URLs that are completely malformed? (Assumption: Standard URL validation should still apply).
- **Styling Build Failures**: What happens if the styling assets fail to generate? (Assumption: The app should still be functional but may look unstyled; build logs should indicate the failure).
## Requirements *(mandatory)*
### Functional Requirements
- **FR-001**: System MUST ensure global styling (Tailwind CSS) is imported in `src/routes/+layout.svelte` to ensure consistent appearance.
- **FR-002**: System MUST use an environment variable (e.g., `PUBLIC_WS_URL`) with a fallback to the backend port (8000) to determine the WebSocket connection URL.
- **FR-003**: System MUST relax URL validation for external services to allow base URLs and automatically append `/api/v1` if the version suffix is missing.
- **FR-004**: System MUST provide visual feedback (toast notification and status indicator in log view) when a real-time connection fails to establish.
- **FR-005**: System MUST ensure that service clients correctly handle API versioning internally by using the normalized URL.
### Key Entities *(include if feature involves data)*
- **Service Connection**: Represents the configuration for connecting to an external service.
- Attributes: Base URL, Credentials (if applicable), Connection Status.
- **Task Log Stream**: Represents the real-time data flow of logs from the backend to the frontend.
- Attributes: Task ID, Log Message, Timestamp.
## Success Criteria *(mandatory)*
### Measurable Outcomes
- **SC-001**: 100% of pages render with consistent, professional styling as verified by visual inspection.
- **SC-002**: Real-time communication success rate is 100% in the development environment when both frontend and backend are running.
- **SC-003**: Users can successfully configure and save external service connections using only the base domain/IP in 100% of valid cases.
- **SC-004**: Real-time updates appear in the UI within 500ms of being generated on the backend.
## Clarifications
### Session 2025-12-20
- Q: WebSocket Reconnection Strategy → A: Automatic reconnection with exponential backoff (Option A).
- Q: URL Validation Strictness → A: Automatically append `/api/v1` if missing (Option A).
- Q: Global Styling Implementation → A: Import in `src/routes/+layout.svelte` (Option A).
- Q: WebSocket Port Configuration → A: Use environment variable with fallback (Option A).
- Q: Visual Feedback for Connection Failure → A: Toast notification + Status indicator (Option A).

View File

@@ -0,0 +1,139 @@
# Tasks: Fix UI Styling, WebSocket Port Mismatch, and URL Validation
**Input**: Design documents from `/specs/001-fix-ui-ws-validation/`
**Prerequisites**: plan.md (required), spec.md (required for user stories), research.md, data-model.md, contracts/
**Organization**: Tasks are grouped by user story to enable independent implementation and testing of each story.
## Format: `[ID] [P?] [Story] Description`
- **[P]**: Can run in parallel (different files, no dependencies)
- **[Story]**: Which user story this task belongs to (e.g., US1, US2, US3)
- Include exact file paths in descriptions
## Phase 1: Setup (Shared Infrastructure)
**Purpose**: Project initialization and basic structure
- [x] T001 Verify project structure and install dependencies in `backend/` and `frontend/`
---
## Phase 2: Foundational (Blocking Prerequisites)
**Purpose**: Core infrastructure that MUST be complete before ANY user story can be implemented
**⚠️ CRITICAL**: No user story work can begin until this phase is complete
- [x] T002 [P] Configure `PUBLIC_WS_URL` in `frontend/.env`
**Checkpoint**: Foundation ready - user story implementation can now begin in parallel
---
## Phase 3: User Story 1 - Consistent UI Styling (Priority: P1) 🎯 MVP
**Goal**: Apply Tailwind CSS globally via the root layout to ensure consistent appearance.
**Independent Test**: Open the application in a browser and verify that Tailwind styling is applied to all elements (e.g., Navbar, Footer, Buttons).
### Implementation for User Story 1
- [x] T003 [P] [US1] Verify Tailwind directives in `frontend/src/app.css`
- [x] T004 [US1] Import `../app.css` in `frontend/src/routes/+layout.svelte`
**Checkpoint**: At this point, User Story 1 should be fully functional and testable independently
---
## Phase 4: User Story 2 - Real-time Log Monitoring (Priority: P1)
**Goal**: Resolve WebSocket port mismatch using environment variables and fallback logic for real-time logs.
**Independent Test**: Start a task (e.g., a mock migration) and verify that logs appear in the `TaskRunner` component in real-time.
### Implementation for User Story 2
- [x] T005 [P] [US2] Implement WebSocket URL fallback logic in `frontend/src/lib/api.js`
- [x] T006 [US2] Update `frontend/src/components/TaskRunner.svelte` to use the dynamic WebSocket URL
**Checkpoint**: At this point, User Stories 1 AND 2 should both work independently
---
## Phase 5: User Story 3 - Flexible External Service Connection (Priority: P2)
**Goal**: Automatically append `/api/v1` to service base URLs if missing to simplify configuration.
**Independent Test**: Create a new service connection with `http://localhost:8080` and verify it is saved as `http://localhost:8080/api/v1`.
### Implementation for User Story 3
- [x] T007 [P] [US3] Relax `base_url` validation and add normalization in `superset_tool/models.py`
- [x] T008 [US3] Add unit tests for `SupersetConfig` URL normalization in `backend/tests/test_models.py`
**Checkpoint**: All user stories should now be independently functional
---
## Phase 6: Polish & Cross-Cutting Concerns
**Purpose**: Improvements that affect multiple user stories
- [x] T009 [P] Update `docs/settings.md` with new URL validation behavior
- [ ] T010 Run full verification suite per `quickstart.md`
---
## Dependencies & Execution Order
### Phase Dependencies
- **Setup (Phase 1)**: No dependencies - can start immediately
- **Foundational (Phase 2)**: Depends on Setup completion - BLOCKS all user stories
- **User Stories (Phase 3+)**: All depend on Foundational phase completion
- User stories can then proceed in parallel (if staffed)
- Or sequentially in priority order (P1 → P2 → P3)
- **Polish (Final Phase)**: Depends on all desired user stories being complete
### User Story Dependencies
- **User Story 1 (P1)**: Can start after Foundational (Phase 2) - No dependencies on other stories
- **User Story 2 (P2)**: Can start after Foundational (Phase 2) - May integrate with US1 but should be independently testable
- **User Story 3 (P3)**: Can start after Foundational (Phase 2) - May integrate with US1/US2 but should be independently testable
### Parallel Opportunities
- All Setup tasks marked [P] can run in parallel
- All Foundational tasks marked [P] can run in parallel (within Phase 2)
- Once Foundational phase completes, all user stories can start in parallel
- Models within a story marked [P] can run in parallel
---
## Parallel Example: User Story 1
```bash
# Launch all models for User Story 1 together:
Task: "Verify Tailwind directives in frontend/src/app.css"
```
---
## Implementation Strategy
### MVP First (User Story 1 Only)
1. Complete Phase 1: Setup
2. Complete Phase 2: Foundational (CRITICAL - blocks all stories)
3. Complete Phase 3: User Story 1
4. **STOP and VALIDATE**: Test User Story 1 independently
5. Deploy/demo if ready
### Incremental Delivery
1. Complete Setup + Foundational → Foundation ready
2. Add User Story 1 → Test independently → Deploy/Demo (MVP!)
3. Add User Story 2 → Test independently → Deploy/Demo
4. Add User Story 3 → Test independently → Deploy/Demo
5. Each story adds value without breaking previous stories

View File

@@ -66,6 +66,8 @@ As a user, I want a consistent look and feel across all pages with a shared navi
- **FR-005**: System MUST handle client-side navigation between routes without full page refreshes.
- **FR-006**: System MUST integrate with the existing backend API for data retrieval.
- **FR-007**: System MUST support data submission via existing API endpoints using standard asynchronous requests.
- **FR-008**: System MUST support WebSocket proxying for real-time task logs (required by `TaskRunner.svelte`).
- **FR-009**: System MUST support data submission for Settings updates and Plugin actions (e.g., triggering backups).
### Key Entities *(include if feature involves data)*

View File

@@ -23,9 +23,9 @@
**Purpose**: Project initialization and basic structure
- [ ] T001 Initialize SvelteKit in `frontend/` directory (replacing current setup)
- [ ] T002 Install `@sveltejs/adapter-static` in `frontend/package.json`
- [ ] T003 [P] Configure `frontend/svelte.config.js` for static adapter and SPA fallback
- [x] T001 Initialize SvelteKit in `frontend/` directory (replacing current setup)
- [x] T002 Install `@sveltejs/adapter-static` in `frontend/package.json`
- [x] T003 [P] Configure `frontend/svelte.config.js` for static adapter and SPA fallback
---
@@ -35,10 +35,11 @@
**⚠️ CRITICAL**: No user story work can begin until this phase is complete
- [ ] T004 Create `frontend/src/routes/+layout.ts` to disable SSR and prerendering (`ssr = false`, `prerender = false`)
- [ ] T005 Implement catch-all route in `backend/src/app.py` to serve `index.html` for SPA routing
- [ ] T006 [P] Update `backend/src/app.py` to mount `frontend/build` directory using `StaticFiles`
- [ ] T007 [P] Update `frontend/src/lib/api.js` to ensure compatibility with SvelteKit environment
- [x] T004 Create `frontend/src/routes/+layout.ts` to disable SSR and prerendering (`ssr = false`, `prerender = false`)
- [x] T005 Implement catch-all route in `backend/src/app.py` to serve `index.html` for SPA routing
- [x] T006 [P] Update `backend/src/app.py` to mount `frontend/build` directory using `StaticFiles`
- [x] T007 [P] Update `frontend/src/lib/api.js` to ensure compatibility with SvelteKit environment
- [x] T022 [FR-008] Configure WebSocket proxying in `backend/src/app.py` and `frontend/vite.config.js`
**Checkpoint**: Foundation ready - user story implementation can now begin in parallel
@@ -52,9 +53,11 @@
### Implementation for User Story 1
- [ ] T008 [P] [US1] Create Dashboard route in `frontend/src/routes/+page.svelte` (migrating from `App.svelte`/`Dashboard.svelte`)
- [ ] T009 [P] [US1] Create Settings route in `frontend/src/routes/settings/+page.svelte` (migrating from `Settings.svelte`)
- [ ] T010 [US1] Implement navigation links between Dashboard and Settings in `frontend/src/routes/+page.svelte` and `frontend/src/routes/settings/+page.svelte`
- [x] T008 [P] [US1] Create Dashboard route in `frontend/src/routes/+page.svelte` (migrating from `App.svelte`/`Dashboard.svelte`)
- [x] T009 [P] [US1] Create Settings route in `frontend/src/routes/settings/+page.svelte` (migrating from `Settings.svelte`)
- [x] T010 [US1] Implement navigation links between Dashboard and Settings in `frontend/src/routes/+page.svelte` and `frontend/src/routes/settings/+page.svelte`
- [x] T023 [US1] Implement "Save Settings" form submission in `frontend/src/routes/settings/+page.svelte`
- [x] T024 [US1] Implement plugin action triggers (e.g., "Run Backup") in `frontend/src/routes/+page.svelte`
**Checkpoint**: At this point, User Story 1 should be fully functional and testable independently.
@@ -68,10 +71,10 @@
### Implementation for User Story 2
- [ ] T011 [P] [US2] Implement `load` function for Dashboard in `frontend/src/routes/+page.ts` to fetch plugins from `/api/plugins/`
- [ ] T012 [P] [US2] Implement `load` function for Settings in `frontend/src/routes/settings/+page.ts` to fetch config and environments from `/api/settings/`
- [ ] T013 [US2] Update `frontend/src/routes/+page.svelte` to use data from `load` function via `export let data;`
- [ ] T014 [US2] Update `frontend/src/routes/settings/+page.svelte` to use data from `load` function via `export let data;`
- [x] T011 [P] [US2] Implement `load` function for Dashboard in `frontend/src/routes/+page.ts` to fetch plugins from `/api/plugins/`
- [x] T012 [P] [US2] Implement `load` function for Settings in `frontend/src/routes/settings/+page.ts` to fetch config and environments from `/api/settings/`
- [x] T013 [US2] Update `frontend/src/routes/+page.svelte` to use data from `load` function via `export let data;`
- [x] T014 [US2] Update `frontend/src/routes/settings/+page.svelte` to use data from `load` function via `export let data;`
**Checkpoint**: At this point, User Stories 1 AND 2 should both work independently.
@@ -85,9 +88,9 @@
### Implementation for User Story 3
- [ ] T015 [US3] Create shared layout in `frontend/src/routes/+layout.svelte` with `<slot />`
- [ ] T016 [P] [US3] Move navigation bar component to `frontend/src/components/Navbar.svelte` and include in `+layout.svelte`
- [ ] T017 [P] [US3] Create footer component in `frontend/src/components/Footer.svelte` and include in `+layout.svelte`
- [x] T015 [US3] Create shared layout in `frontend/src/routes/+layout.svelte` with `<slot />`
- [x] T016 [P] [US3] Move navigation bar component to `frontend/src/components/Navbar.svelte` and include in `+layout.svelte`
- [x] T017 [P] [US3] Create footer component in `frontend/src/components/Footer.svelte` and include in `+layout.svelte`
**Checkpoint**: All user stories should now be independently functional.
@@ -97,10 +100,12 @@
**Purpose**: Improvements that affect multiple user stories
- [ ] T018 [P] Implement custom 404 error page in `frontend/src/routes/+error.svelte`
- [ ] T019 Add graceful error handling for API failures in `load` functions (T011, T012)
- [ ] T020 [P] Update `frontend/README.md` with new SvelteKit-based development and build instructions
- [ ] T021 Run `specs/004-integrate-svelte-kit/quickstart.md` validation
- [x] T018 [P] Implement custom 404 error page in `frontend/src/routes/+error.svelte`
- [x] T019 Add graceful error handling for API failures in `load` functions (T011, T012)
- [x] T020 [P] Update `frontend/README.md` with new SvelteKit-based development and build instructions
- [x] T021 Run `specs/004-integrate-svelte-kit/quickstart.md` validation
- [x] T025 [FR-008] Update `TaskRunner.svelte` to use SvelteKit-compatible WebSocket connection logic
- [x] T026 [SC-001] Perform performance benchmarking to verify < 200ms transition time
---