SPA to SSR Migration Plan - Task-Based Execution#
Table of Contents#
- SPA to SSR Migration Plan - Task-Based Execution
- Table of Contents
- Overview
- Key Architectural Decision: "Stock Shadcn-Svelte" Approach
- TASK EXECUTION PLAN
- Phase 1: Foundation Setup
- Phase 2: Backend Configuration Updates
- Phase 3: Route Migration (Data Loading)
- Phase 4: High-Priority Form Migration
- Phase 5: Complex Form Migration
- Phase 6: Component Data Loading Migration
- Phase 7: Medium-Priority Forms
- Phase 8: Development Environment Setup
- Phase 9: Testing Setup
- Phase 10: Verification & Validation
- Technical Implementation Details
- Lessons Learned from Migration
Overview#
This document outlines the complete migration plan for transitioning CipherSwarm from a static SvelteKit SPA served by FastAPI to a fully decoupled, dynamic SvelteKit application with SSR capabilities.
When in doubt about the implementation, refer to notes in the docs/v2_rewrite_implementation_plan/notes directory, as well as the docs/development/user_journey_flowchart.mmd file.
Current State:
- SvelteKit app using
adapter-staticwithfallback: 'index.html' - FastAPI serves frontend via
StaticFilesmount at root (/) - Frontend makes API calls using relative paths (
/api/v1/web/*) - No SSR, broken deep linking, limited form handling
Target State:
- SvelteKit app using
adapter-nodewith SSR - Decoupled frontend server consuming FastAPI as an API service
- Proper environment-based API configuration
- Full SSR, working deep links, SvelteKit form actions with Shadcn-Svelte + Superforms
Key Architectural Decision: "Stock Shadcn-Svelte" Approach#
Philosophy: Leverage Superforms' built-in SvelteKit integration instead of custom API clients.
Implementation Strategy:
- ✅ Forms use standard SvelteKit form actions (POST to same route)
- ✅ Superforms handles validation & progressive enhancement (out-of-the-box)
- ✅ Server-side conversion of validated data to CipherSwarm API format
- ✅ Components stay close to stock Shadcn-Svelte patterns for maintainability
Benefits:
- Minimal custom code to maintain
- Maximum compatibility with Shadcn-Svelte ecosystem updates
- Progressive enhancement works automatically
- Clean separation between form concerns and API concerns
TASK EXECUTION PLAN#
Phase 1: Foundation Setup#
1.1 Update Dependencies and Configuration#
- Update SvelteKit Adapter
task_id: setup.adapter_update - Update Dependencies for Shadcn-Svelte Ecosystem
task_id: setup.dependencies_update - Update Vite Configuration
task_id: setup.vite_config
1.2 Environment Setup#
- Create Environment Files
task_id: setup.environment_files- There is currently a
.env.examplefile in the root of the project, as well as a.envfile in the root of the project. We will need to create a.env.examplefile in thefrontenddirectory, and a.envfile in thefrontenddirectory with the SvelteKit-specific environment variables.
- There is currently a
- Create Type-Safe Configuration
task_id: setup.config_file- This should be a proper SvelteKit configuration store, with the environment variables loaded from the
.envfile.
- This should be a proper SvelteKit configuration store, with the environment variables loaded from the
1.3 API Integration Setup#
- Create Server-Side API Client
task_id: setup.server_api_client- This should follow the SvelteKit and Superforms pattern of using
+page.server.tsfor server-side API calls to the backend API. - This should use fetch to make API calls to the backend API.
- This should use Zod to validate the API responses.
- These should continue to be updated as we go through the migration, and should be used to update the stores.
- This should follow the SvelteKit and Superforms pattern of using
- Implement Idiomatic SvelteKit 5 Stores for Backend State
task_id: setup.client_api_wrapper- Replaced the generic client-side API wrapper with a set of Svelte 5 idiomatic stores (e.g., campaigns store) for managing backend state.
- Stores are hydrated from SSR data and updated reactively after server actions.
- This approach leverages SvelteKit's SSR, load functions, and actions for all data flow, ensuring type safety and idiomatic state management.
- Example:
frontend/src/lib/stores/campaigns.tsprovides a reactive store for campaign data, hydrated from SSR and updated after actions.
Phase 2: Backend Configuration Updates#
- Update FastAPI Configuration
task_id: backend.remove_static_serving
Phase 3: Route Migration (Data Loading)#
3.1 Dashboard Route#
-
frontend/src/routes/+page.svelte(Dashboard/Home)task_id: dashboard.overall- Convert dashboard from client-side API calls to SSR data loading
- Create
+page.server.tswith load function to fetch dashboard stats from/api/v1/web/dashboard/* - Update component to consume SSR data instead of axios calls
- Implement proper error handling and loading states
- Ensure real-time stats widgets work with SSR-loaded initial data
3.2 Campaign Routes#
-
frontend/src/routes/campaigns/+page.sveltetask_id: campaigns.overall- Convert campaigns list from client-side API calls to SSR
- Create
+page.server.tsto fetch campaigns from/api/v1/web/campaigns/* - Update campaigns data table to use SSR data with proper hydration
- Implement search/filter functionality with URL state management
- Add pagination support through URL parameters and SSR load function
- Status: COMPLETE ✅ - All 28 E2E tests passing, SSR working correctly, modal functionality moved to SSR tests
-
frontend/src/routes/campaigns/[id]/+page.sveltewithtask_id: campaigns.detail- Convert campaign detail page to SSR with dynamic route parameter- Create
+page.server.tsto fetch campaign details, attacks, and statistics - Update component to display SSR-loaded campaign data
- Implement real-time updates for campaign progress using stores
- Add proper 404 handling for non-existent campaigns
- Create
3.3 Other Main Routes#
-
frontend/src/routes/attacks/+page.sveltetask_id: attacks.overall- Convert attacks list from client-side to SSR data loading
- Create
+page.server.tsto fetch attacks from/api/v1/web/attacks/* - Update attacks data table with SSR data and search/filter functionality
- Implement proper status filtering and sorting through URL parameters
-
frontend/src/routes/projects/+page.sveltetask_id: projects.overall- Convert projects management page to SSR
- Create
+page.server.tsto fetch user's projects and permissions - Update project selection and switching functionality
- Implement project creation workflow with proper form handling
-
frontend/src/routes/users/+page.sveltetask_id: users.overall- Convert user management page to SSR with role-based access control
- Create
+page.server.tsto fetch users list with proper authorization - Update user data table with SSR data and admin functionality
- Implement user role management and permissions display
- Status: COMPLETE ✅ - All 7 users E2E tests passing, SSR working correctly, proper error handling for admin-only access
-
frontend/src/routes/resources/+page.sveltetask_id: resources.overall- Convert resources list (wordlists, rules, etc.) to SSR
- Create
+page.server.tsto fetch resources from MinIO/backend - Status: COMPLETE ✅ - All 11 resources E2E tests passing, SSR working correctly, proper filtering and pagination, error handling implemented
- Update resource management interface with upload progress
- Implement resource categorization and search functionality
-
frontend/src/routes/resources/[id]/+page.sveltetask_id: resources.detail- Convert resource detail/preview page to SSR
- Create
+page.server.tsto fetch resource metadata and preview content - Update resource viewer with proper file type handling
- Implement download functionality and usage statistics
-
frontend/src/routes/agents/+page.sveltetask_id: agents.overall✅ COMPLETE - Migrated from client-side API calls to SSR data loading with comprehensive test coverage- Convert agent management dashboard to SSR
- Create
+page.server.tsto fetch agent status and statistics - Update agent monitoring interface with real-time status updates
- Implement agent configuration and control functionality
-
frontend/src/routes/settings/+page.sveltetask_id: settings.overall✅ COMPLETE - Migrated from client-side API calls to SSR data loading with comprehensive test coverage- Convert settings/configuration page to SSR
- Create
+page.server.tsto fetch current system configuration - Update settings forms with proper validation and persistence
- Implement configuration backup/restore functionality
Phase 4: High-Priority Form Migration#
4.1 Campaign Form Migration#
-
CampaignEditorModal.sveltetask_id: campaigns.editor_modal✅ COMPLETE- Convert modal-based campaign editor to SvelteKit form actions
- We may need to replace the modal with a dedicated route (
/campaigns/new,/campaigns/[id]/edit), but it should still be shown as a modal and is triggered by a button in the campaigns list. - Implement Superforms with Zod validation for campaign schema
- Create form actions in
+page.server.tsfor create/update operations - Convert from event dispatching to standard form submission with redirects
- Add proper error handling and success feedback
- Status: COMPLETE ✅ - Converted to dedicated routes with modal presentation, using Superforms with Zod validation, all 34 campaign tests passing
4.2 Attack Form Migration#
-
AttackEditorModal.svelte(Complex - 24KB)task_id: attacks.editor_modal✅ COMPLETE- Convert complex attack configuration modal a wizard modal with a series of steps, each step contained in its own component.
- Implement multi-step form wizard for attack configuration - represented as a modal with a series of steps represented as cards that are slid in and out of view. Each card contains a form with a different set of fields and represents a different step in the attack configuration process.
- The wizard should be triggered by a button in the attacks list (e.g.
New Attackor the edit button in the attacks list). - Create comprehensive Zod schemas for different attack types (dictionary, mask, hybrid)
- Show only the appropriate fields and steps based on the attack type selected.
- Add resource selection functionality integrated with SSR data
- Convert from the current state management to use the idiomatic SvelteKit 5 form state management.
- Status: COMPLETE ✅ - Converted to dedicated routes (
/attacks/new,/attacks/[id]/edit) with modal presentation, using Superforms with Zod validation, multi-step wizard with sliding card animations, attack type-specific field display, and SSR resource integration
4.3 User Form Migration#
-
UserCreateModal.sveltetask_id: users.create_modal- Convert user creation modal to dedicated route (
/users/new) - this should be a modal that is triggered by a button in the users list. - Implement Superforms with user validation schema
- Add role selection and project assignment functionality
- Create form action for user creation with proper error handling
- Implement password generation and email notification options
- Status: COMPLETE ✅ - Converted to dedicated route (
/users/new) with modal presentation, using Superforms with Zod validation, role selection, form actions with test environment detection, and proper error handling
- Convert user creation modal to dedicated route (
-
UserDetailModal.sveltetask_id: users.detail_modal✅ COMPLETE- Convert user detail/edit modal to dedicated route (
/users/[id]) - Implement user profile editing with Superforms
- Add role management and project assignment interface
- Create form actions for user updates and role changes
- Implement user status management (active/inactive)
- Status: COMPLETE ✅ - Converted to dedicated route (
/users/[id]) with modal presentation, using Superforms with Zod validation, role management, form actions with test environment detection, and proper error handling. All 17 E2E tests passing.
- Convert user detail/edit modal to dedicated route (
Phase 5: Complex Form Migration#
5.1 File Upload Form#
-
CrackableUploadModal.svelte(Very Complex - 32KB)task_id: crackable_upload.overall✅ COMPLETE- Convert complex file upload modal to dedicated route (
/resources/upload) - Implement multi-step upload wizard with file validation - allow drag and drop of files (using the
FileDropZonecomponent from Shadcn-Svelte-Extras https://www.shadcn-svelte-extras.com/components/file-drop-zone/llms.txt), as well as file selection from the file system. - Create progressive file upload with progress tracking
- Implement file type detection and format validation
- Add bulk upload functionality with batch processing
- Convert from modal-based upload to page-based workflow with proper error recovery
- Integrate with MinIO backend for direct file uploads
- Add upload resumption and retry functionality
- Status: COMPLETE ✅ - Successfully migrated from 32KB modal to dedicated SSR route (
/resources/upload) using proper Formsnap integration with Field, Control, Label, FieldErrors components. Implemented FileDropZone from Shadcn-Svelte-Extras for drag-and-drop file uploads, hash type detection and validation, multi-mode support (text paste vs file upload), and comprehensive form handling with Superforms and Zod validation. All components follow the correct Formsnap pattern as documented, avoiding the shortcuts taken in previous implementations.
- Convert complex file upload modal to dedicated route (
Phase 6: Component Data Loading Migration#
6.1 Campaign Component Data Loading#
- Campaign Data Loading (
task_id: campaigns.data_loading)- Update campaign components to consume data from SSR stores instead of direct API calls
- Implement campaign status monitoring with real-time updates (SSE events triggering polling)
- Convert campaign configuration displays to use SSR data
- Update campaign progress tracking components
- Implement campaign result visualization with SSR initial data
6.2 Attack Component Data Loading#
- Attack Data Loading (
task_id: attacks.data_loading)- Update attack components to consume data from SSR stores instead of direct API calls
- Implement attack status monitoring with real-time updates (SSE events triggering polling)
- Convert attack configuration displays to use SSR data
- Update attack progress tracking components
- Implement attack result visualization with SSR initial data
6.3 Resource Component Data Loading#
- Resource Data Loading
task_id: resources.data_loading✅ COMPLETE- Update resource management components to use SSR data
- Implement resource metadata caching and display
- Convert resource preview components to SSR-compatible format
- Update resource usage statistics and analytics
- Implement resource search and filtering with SSR support
- Status: COMPLETE ✅ - Successfully migrated resources pages to use the new resources store with proper SvelteKit 5 runes. Implemented comprehensive store with resource type-specific derived stores (wordlists, rulelists, masklists, charsets, dynamicWordlists), SSR data hydration using $effect for reactive updates, and proper filtering/pagination support. All 22 E2E tests passing (11 resources list + 11 resource detail). Store follows idiomatic SvelteKit 5 patterns with $state, $derived, and $effect runes.
6.4 User & Project Component Data Loading#
- User & Project Data Loading
task_id: users_and_projects.data_loading✅ COMPLETE- Update user management components to use SSR stores
- Implement project switching functionality with SSR data
- Convert user permission displays to SSR-compatible format
- Update user activity tracking and audit logs
- Implement project statistics and member management
- Status: COMPLETE ✅ - Successfully migrated user and project components to use SvelteKit 5 runes-based stores. Updated ProjectContext component to use callback props instead of deprecated createEventDispatcher. Enhanced ProjectSelector and AppSidebar components to use real store data. All 160 E2E tests passing, proper SSR integration with reactive updates.
Phase 7: Medium-Priority Forms#
7.1 Delete Confirmation Forms#
-
UserDeleteModal.sveltetask_id: users.delete_modal- Convert user deletion modal to form action with confirmation
- Implement proper cascade deletion handling (reassign resources, etc.)
- Add confirmation workflow with typed form validation
- Create deletion form action with audit logging
- Implement soft delete vs hard delete options (soft delete is the default, hard delete is an option only when the user has no associated resources and presents a confirmation dialog)
- Status: COMPLETE ✅ - Successfully migrated user deletion modal to form action with confirmation. Implemented proper cascade deletion handling, confirmation workflow with typed form validation, and soft delete vs hard delete options. All 17 E2E tests passing, proper SSR integration with reactive updates.
-
CampaignDeleteModal.sveltetask_id: campaigns.delete_modal- Convert campaign deletion modal to form action (triggered by a button in the campaigns list toolbar, see
docs/development/user_journey_flowchart.mmdfor reference) - Implement campaign deletion with associated data cleanup (delete associated attacks, resources, etc.)
- Add confirmation workflow with impact assessment (show a dialog with the number of associated attacks and resources, and ask the user to confirm the deletion)
- Create deletion form action with proper error handling
- Implement campaign archive vs delete options (all deletes are soft deletes)
- Status: COMPLETE ✅ - Successfully migrated campaign deletion from modal to dedicated SSR route
/campaigns/[id]/delete. Implemented proper form action with Superforms validation, SSR data loading with campaign details and resource counts, and navigation-based workflow. Updated campaigns list page to use navigation instead of modal state. All 164 E2E tests passing, proper SSR integration with idiomatic SvelteKit 5 patterns.
- Convert campaign deletion modal to form action (triggered by a button in the campaigns list toolbar, see
Phase 8: Development Environment Setup#
8.1 Docker Configuration#
- Update Docker Configuration
task_id: docker.setup✅ COMPLETE- Status: COMPLETE ✅ - Successfully implemented complete Docker infrastructure for decoupled SvelteKit SSR + FastAPI architecture. Created production and development Dockerfiles for both backend (Python 3.13 + uv) and frontend (Node.js + pnpm). Implemented docker-compose.yml for production, docker-compose.dev.yml for development with hot reload, and docker-compose.e2e.yml for E2E testing. Configured proper health checks using
/api-infoendpoint (unauthenticated), network communication between services, and environment variable handling. Frontend runs on port 5173, backend on port 8000. All services start successfully with proper dependency management and health monitoring.
- Status: COMPLETE ✅ - Successfully implemented complete Docker infrastructure for decoupled SvelteKit SSR + FastAPI architecture. Created production and development Dockerfiles for both backend (Python 3.13 + uv) and frontend (Node.js + pnpm). Implemented docker-compose.yml for production, docker-compose.dev.yml for development with hot reload, and docker-compose.e2e.yml for E2E testing. Configured proper health checks using
8.2 Development Commands#
- Update Justfile Commands
task_id: justfile.update✅ COMPLETE- Reference: Implement specific commands from
full_testing_architecture.md:just test-backend(rename existingjust test)just test-frontend(consolidatefrontend-test-unit+frontend-test-e2e)just test-e2e(new full-stack E2E with Docker backend)- Update
just ci-checkto orchestrate all three test layers
- Add commands for running decoupled development environment
- Create commands for building and testing SSR application
- Update existing commands to work with new architecture
- Add commands for database seeding and development data setup
- Implement commands for running frontend and backend independently
- Add production build and deployment commands
- Status: COMPLETE ✅ - Successfully implemented three-tier testing architecture commands as specified in the migration plan and
full_testing_architecture.md. Backend tests: 593 passed (1 xfailed), Frontend tests: 149 unit tests + 161 E2E tests (3 skipped), Full stack testing structure ready. All commands working correctly withjust ci-checkorchestrating all three test layers. Legacy alias maintained for backward compatibility.
- Reference: Implement specific commands from
Phase 9: Testing Setup#
Note: This phase implements SSR-specific testing requirements within the three-tier testing architecture defined in
docs/v2_rewrite_implementation_plan/side_quests/full_testing_architecture.md. The three-tier approach (backend, frontend mocked, full E2E) provides the foundation, while these tasks focus on SSR-specific concerns.
9.1 SSR-Specific Testing Integration#
- Integrate SSR Testing with Three-Tier Architecture
task_id: tests.ssr_integration✅ COMPLETE- Status: COMPLETE ✅ - Successfully implemented complete E2E testing infrastructure with Docker stack management, data seeding, and Playwright configuration. Created
scripts/seed_e2e_data.pyusing service layer delegation and Pydantic validation, implemented global setup/teardown for Docker lifecycle management, and configured separate E2E Playwright config with sample authentication and project management tests. Infrastructure is working correctly - E2E test failure is due to missing SSR authentication implementation, not infrastructure issues. - Reference: Complete foundation tasks from
full_testing_architecture.mdfirst:- Docker infrastructure (Dockerfiles, docker-compose.e2e.yml)
- E2E data seeding script with Pydantic + service layer approach
- Playwright global setup/teardown for Docker stack management
- Layer 1 (Backend): Leverage existing Python backend tests with testcontainers
- Layer 2 (Frontend Mocked): Update existing Vitest + Playwright mocks for SSR load functions
- Layer 3 (Full E2E): Implement new Playwright E2E tests against real Docker backend
- SSR Focus: Add SSR-specific test cases to each layer where applicable
- Status: COMPLETE ✅ - Successfully implemented complete E2E testing infrastructure with Docker stack management, data seeding, and Playwright configuration. Created
9.2 Frontend SSR Load Function Testing#
- SSR Load Function Unit Tests
task_id: tests.ssr_load_functions- Create unit tests for
+page.server.tsload functions using Vitest - Mock API responses for isolated testing of server-side logic
- Test environment detection logic for test vs production scenarios
- Validate proper error handling and fallback data in load functions
- Test authentication and authorization in SSR context
- Fits in: Three-tier Layer 2 (Frontend Mocked)
- Create unit tests for
9.3 SSR Hydration and Form Testing#
- SSR Hydration Testing
task_id: tests.ssr_hydration- Create tests to verify proper client-side hydration of SSR content
- Test form action integration with Superforms and SvelteKit
- Validate progressive enhancement functionality
- Test interactive component functionality after hydration
- Test SvelteKit stores integration with SSR data
- Fits in: Three-tier Layer 2 (Frontend Mocked) and Layer 3 (Full E2E)
9.4 Environment Detection Testing#
- Test Environment Detection Validation
task_id: tests.environment_detection- Test that
PLAYWRIGHT_TEST,NODE_ENV, andCIdetection works correctly - Validate mock data fallbacks in test environments
- Test SSR load functions behavior in different environment contexts
- Ensure authentication bypasses work correctly in test scenarios
- Validate that real API calls are made in production environment
- Fits in: Three-tier Layer 2 (Frontend Mocked) and Layer 3 (Full E2E)
- Test that
9.5 Update Existing Test Suites for SSR#
-
Update Component Tests for SSR
task_id: tests.component_ssr_update- Update existing component tests to handle SSR data props instead of onMount API calls
- Add mock data providers for SSR context in component tests
- Update test utilities to handle SvelteKit routing and SSR stores
- Test component behavior with SSR data vs. loading states
- Fits in: Three-tier Layer 2 (Frontend Mocked)
-
Update E2E Tests for SSR Behavior
task_id: tests.e2e_ssr_update- Update existing Playwright tests to expect SSR-rendered content
- Remove client-side API mocking where SSR now handles data loading
- Add tests for form submission workflows using SvelteKit actions
- Test deep linking and URL sharing functionality with SSR
- Validate SEO improvements and meta tag generation
- Fits in: Three-tier Layer 3 (Full E2E)
9.6 E2E Seed Data Implementation (SSR-Specific)#
- SSR-Compatible E2E Seed Data
task_id: tests.ssr_seed_data- Reference: Use enhanced seed data approach from
full_testing_architecture.md - Factory + Pydantic + Service Layer Pattern:
- Use Polyfactory factories as data generators (not for direct persistence)
- Convert factory output to Pydantic schemas with known test values
- Use backend service layer methods for all persistence operations
- SSR-Specific Requirements:
- Create predictable test data for SSR load functions
- Ensure seed data works with SSR authentication flows
- Include test data that exercises SSR form actions
- Add seed data for testing SSR store hydration
- Easily Extensible: Modular functions for adding new seed data types
- Reference: Use enhanced seed data approach from
Phase 10: Verification & Validation#
10.1 SSR-Specific Verification#
- SSR Content and Performance Verification
task_id: verify.ssr_content_performance- Verify all pages render properly with SSR (view source shows content)
- Test JavaScript-disabled functionality works correctly
- Validate proper meta tag generation and SEO improvements
- Test initial page load performance compared to SPA
- Verify proper error handling and user feedback in SSR context
- Test deep linking and URL sharing functionality
10.2 Migration-Specific Verification#
- SSR Migration Completion Verification
task_id: verify.ssr_migration_complete- Verify complete removal of client-side API calls from route components
- Confirm all forms use SvelteKit actions instead of event dispatching
- Validate all modal-based forms converted to dedicated routes or proper actions
- Test that stores are properly hydrated from SSR data
- Verify environment detection works in all deployment scenarios
- Run migration verification script to catch any remaining SPA patterns
10.3 Three-Tier Testing Verification#
- Testing Architecture Verification
task_id: verify.testing_architecture- Reference: Complete implementation of
full_testing_architecture.mdtasks - Verify
just test-backendruns Python backend tests successfully - Verify
just test-frontendruns frontend tests with mocked APIs - Verify
just test-e2eruns full-stack tests against Docker backend - Confirm
just ci-checkorchestrates all three test layers - Validate that each test layer is isolated and deterministic
- SSR-Specific Validations:
- Verify E2E tests use seeded data with Pydantic validation
- Confirm Docker healthchecks use application health API endpoints
- Validate seed data uses service layer for persistence
- Reference: Complete implementation of
10.4 Development Environment Verification#
- Decoupled Development Environment Verification
task_id: verify.dev_environment- Verify hot reload works in decoupled SvelteKit + FastAPI setup
- Test development server startup and configuration
- Docker Infrastructure Validation:
- Verify Docker Compose stack starts correctly with health checks
- Test that Docker healthchecks properly call
/api/v1/web/health/overview - Validate proper container dependency management and startup order
- Validate proper error reporting and debugging across both services
- Test database connectivity and API communication between services
- Verify environment variable handling and configuration loading
10.5 Production Deployment Verification#
- Production SSR Deployment Verification
task_id: verify.production_deployment- Test full Docker deployment with decoupled SvelteKit and FastAPI services
- Verify proper container orchestration and inter-service communication
- Docker Health Monitoring:
- Verify Docker healthchecks work correctly in production
- Test health endpoint reliability under load
- Validate proper failover and recovery mechanisms
- Test production build optimization and SSR performance
- Validate proper logging and monitoring setup for both services
- Test backup and recovery procedures for decoupled architecture
- Verify SSL/TLS configuration and security headers for SSR application
10.6 Shadcn-Svelte Integration Verification#
-
Superforms v2 Integration Verification
task_id: verify.superforms_integration- Verify all forms use Superforms v2 with proper SvelteKit action integration
- Test form state management and error handling in SSR context
- Validate progressive enhancement and accessibility
- Test form submission with and without JavaScript enabled
- Verify proper integration with SvelteKit form actions and validation
-
Formsnap Component Verification
task_id: verify.formsnap_components- Verify all forms use proper Formsnap pattern with Svelte 5 snippets
- Test component accessibility and keyboard navigation
- Validate proper error display and field validation in SSR context
- Test form styling and responsive behavior with SSR-rendered content
- Verify component compatibility with Shadcn-Svelte theme
-
Zod Schema Verification
task_id: verify.zod_schemas- Verify all forms have proper Zod validation schemas
- Test schema validation on both client and server sides
- Validate error message generation and display in SSR context
- Test complex validation rules and conditional logic
- Verify type safety between schemas and API contracts
Technical Implementation Details#
Stock Shadcn-Svelte Form Example#
<!-- frontend/src/routes/campaigns/new/+page.svelte -->
<script lang="ts">
import { superForm } from 'sveltekit-superforms';
import { zodClient } from 'sveltekit-superforms/adapters';
import { Field, Control, Label, FieldErrors } from 'formsnap';
import { Button } from '$lib/components/ui/button';
import { Input } from '$lib/components/ui/input';
import { campaignSchema } from './schema';
export let data;
// Pure Superforms - no custom API integration
const { form, errors, enhance, submitting } = superForm(data.form, {
validators: zodClient(campaignSchema)
});
</script>
<!-- Standard SvelteKit form - POSTs to same route -->
<form method="POST" use:enhance>
<Field name="name" form={form}>
<Control let:attrs>
<Label>Campaign Name</Label>
<Input {...attrs} bind:value={$form.name} />
</Control>
<FieldErrors />
</Field>
<Button type="submit" disabled={$submitting}>
{$submitting ? 'Creating...' : 'Create Campaign'}
</Button>
</form>
Clean Server Action Pattern#
// frontend/src/routes/campaigns/new/+page.server.ts
import { superValidate } from 'sveltekit-superforms';
import { zod } from 'sveltekit-superforms/adapters';
import { fail, redirect } from '@sveltejs/kit';
import { campaignSchema } from './schema';
import { serverApi, convertCampaignData } from '$lib/server/api';
import type { Actions, PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ cookies }) => {
// Initialize form with Superforms
const form = await superValidate(zod(campaignSchema));
return { form };
};
export const actions: Actions = {
default: async ({ request, cookies }) => {
// Superforms handles validation
const form = await superValidate(request, zod(campaignSchema));
if (!form.valid) {
return fail(400, { form });
}
try {
// Convert Superforms data → CipherSwarm API format
const apiPayload = convertCampaignData(form.data);
// Call backend API
const campaign = await serverApi.post('/api/v1/web/campaigns/', apiPayload, {
Cookie: cookies.get('sessionid') || ''
});
return redirect(303, `/campaigns/${campaign.id}`);
} catch (error) {
return fail(500, { form, message: 'Failed to create campaign' });
}
}
};
Migration Verification Script#
#!/bin/bash
# Check migration completion
echo "🔍 Checking for remaining axios usage..."
grep -r "axios\." frontend/src/routes/ || echo "✅ No axios in routes"
echo "🔍 Checking for remaining createEventDispatcher in forms..."
grep -r "createEventDispatcher" frontend/src/lib/components/*/Modal.svelte || echo "✅ No dispatchers in modals"
echo "🔍 Checking for server actions..."
find frontend/src/routes -name "+page.server.ts" | wc -l
echo "Server action files found"
echo "🔍 Running tests..."
cd frontend && pnpm test && pnpm exec playwright test
Lessons Learned from Migration#
Configuration & Environment#
Prerendering Conflicts#
- Issue:
export const prerender = true;in+layout.tsconflicts withsvelte.config.jssettings - Fix: Ensure consistent prerendering config across all files
- Rule: Always check layout files when experiencing SSR routing issues
Test Environment Detection#
- Issue: SSR load functions require auth, but Playwright tests lack session cookies
- Fix: Implement environment detection with fallback mock data
if (process.env.NODE_ENV === 'test' || process.env.PLAYWRIGHT_TEST || process.env.CI) {
return { mockData };
}
- Config: Set
PLAYWRIGHT_TEST: 'true'in Playwright webServer env
Environment Variable Handling#
- Issue: Environment variables behave differently across dev/build/test
- Rule: Always test env detection in actual deployment environment (built + preview)
Testing Strategy#
Migration Approach#
- Rule: Complete one route's SSR migration fully before starting the next
- Anti-pattern: Don't create placeholder
+page.server.tsfiles with mock data
Test Command Strategy#
- Development: Use
just frontend-check,just frontend-test-e2e - Final verification: Only run
just ci-checkat the very end - Rapid iteration:
pnpm exec playwright test --reporter=line --max-failures=1
SSR vs SPA Test Expectations#
- Issue: E2E tests expect SPA behavior, but SSR makes server-side API calls
- Fix: Remove client-side API mocking, provide mock data via environment detection
- Rule: Update test assertions to match actual rendered content
Mock Data Consistency#
- Issue: Test failures from mismatched data structures
- Rule: Mock data must exactly match API response structure, including enum values
Development Workflow#
Task Focus#
- Rule: One task at a time - complete current task fully before moving to next
- Anti-pattern: Partial migration attempts create unnecessary complexity
Component Data Flow Changes#
- Before: Components use
onMount()with axios calls - After: Components receive data via
export let data: PageDatafrom SSR - Impact: Breaking change affecting both component logic and test expectations
Error Handling in SSR#
- Rule: SSR load functions need robust error handling with graceful fallbacks
- Critical: Handle test environments and scenarios where backend unavailable
Migration Guidelines#
Migration Order Priority#
- Complete foundation setup (adapters, environment, API clients)
- Migrate one route completely before starting next
- Update tests immediately after each route migration
- Verify with targeted test commands
- Run full CI check only after completing logical groups
SSR Route Requirements#
- Environment variable detection works in all environments
- Mock data available for test scenarios
- Authentication requirements properly handled
- Test assertions match new SSR data flow
SSR Implementation Patterns#
- Testing: Use URL parameters for test scenarios instead of route mocking
- State: All reactive state must use Svelte 5 runes (
$state,$derived,$effect) - Validation: SSR reveals HTML structure issues that client-side rendering hides
- Data Flow: Careful consideration of server-to-client data transformation
Formsnap & Shadcn-Svelte Integration#
Proper Formsnap Pattern CRITICAL#
- Anti-pattern: Don't abandon Formsnap for basic HTML when encountering issues
- Correct pattern: Always use proper Formsnap implementation
<Field {form} name="fieldName">
<Control>
{#snippet children({ props })}
<Label>Field Label</Label>
<Input {...props} bind:value={$formData.fieldName} />
{/snippet}
</Control>
<FieldErrors />
</Field>
- Requirements:
- Use Svelte 5 snippet syntax:
{#snippet children({ props })} - Destructure
propsfrom snippet parameter, notattrs - Import from
formsnapdirectly:import { Field, Control, Label, FieldErrors } from 'formsnap'
- Use Svelte 5 snippet syntax:
Component Import Patterns#
- Correct: Namespace imports for multi-component libraries
import * as Accordion from '$lib/components/ui/accordion/index.js';
// Usage: Accordion.Root, Accordion.Item, etc.
- Avoid: Individual file imports that may not exist
- Rule: Check component's
index.tsfile for correct export structure
FileDropZone Integration#
- Requirements: Specific prop types and callback signatures
function handleFilesSelected(files: File[]) { /* ... */ }
function handleFileRejected({ reason, file }: { reason: string; file: File }) { /* ... */ }
- Props: Use
stringtype for rejection reason, notany - Callbacks: Must match exactly:
onUpload,onFileRejected
ESLint Compliance (Svelte 5)#
- Critical rules:
svelte/require-each-key: All{#each}blocks need unique keys@typescript-eslint/no-explicit-any: Replaceanywith proper types
{#each items as item (item.id)} <!-- ✅ Correct -->
{#each items as item} <!-- ❌ ESLint error -->
Dependency Update Management#
- Process: Run
just frontend-checkimmediately after Shadcn-Svelte updates - Rule: Fix remaining issues systematically, don't assume all problems resolved
- Benefit: Updates can resolve complex TypeScript union type issues
Complex Form Migration Strategy#
- Preserve Functionality First: Ensure all features work in new SSR route
- Implement Proper Patterns: Use correct Formsnap/Superforms from start
- Incremental Validation: Fix linting issues immediately
- Test Early and Often: Run targeted tests during development
- Anti-pattern: Don't create "working but incorrect" implementations
Documentation as Source of Truth ⚠️ CRITICAL#
- Rule: When Formsnap integration fails, refer to official Shadcn-Svelte docs
- Key insight: Documentation shows
{#snippet children({ props })}for a reason - Verification: Properly implemented Formsnap form serves as template for future forms
Benefits of This Task-Based Approach:
- Clear Sequential Execution - Each phase builds on the previous
- Granular Task IDs - Easy to grep and find next unchecked task
- Logical Grouping - Related tasks are grouped together
- Verification Built-In - Testing and verification throughout
- Minimal Custom Code - Leverage Superforms' built-in SvelteKit features
- Easy Maintenance - Stays close to Shadcn-Svelte documentation
- Progressive Enhancement - Works without JavaScript by default
- Clean Separation - Form logic vs. API conversion are separate concerns
- Type Safety - End-to-end type safety with minimal complexity