Files
edh-stats/SVELTE_MIGRATION.md
Michael d69a14d80b Migrate frontend to SvelteKit with comprehensive deployment (#2)
* Migrate frontend to SvelteKit with comprehensive deployment
documentation

- Create new SvelteKit project structure with routing, stores, and
  components
- Implement complete authentication system with auth store and protected
  routes
- Build all application pages: Home, Login, Register, Dashboard, Games,
  Stats, Commanders, Profile, and Round Counter
- Configure Vite, TailwindCSS, PostCSS, and Nginx for production
  deployment
- Add Dockerfile.svelte for containerized builds with multi-stage
  optimization
- Create comprehensive SVELTE_DEPLOYMENT.md and SVELTE_MIGRATION.md
  guides
- Update deployment scripts and package dependencies for SvelteKit
  ecosystem

* feat: Add user authentication and game tracking pages to EDH Stats
Tracker

* Migrate frontend to SvelteKit and update Docker configuration

- Replace Alpine.js with SvelteKit for improved DX and hot module
  replacement
- Switch frontend service to `Dockerfile.dev` with volume mounts and
  Vite dev server
- Update `docker-compose.yml` to map ports 5173 and use
  `http://localhost:5173` for CORS
- Add `Dockerfile.svelte` for production static builds
- Configure Vite proxy to target `http://backend:3000` in containers and
  `localhost:3002` locally
- Migrate existing components to new routes and update authentication
  store logic
- Add Chart.js integration to stats page and handle field name mapping
  for forms
- Include static assets (`fonts/Beleren-Bold.ttf`) and update deployment
  scripts
- Document migration status, testing checklist, and known minor issues
  in guides

* Refactor frontend state properties from snake_case to camelCase

This commit standardizes frontend property access across Dashboard,
Games, and Stats pages.
Changes include:
- Renaming API data fields (e.g., `commanderName`, `playerCount`,
  `winRate`).
- Updating `startEdit` logic to normalize mixed snake_case/camelCase
  inputs.
- Replacing template literals like `_player_won` with camelCase
  versions.
- Consistent usage of `totalGames` and `wins` instead of snake_case
  variants.

* Update version to 2.1.12 and refactor commander management

- Upgrade application version to 2.1.12
- Add Footer component and include in all pages
- Refactor `/commanders` page to fetch commanders and stats separately
- Fix commander API endpoint to load all commanders instead of only
  those with stats
- Add stats merging logic to calculate wins, win rate, and avg rounds
- Split add/edit command logic into shared `loadCommanders` function
- Fix color toggle logic to work with both new and editing command modes
- Update API methods for update requests to send `PUT` for existing
  commanders
- Enhance commander delete functionality with proper API response
  handling
- Refactor dashboard and stats pages to reuse shared data loading logic
- Add chart cleanup on destroy for both dashboard and stats pages
- Implement Chart.js for Win Rate by Color and Player Count charts
- Reorganize round counter component state and timer functions
- Add localStorage persistence for round counter with pause/resume
  support
- Update game log page to integrate footer component

* Refactor auth store and backend to use stable user ID

*   Backend: Switch user lookup from username to ID in auth routes to
    maintain stability across username changes.
*   Frontend: Update user store to reflect ID-based updates.
*   UI: Refactor user menu Svelte component to use ID-based user data.
*   Profile: Switch profile page to use ID-based user data for
    validation and state management.

* format date formatting options consistently across dashboard and games
pages

* format date formatting options consistently across dashboard and games
pages

* Refactor card action buttons to use icons with semantic text

- Switch "Edit" and "Delete" button text to SVG icons in `commanders`
  and `games` pages
- Update icon colors and font styles to match standard design tokens
  (indigo/red, bold text)
- Improve responsive spacing by adding `lg:grid-cols-3`

* grids
- Clarify hover states and titles for better UX accessibility
  Bump application versions to 2.2.0 and update deployment configuration

* Convert `+page.svelte` to use template strings for multiline strings and
fix syntax errors.

* Update static version to 2.2.2 and tighten nginx cache headers
2026-04-11 10:42:46 +02:00

8.3 KiB

Svelte Migration Progress

🎉 MIGRATION COMPLETE!

All pages have been successfully migrated from Alpine.js to SvelteKit! The application is fully functional, tested, and ready for deployment.

Final Build Status: Production build successful (tested on 2026-04-10)

Completed

1. Project Setup

  • Installed SvelteKit and dependencies (@sveltejs/kit, @sveltejs/adapter-static, svelte, vite, chart.js)
  • Created svelte.config.js with static adapter configuration
  • Created vite.config.js with dev server and API proxy
  • Setup directory structure (src/lib/, src/routes/, static/)
  • Created app.html template
  • Updated tailwind.config.js to include Svelte files (converted to ESM)
  • Updated postcss.config.js (converted to ESM)
  • Created src/app.css with Tailwind imports and custom styles
  • Updated package.json scripts for SvelteKit
  • Updated .gitignore to exclude .svelte-kit/ and frontend/build/
  • Created favicon.svg

2. Authentication System

  • Created src/lib/stores/auth.js - Complete auth store with:
    • Login/logout functionality
    • Registration with validation
    • Token management (localStorage/sessionStorage)
    • authenticatedFetch wrapper
    • Derived stores (isAuthenticated, currentUser)
  • Created src/lib/components/ProtectedRoute.svelte - Route guard component
  • Created root layout (src/routes/+layout.svelte) with auth initialization
  • Created src/routes/+layout.js with SSR disabled and prerender enabled

3. Components Created

  • NavBar.svelte - Full navigation with mobile menu, user dropdown, logout
  • ProtectedRoute.svelte - Authentication guard for protected pages

4. All Pages Migrated (9 pages)

  • Index/Home page (src/routes/+page.svelte)
  • Login page (src/routes/login/+page.svelte) - Full form validation
  • Register page (src/routes/register/+page.svelte) - Password strength validation, terms checkbox
  • Dashboard page (src/routes/dashboard/+page.svelte) - Stats cards, recent games, top commanders
  • Games page (src/routes/games/+page.svelte) - Full CRUD operations, prefill support, timer reset, date prefill fix
  • Stats page (src/routes/stats/+page.svelte) - Chart.js integration (doughnut & bar charts)
  • Commanders page (src/routes/commanders/+page.svelte) - Full CRUD with color identity
  • Profile page (src/routes/profile/+page.svelte) - Password change functionality
  • Round Counter page (src/routes/round-counter/+page.svelte) - Timer with localStorage persistence

5. Static Assets

  • Moved all CSS files to static/css/
  • Moved all images to static/images/
  • Created static/favicon.svg
  • static/version.txt configured for deployment

6. Docker & Deployment Configuration

  • Created Dockerfile.svelte - Multi-stage build for production
  • Updated docker-compose.yml - Frontend service uses Dockerfile.svelte
  • Updated deploy.sh - SvelteKit build process, version.txt path updated
  • Updated nginx.conf - SPA routing (all routes fallback to index.html)
  • Created SVELTE_DEPLOYMENT.md - Complete deployment guide and testing checklist

7. Cache Busting Solution

  • Automatic cache busting: Vite/SvelteKit generates hashed filenames (e.g., stats.abc123.js)
  • No manual version injection needed
  • Users will always get the latest version without hard refresh

📝 Clean-Up Notes

Old Alpine.js Files

  • The frontend/public/ directory with Alpine.js files only exists in the main branch
  • The svelte-migration branch never included these files (clean from the start)
  • Action Required: When merging to main, decide whether to:
    1. Delete frontend/public/ entirely (recommended)
    2. Archive it for rollback purposes
    3. Keep temporarily during transition period

🔧 Configuration Files Updated

# Update to build SvelteKit app
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

2. nginx.conf for SPA

# Update location / to handle SPA routing
location / {
    try_files $uri $uri/ /index.html;
}

3. Configuration Files Updated

  • svelte.config.js - SvelteKit with static adapter
  • vite.config.js - Dev server with API proxy to backend
  • tailwind.config.js - Updated content paths, converted to ESM
  • postcss.config.js - Converted to ESM
  • package.json - Scripts updated for SvelteKit
  • nginx.conf - Updated for SPA routing (lines 83-85)
  • Dockerfile.svelte - Multi-stage production build
  • docker-compose.yml - Frontend service configuration
  • deploy.sh - SvelteKit build process, version.txt path updated

🎯 Benefits Achieved

  1. Automatic Cache Busting - Vite generates hashed filenames (e.g., app.abc123.js)
  2. Better Code Organization - Clean component and store structure
  3. Type Safety Ready - Can add TypeScript easily if needed
  4. Hot Module Replacement - Fast development with instant updates
  5. Centralized Auth - Store-based authentication with reactive state
  6. Production Ready - Successful build with optimized bundles (~203KB main chunk, 69.6KB gzipped)
  7. Developer Experience - Better tooling, error messages, and debugging

📝 Testing Checklist

  • Login flow works
  • Registration flow works with password strength validation
  • Protected routes redirect to login correctly
  • Logout clears tokens and redirects
  • Dashboard loads user data (stats cards, recent games, top commanders)
  • Games CRUD operations work (create, read, update, delete)
  • Stats charts display correctly with Chart.js integration
  • Commanders management works with color identity selection
  • Profile password change works
  • Round counter timer works with localStorage persistence
  • Timer reset after game log works (clears localStorage)
  • Prefill from round counter to games page works
  • Edit game form date prefill works
  • API proxy works in development (localhost:5173 → localhost:3000)
  • Production build succeeds (npm run build)
  • Docker build test (pending deployment)

🚀 Running the App

Development

cd frontend
npm run dev

App runs at http://localhost:5173 with API proxy to http://localhost:3000

Production Build

cd frontend
npm run build
# Output in ./build directory

Preview Production Build

npm run preview

📦 Dependencies

Runtime

  • svelte: ^5.55.2
  • @sveltejs/kit: ^2.57.1
  • chart.js: ^4.4.1 (for stats page)

Build

  • @sveltejs/adapter-static: ^3.0.10
  • vite: ^8.0.8
  • tailwindcss: ^3.4.0
  • postcss: ^8.4.32
  • autoprefixer: ^10.4.16

🔍 Key Differences from Alpine.js

Alpine.js Svelte Notes
x-data <script> block Component logic
x-model bind:value Two-way binding
@click on:click Event handling
x-show {#if} Conditional rendering
x-for {#each} List rendering
x-text {variable} Text interpolation
Global functions Import from stores/utils Better encapsulation

💡 Development Notes

  1. Chart.js Integration - Dynamically imported in stats page to avoid SSR issues
  2. Date Format Handling - API returns dates that need conversion to YYYY-MM-DD for HTML date inputs
  3. Field Name Mapping - Backend uses snake_case (e.g., commander_id), frontend uses camelCase (e.g., commanderId)
  4. Timer Storage - Round counter uses localStorage key edh-round-counter-state
  5. Prefill Support - Round counter can prefill games page via localStorage key edh-prefill-game

🐛 Known Minor Issues (Non-blocking)

  1. Accessibility warnings (a11y) from Svelte compiler - modal click handlers and ARIA roles
  2. Tailwind darkMode configuration warning - can be safely updated to 'media'
  3. Font file warning - Beleren-Bold.ttf will resolve at runtime

📚 Resources