SvelteKit Full-Stack Framework

Modern web development with SvelteKit, stores, routing, and SSR patterns

# SvelteKit Best Practices

Comprehensive guide for building full-stack web applications with SvelteKit, including routing, stores, SSR, and modern development patterns.

---

## Core SvelteKit Principles

1. **File-Based Routing System**
   - Use the file system for automatic route generation
   - Implement layouts for shared UI components
   - Handle dynamic routes with parameter brackets
   - Example routing structure:
     ```
     src/routes/
       +layout.svelte          // Root layout
       +page.svelte           // Home page (/)
       about/
         +page.svelte         // About page (/about)
       blog/
         +layout.svelte       // Blog layout
         +page.svelte         // Blog list (/blog)
         [slug]/
           +page.svelte       // Blog post (/blog/[slug])
       dashboard/
         (authenticated)/     // Route group
           +layout.svelte     // Auth layout
           profile/
             +page.svelte     // Profile (/dashboard/profile)
           settings/
             +page.svelte     // Settings (/dashboard/settings)
     ```

2. **Page and Layout Components**
   - Create reusable layouts with slots
   - Implement nested layouts for complex UIs
   - Handle layout-specific styles and logic
   - Example layout implementation:
     ```svelte
     <!-- src/routes/+layout.svelte -->
     <script lang="ts">
       import { page } from '$app/stores';
       import { onMount } from 'svelte';
       import Navigation from '$lib/components/Navigation.svelte';
       import Footer from '$lib/components/Footer.svelte';
       import { authStore } from '$lib/stores/auth';

       onMount(() => {
         // Initialize app-wide logic
         authStore.checkAuthStatus();
       });

       $: currentPath = $page.url.pathname;
     </script>

     <div class="app">
       <Navigation {currentPath} />

       <main class="main-content">
         <slot />
       </main>

       <Footer />
     </div>

     <style>
       .app {
         min-height: 100vh;
         display: flex;
         flex-direction: column;
       }

       .main-content {
         flex: 1;
         padding: 2rem;
       }
     </style>

     <!-- src/routes/blog/+layout.svelte -->
     <script lang="ts">
       import type { LayoutData } from './$types';

       export let data: LayoutData;
     </script>

     <div class="blog-layout">
       <aside class="sidebar">
         <h3>Categories</h3>
         {#each data.categories as category}
           <a href="/blog/category/{category.slug}">
             {category.name}
           </a>
         {/each}
       </aside>

       <div class="content">
         <slot />
       </div>
     </div>

     <style>
       .blog-layout {
         display: grid;
         grid-template-columns: 250px 1fr;
         gap: 2rem;
         max-width: 1200px;
         margin: 0 auto;
       }

       .sidebar {
         background: #f5f5f5;
         padding: 1rem;
         border-radius: 8px;
       }
     </style>
     ```

3. **Load Functions for Data Fetching**
   - Use load functions for server-side data fetching
   - Implement client-side data loading when needed
   - Handle loading states and errors gracefully
   - Example load function patterns:
     ```typescript
     // src/routes/blog/+page.ts
     import type { PageLoad } from './$types';
     import { error } from '@sveltejs/kit';

     export const load: PageLoad = async ({ fetch, url }) => {
       try {
         const page = url.searchParams.get('page') || '1';
         const category = url.searchParams.get('category') || '';

         const response = await fetch(`/api/posts?page=${page}&category=${category}`);

         if (!response.ok) {
           throw error(response.status, 'Failed to load blog posts');
         }

         const { posts, totalPages, currentPage } = await response.json();

         return {
           posts,
           pagination: {
             currentPage: parseInt(currentPage),
             totalPages,
             hasNextPage: currentPage < totalPages,
             hasPrevPage: currentPage > 1
           }
         };
       } catch (err) {
         throw error(500, 'Failed to load blog posts');
       }
     };

     // src/routes/blog/[slug]/+page.server.ts
     import type { PageServerLoad } from './$types';
     import { error } from '@sveltejs/kit';
     import { db } from '$lib/server/database';

     export const load: PageServerLoad = async ({ params, locals }) => {
       try {
         const post = await db.posts.findBySlug(params.slug);

         if (!post) {
           throw error(404, 'Post not found');
         }

         // Only show drafts to authenticated users
         if (post.status === 'draft' && !locals.user?.isAdmin) {
           throw error(403, 'Access denied');
         }

         const relatedPosts = await db.posts.findRelated(post.id, 3);

         return {
           post,
           relatedPosts
         };
       } catch (err) {
         if (err.status) throw err;
         throw error(500, 'Failed to load post');
       }
     };
     ```

---

## State Management with Stores

4. **Svelte Stores for Global State**
   - Use writable stores for mutable state
   - Implement derived stores for computed values
   - Create custom stores for complex logic
   - Example store implementations:
     ```typescript
     // src/lib/stores/auth.ts
     import { writable, derived } from 'svelte/store';
     import type { User } from '$lib/types';

     interface AuthState {
       user: User | null;
       loading: boolean;
       error: string | null;
     }

     function createAuthStore() {
       const { subscribe, set, update } = writable<AuthState>({
         user: null,
         loading: false,
         error: null
       });

       return {
         subscribe,
         login: async (email: string, password: string) => {
           update(state => ({ ...state, loading: true, error: null }));

           try {
             const response = await fetch('/api/auth/login', {
               method: 'POST',
               headers: { 'Content-Type': 'application/json' },
               body: JSON.stringify({ email, password })
             });

             if (!response.ok) {
               throw new Error('Login failed');
             }

             const { user, token } = await response.json();

             // Store token in localStorage
             localStorage.setItem('token', token);

             update(state => ({ ...state, user, loading: false }));
           } catch (error) {
             update(state => ({
               ...state,
               loading: false,
               error: error.message
             }));
           }
         },
         logout: () => {
           localStorage.removeItem('token');
           set({ user: null, loading: false, error: null });
         },
         checkAuthStatus: async () => {
           const token = localStorage.getItem('token');
           if (!token) return;

           try {
             const response = await fetch('/api/auth/me', {
               headers: { Authorization: `Bearer ${token}` }
             });

             if (response.ok) {
               const user = await response.json();
               update(state => ({ ...state, user }));
             } else {
               localStorage.removeItem('token');
             }
           } catch (error) {
             console.error('Auth check failed:', error);
           }
         }
       };
     }

     export const authStore = createAuthStore();

     // Derived stores for computed values
     export const isAuthenticated = derived(
       authStore,
       $auth => !!$auth.user
     );

     export const isAdmin = derived(
       authStore,
       $auth => $auth.user?.role === 'admin'
     );
     ```

5. **Custom Stores for Complex State**
   - Create domain-specific stores
   - Implement store composition patterns
   - Handle async operations in stores
   - Example custom store:
     ```typescript
     // src/lib/stores/shopping-cart.ts
     import { writable, derived } from 'svelte/store';
     import type { Product, CartItem } from '$lib/types';

     function createCartStore() {
       const { subscribe, set, update } = writable<CartItem[]>([]);

       return {
         subscribe,
         addItem: (product: Product, quantity: number = 1) => {
           update(items => {
             const existingItem = items.find(item => item.product.id === product.id);

             if (existingItem) {
               return items.map(item =>
                 item.product.id === product.id
                   ? { ...item, quantity: item.quantity + quantity }
                   : item
               );
             } else {
               return [...items, { product, quantity }];
             }
           });
         },
         removeItem: (productId: string) => {
           update(items => items.filter(item => item.product.id !== productId));
         },
         updateQuantity: (productId: string, quantity: number) => {
           if (quantity <= 0) {
             cartStore.removeItem(productId);
             return;
           }

           update(items =>
             items.map(item =>
               item.product.id === productId
                 ? { ...item, quantity }
                 : item
             )
           );
         },
         clear: () => set([]),
         loadFromStorage: () => {
           if (typeof localStorage !== 'undefined') {
             const stored = localStorage.getItem('cart');
             if (stored) {
               set(JSON.parse(stored));
             }
           }
         }
       };
     }

     export const cartStore = createCartStore();

     // Derived stores for cart calculations
     export const cartTotal = derived(
       cartStore,
       $cart => $cart.reduce((total, item) =>
         total + (item.product.price * item.quantity), 0
       )
     );

     export const cartItemCount = derived(
       cartStore,
       $cart => $cart.reduce((count, item) => count + item.quantity, 0)
     );

     // Auto-save to localStorage
     cartStore.subscribe(items => {
       if (typeof localStorage !== 'undefined') {
         localStorage.setItem('cart', JSON.stringify(items));
       }
     });
     ```

6. **Store Persistence and Synchronization**
   - Persist store state across sessions
   - Sync stores with server state
   - Handle offline scenarios
   - Example persistence patterns:
     ```typescript
     // src/lib/stores/persisted.ts
     import { writable, type Writable } from 'svelte/store';
     import { browser } from '$app/environment';

     export function persisted<T>(
       key: string,
       initialValue: T,
       storage: Storage = localStorage
     ): Writable<T> {
       let storedValue = initialValue;

       if (browser) {
         const item = storage.getItem(key);
         if (item) {
           try {
             storedValue = JSON.parse(item);
           } catch (e) {
             console.warn(`Failed to parse stored value for ${key}`, e);
           }
         }
       }

       const store = writable(storedValue);

       if (browser) {
         store.subscribe(value => {
           try {
             storage.setItem(key, JSON.stringify(value));
           } catch (e) {
             console.warn(`Failed to store value for ${key}`, e);
           }
         });
       }

       return store;
     }

     // Usage
     export const userPreferences = persisted('userPreferences', {
       theme: 'light',
       language: 'en',
       notifications: true
     });
     ```

---

## Component Patterns

7. **Reactive Component Architecture**
   - Use reactive statements for computed values
   - Implement proper component lifecycle
   - Handle component communication effectively
   - Example component patterns:
     ```svelte
     <!-- src/lib/components/ProductCard.svelte -->
     <script lang="ts">
       import { createEventDispatcher } from 'svelte';
       import { cartStore } from '$lib/stores/shopping-cart';
       import type { Product } from '$lib/types';

       export let product: Product;
       export let showDetails: boolean = false;

       const dispatch = createEventDispatcher<{
         addToCart: { product: Product; quantity: number };
         viewDetails: { product: Product };
       }>();

       let quantity: number = 1;
       let imageLoaded: boolean = false;

       // Reactive statements
       $: discountedPrice = product.discount
         ? product.price * (1 - product.discount)
         : product.price;

       $: isOnSale = product.discount > 0;
       $: isInStock = product.stock > 0;

       function handleAddToCart() {
         if (isInStock) {
           cartStore.addItem(product, quantity);
           dispatch('addToCart', { product, quantity });
         }
       }

       function handleViewDetails() {
         dispatch('viewDetails', { product });
       }

       function handleImageLoad() {
         imageLoaded = true;
       }
     </script>

     <article class="product-card" class:on-sale={isOnSale}>
       <div class="image-container">
         {#if !imageLoaded}
           <div class="image-placeholder">Loading...</div>
         {/if}
         <img
           src={product.image}
           alt={product.name}
           on:load={handleImageLoad}
           class:loaded={imageLoaded}
         />
         {#if isOnSale}
           <span class="sale-badge">
             {Math.round(product.discount * 100)}% OFF
           </span>
         {/if}
       </div>

       <div class="content">
         <h3 class="title">{product.name}</h3>

         {#if showDetails}
           <p class="description">{product.description}</p>
         {/if}

         <div class="price-section">
           {#if isOnSale}
             <span class="original-price">${product.price}</span>
           {/if}
           <span class="current-price">${discountedPrice.toFixed(2)}</span>
         </div>

         <div class="actions">
           {#if isInStock}
             <div class="quantity-selector">
               <label for="quantity-{product.id}">Qty:</label>
               <input
                 id="quantity-{product.id}"
                 type="number"
                 min="1"
                 max={product.stock}
                 bind:value={quantity}
               />
             </div>
             <button class="add-to-cart" on:click={handleAddToCart}>
               Add to Cart
             </button>
           {:else}
             <button class="out-of-stock" disabled>
               Out of Stock
             </button>
           {/if}

           <button class="view-details" on:click={handleViewDetails}>
             View Details
           </button>
         </div>
       </div>
     </article>

     <style>
       .product-card {
         border: 1px solid #e2e8f0;
         border-radius: 8px;
         overflow: hidden;
         transition: transform 0.2s, box-shadow 0.2s;
       }

       .product-card:hover {
         transform: translateY(-2px);
         box-shadow: 0 8px 25px rgba(0, 0, 0, 0.1);
       }

       .image-container {
         position: relative;
         height: 200px;
       }

       .image-placeholder {
         display: flex;
         align-items: center;
         justify-content: center;
         height: 100%;
         background: #f7fafc;
         color: #a0aec0;
       }

       img {
         width: 100%;
         height: 100%;
         object-fit: cover;
         opacity: 0;
         transition: opacity 0.3s;
       }

       img.loaded {
         opacity: 1;
       }

       .sale-badge {
         position: absolute;
         top: 8px;
         right: 8px;
         background: #e53e3e;
         color: white;
         padding: 4px 8px;
         border-radius: 4px;
         font-size: 0.75rem;
         font-weight: bold;
       }

       .content {
         padding: 1rem;
       }

       .title {
         margin: 0 0 0.5rem 0;
         font-size: 1.125rem;
         font-weight: 600;
       }

       .price-section {
         margin: 0.5rem 0;
       }

       .original-price {
         text-decoration: line-through;
         color: #a0aec0;
         margin-right: 0.5rem;
       }

       .current-price {
         font-size: 1.25rem;
         font-weight: bold;
         color: #2d3748;
       }

       .actions {
         display: flex;
         flex-direction: column;
         gap: 0.5rem;
         margin-top: 1rem;
       }

       .quantity-selector {
         display: flex;
         align-items: center;
         gap: 0.5rem;
       }

       input[type="number"] {
         width: 60px;
         padding: 0.25rem;
         border: 1px solid #e2e8f0;
         border-radius: 4px;
       }

       button {
         padding: 0.5rem 1rem;
         border: none;
         border-radius: 4px;
         cursor: pointer;
         font-weight: 500;
         transition: background-color 0.2s;
       }

       .add-to-cart {
         background: #4299e1;
         color: white;
       }

       .add-to-cart:hover {
         background: #3182ce;
       }

       .view-details {
         background: #edf2f7;
         color: #2d3748;
       }

       .view-details:hover {
         background: #e2e8f0;
       }

       .out-of-stock {
         background: #fed7d7;
         color: #e53e3e;
         cursor: not-allowed;
       }
     </style>
     ```

8. **Form Handling and Validation**
   - Implement reactive form validation
   - Handle form submission with proper error handling
   - Create reusable form components
   - Example form implementation:
     ```svelte
     <!-- src/lib/components/ContactForm.svelte -->
     <script lang="ts">
       import { createEventDispatcher } from 'svelte';

       export let initialData: Partial<ContactFormData> = {};

       const dispatch = createEventDispatcher<{
         submit: ContactFormData;
         cancel: void;
       }>();

       interface ContactFormData {
         name: string;
         email: string;
         subject: string;
         message: string;
       }

       let formData: ContactFormData = {
         name: '',
         email: '',
         subject: '',
         message: '',
         ...initialData
       };

       let errors: Partial<ContactFormData> = {};
       let isSubmitting = false;
       let touched: Partial<Record<keyof ContactFormData, boolean>> = {};

       // Validation rules
       const validators = {
         name: (value: string) => {
           if (!value.trim()) return 'Name is required';
           if (value.length < 2) return 'Name must be at least 2 characters';
           return null;
         },
         email: (value: string) => {
           if (!value.trim()) return 'Email is required';
           const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
           if (!emailRegex.test(value)) return 'Please enter a valid email';
           return null;
         },
         subject: (value: string) => {
           if (!value.trim()) return 'Subject is required';
           return null;
         },
         message: (value: string) => {
           if (!value.trim()) return 'Message is required';
           if (value.length < 10) return 'Message must be at least 10 characters';
           return null;
         }
       };

       // Reactive validation
       $: {
         errors = {};
         Object.keys(validators).forEach(key => {
           const field = key as keyof ContactFormData;
           if (touched[field]) {
             const error = validators[field](formData[field]);
             if (error) errors[field] = error;
           }
         });
       }

       $: isFormValid = Object.keys(errors).length === 0 &&
                       Object.keys(touched).length > 0;

       function handleFieldBlur(field: keyof ContactFormData) {
         touched[field] = true;
         touched = { ...touched }; // Trigger reactivity
       }

       async function handleSubmit() {
         // Mark all fields as touched for validation
         Object.keys(formData).forEach(key => {
           touched[key as keyof ContactFormData] = true;
         });
         touched = { ...touched };

         if (!isFormValid) return;

         isSubmitting = true;

         try {
           // Simulate API call
           await new Promise(resolve => setTimeout(resolve, 1000));
           dispatch('submit', formData);
         } catch (error) {
           console.error('Form submission failed:', error);
         } finally {
           isSubmitting = false;
         }
       }

       function handleCancel() {
         dispatch('cancel');
       }
     </script>

     <form on:submit|preventDefault={handleSubmit} class="contact-form">
       <div class="form-group">
         <label for="name">Name *</label>
         <input
           id="name"
           type="text"
           bind:value={formData.name}
           on:blur={() => handleFieldBlur('name')}
           class:error={errors.name}
           required
         />
         {#if errors.name}
           <span class="error-message">{errors.name}</span>
         {/if}
       </div>

       <div class="form-group">
         <label for="email">Email *</label>
         <input
           id="email"
           type="email"
           bind:value={formData.email}
           on:blur={() => handleFieldBlur('email')}
           class:error={errors.email}
           required
         />
         {#if errors.email}
           <span class="error-message">{errors.email}</span>
         {/if}
       </div>

       <div class="form-group">
         <label for="subject">Subject *</label>
         <input
           id="subject"
           type="text"
           bind:value={formData.subject}
           on:blur={() => handleFieldBlur('subject')}
           class:error={errors.subject}
           required
         />
         {#if errors.subject}
           <span class="error-message">{errors.subject}</span>
         {/if}
       </div>

       <div class="form-group">
         <label for="message">Message *</label>
         <textarea
           id="message"
           bind:value={formData.message}
           on:blur={() => handleFieldBlur('message')}
           class:error={errors.message}
           rows="5"
           required
         ></textarea>
         {#if errors.message}
           <span class="error-message">{errors.message}</span>
         {/if}
       </div>

       <div class="form-actions">
         <button type="button" on:click={handleCancel} class="cancel-btn">
           Cancel
         </button>
         <button
           type="submit"
           disabled={!isFormValid || isSubmitting}
           class="submit-btn"
         >
           {#if isSubmitting}
             Sending...
           {:else}
             Send Message
           {/if}
         </button>
       </div>
     </form>

     <style>
       .contact-form {
         max-width: 500px;
         margin: 0 auto;
       }

       .form-group {
         margin-bottom: 1rem;
       }

       label {
         display: block;
         margin-bottom: 0.5rem;
         font-weight: 500;
         color: #2d3748;
       }

       input, textarea {
         width: 100%;
         padding: 0.75rem;
         border: 1px solid #e2e8f0;
         border-radius: 4px;
         font-size: 1rem;
         transition: border-color 0.2s;
       }

       input:focus, textarea:focus {
         outline: none;
         border-color: #4299e1;
         box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.1);
       }

       input.error, textarea.error {
         border-color: #e53e3e;
       }

       .error-message {
         display: block;
         margin-top: 0.25rem;
         font-size: 0.875rem;
         color: #e53e3e;
       }

       .form-actions {
         display: flex;
         justify-content: flex-end;
         gap: 1rem;
         margin-top: 2rem;
       }

       button {
         padding: 0.75rem 1.5rem;
         border: none;
         border-radius: 4px;
         font-weight: 500;
         cursor: pointer;
         transition: background-color 0.2s;
       }

       .cancel-btn {
         background: #edf2f7;
         color: #2d3748;
       }

       .cancel-btn:hover {
         background: #e2e8f0;
       }

       .submit-btn {
         background: #4299e1;
         color: white;
       }

       .submit-btn:hover:not(:disabled) {
         background: #3182ce;
       }

       .submit-btn:disabled {
         background: #a0aec0;
         cursor: not-allowed;
       }
     </style>
     ```

---

## API Routes and Server-Side Logic

9. **API Route Implementation**
   - Create RESTful API endpoints
   - Handle different HTTP methods
   - Implement proper error handling and validation
   - Example API routes:
     ```typescript
     // src/routes/api/posts/+server.ts
     import { json, error } from '@sveltejs/kit';
     import type { RequestHandler } from './$types';
     import { db } from '$lib/server/database';
     import { validatePostData } from '$lib/server/validation';

     export const GET: RequestHandler = async ({ url, locals }) => {
       try {
         const page = parseInt(url.searchParams.get('page') || '1');
         const limit = parseInt(url.searchParams.get('limit') || '10');
         const category = url.searchParams.get('category') || '';
         const search = url.searchParams.get('search') || '';

         const offset = (page - 1) * limit;

         const { posts, total } = await db.posts.findMany({
           offset,
           limit,
           category,
           search,
           publishedOnly: !locals.user?.isAdmin
         });

         return json({
           posts,
           pagination: {
             currentPage: page,
             totalPages: Math.ceil(total / limit),
             total,
             hasNextPage: page * limit < total,
             hasPrevPage: page > 1
           }
         });
       } catch (err) {
         console.error('Failed to fetch posts:', err);
         throw error(500, 'Failed to fetch posts');
       }
     };

     export const POST: RequestHandler = async ({ request, locals }) => {
       if (!locals.user) {
         throw error(401, 'Authentication required');
       }

       try {
         const postData = await request.json();

         const validationResult = validatePostData(postData);
         if (!validationResult.isValid) {
           throw error(400, {
             message: 'Validation failed',
             errors: validationResult.errors
           });
         }

         const post = await db.posts.create({
           ...postData,
           authorId: locals.user.id,
           createdAt: new Date(),
           updatedAt: new Date()
         });

         return json(post, { status: 201 });
       } catch (err) {
         if (err.status) throw err;
         console.error('Failed to create post:', err);
         throw error(500, 'Failed to create post');
       }
     };

     // src/routes/api/posts/[id]/+server.ts
     import { json, error } from '@sveltejs/kit';
     import type { RequestHandler } from './$types';
     import { db } from '$lib/server/database';

     export const GET: RequestHandler = async ({ params, locals }) => {
       try {
         const post = await db.posts.findById(params.id);

         if (!post) {
           throw error(404, 'Post not found');
         }

         // Check access permissions
         if (post.status === 'draft' && post.authorId !== locals.user?.id && !locals.user?.isAdmin) {
           throw error(403, 'Access denied');
         }

         return json(post);
       } catch (err) {
         if (err.status) throw err;
         throw error(500, 'Failed to fetch post');
       }
     };

     export const PUT: RequestHandler = async ({ params, request, locals }) => {
       if (!locals.user) {
         throw error(401, 'Authentication required');
       }

       try {
         const post = await db.posts.findById(params.id);

         if (!post) {
           throw error(404, 'Post not found');
         }

         if (post.authorId !== locals.user.id && !locals.user.isAdmin) {
           throw error(403, 'Access denied');
         }

         const updateData = await request.json();
         const validationResult = validatePostData(updateData);

         if (!validationResult.isValid) {
           throw error(400, {
             message: 'Validation failed',
             errors: validationResult.errors
           });
         }

         const updatedPost = await db.posts.update(params.id, {
           ...updateData,
           updatedAt: new Date()
         });

         return json(updatedPost);
       } catch (err) {
         if (err.status) throw err;
         throw error(500, 'Failed to update post');
       }
     };

     export const DELETE: RequestHandler = async ({ params, locals }) => {
       if (!locals.user) {
         throw error(401, 'Authentication required');
       }

       try {
         const post = await db.posts.findById(params.id);

         if (!post) {
           throw error(404, 'Post not found');
         }

         if (post.authorId !== locals.user.id && !locals.user.isAdmin) {
           throw error(403, 'Access denied');
         }

         await db.posts.delete(params.id);

         return new Response(null, { status: 204 });
       } catch (err) {
         if (err.status) throw err;
         throw error(500, 'Failed to delete post');
       }
     };
     ```

10. **Authentication and Authorization Hooks**
    - Implement server-side authentication
    - Create authorization middleware
    - Handle session management
    - Example authentication setup:
      ```typescript
      // src/hooks.server.ts
      import type { Handle } from '@sveltejs/kit';
      import jwt from 'jsonwebtoken';
      import { JWT_SECRET } from '$env/static/private';
      import { db } from '$lib/server/database';

      export const handle: Handle = async ({ event, resolve }) => {
        // Get token from Authorization header or cookies
        const token = event.request.headers.get('authorization')?.replace('Bearer ', '') ||
                     event.cookies.get('auth-token');

        if (token) {
          try {
            const payload = jwt.verify(token, JWT_SECRET) as { userId: string };
            const user = await db.users.findById(payload.userId);

            if (user) {
              event.locals.user = user;
            }
          } catch (err) {
            // Invalid token - clear it
            event.cookies.delete('auth-token', { path: '/' });
          }
        }

        // Apply CORS headers
        if (event.request.method === 'OPTIONS') {
          return new Response(null, {
            status: 200,
            headers: {
              'Access-Control-Allow-Origin': '*',
              'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
              'Access-Control-Allow-Headers': 'Content-Type, Authorization'
            }
          });
        }

        const response = await resolve(event);

        // Add security headers
        response.headers.set('X-Frame-Options', 'DENY');
        response.headers.set('X-Content-Type-Options', 'nosniff');
        response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');

        return response;
      };

      // src/routes/api/auth/login/+server.ts
      import { json, error } from '@sveltejs/kit';
      import type { RequestHandler } from './$types';
      import bcrypt from 'bcryptjs';
      import jwt from 'jsonwebtoken';
      import { JWT_SECRET } from '$env/static/private';
      import { db } from '$lib/server/database';

      export const POST: RequestHandler = async ({ request, cookies }) => {
        try {
          const { email, password } = await request.json();

          if (!email || !password) {
            throw error(400, 'Email and password are required');
          }

          const user = await db.users.findByEmail(email);
          if (!user) {
            throw error(401, 'Invalid credentials');
          }

          const isValidPassword = await bcrypt.compare(password, user.passwordHash);
          if (!isValidPassword) {
            throw error(401, 'Invalid credentials');
          }

          const token = jwt.sign(
            { userId: user.id },
            JWT_SECRET,
            { expiresIn: '7d' }
          );

          // Set HTTP-only cookie
          cookies.set('auth-token', token, {
            path: '/',
            httpOnly: true,
            secure: true,
            sameSite: 'strict',
            maxAge: 60 * 60 * 24 * 7 // 7 days
          });

          // Return user data (without password)
          const { passwordHash, ...userWithoutPassword } = user;

          return json({
            user: userWithoutPassword,
            token
          });
        } catch (err) {
          if (err.status) throw err;
          throw error(500, 'Login failed');
        }
      };
      ```

---

## Testing Strategies

11. **Component and Integration Testing**
    - Test Svelte components with proper mocking
    - Write integration tests for user flows
    - Test stores and reactive behavior
    - Example testing setup:
      ```typescript
      // src/lib/components/ProductCard.test.ts
      import { render, fireEvent, screen } from '@testing-library/svelte';
      import { expect, test, vi } from 'vitest';
      import ProductCard from './ProductCard.svelte';
      import type { Product } from '$lib/types';

      const mockProduct: Product = {
        id: '1',
        name: 'Test Product',
        description: 'A test product',
        price: 29.99,
        image: '/test-image.jpg',
        stock: 10,
        discount: 0.1
      };

      test('renders product information correctly', () => {
        render(ProductCard, { product: mockProduct });

        expect(screen.getByText('Test Product')).toBeInTheDocument();
        expect(screen.getByText('$26.99')).toBeInTheDocument(); // Discounted price
        expect(screen.getByText('10% OFF')).toBeInTheDocument();
      });

      test('dispatches addToCart event when add to cart is clicked', async () => {
        const { component } = render(ProductCard, { product: mockProduct });

        const addToCartHandler = vi.fn();
        component.$on('addToCart', addToCartHandler);

        const addButton = screen.getByText('Add to Cart');
        await fireEvent.click(addButton);

        expect(addToCartHandler).toHaveBeenCalledWith(
          expect.objectContaining({
            detail: { product: mockProduct, quantity: 1 }
          })
        );
      });

      test('shows out of stock when product stock is 0', () => {
        const outOfStockProduct = { ...mockProduct, stock: 0 };
        render(ProductCard, { product: outOfStockProduct });

        expect(screen.getByText('Out of Stock')).toBeInTheDocument();
        expect(screen.queryByText('Add to Cart')).not.toBeInTheDocument();
      });

      // Store testing
      // src/lib/stores/cart.test.ts
      import { get } from 'svelte/store';
      import { expect, test, beforeEach } from 'vitest';
      import { cartStore, cartTotal, cartItemCount } from './shopping-cart';

      beforeEach(() => {
        cartStore.clear();
      });

      test('adds item to cart', () => {
        const product = { id: '1', name: 'Test', price: 10 };

        cartStore.addItem(product, 2);

        const cartItems = get(cartStore);
        expect(cartItems).toHaveLength(1);
        expect(cartItems[0].product.id).toBe('1');
        expect(cartItems[0].quantity).toBe(2);
      });

      test('calculates cart total correctly', () => {
        const product1 = { id: '1', name: 'Product 1', price: 10 };
        const product2 = { id: '2', name: 'Product 2', price: 20 };

        cartStore.addItem(product1, 2);
        cartStore.addItem(product2, 1);

        expect(get(cartTotal)).toBe(40); // (10 * 2) + (20 * 1)
        expect(get(cartItemCount)).toBe(3); // 2 + 1
      });

      // API testing
      // src/routes/api/posts/posts.test.ts
      import { expect, test, vi } from 'vitest';
      import type { RequestEvent } from '@sveltejs/kit';
      import { GET, POST } from './+server';

      // Mock database
      vi.mock('$lib/server/database', () => ({
        db: {
          posts: {
            findMany: vi.fn(),
            create: vi.fn()
          }
        }
      }));

      test('GET returns paginated posts', async () => {
        const mockPosts = [
          { id: '1', title: 'Post 1' },
          { id: '2', title: 'Post 2' }
        ];

        const mockRequest = new Request('http://localhost/api/posts?page=1&limit=10');
        const mockEvent = {
          url: new URL(mockRequest.url),
          locals: { user: null }
        } as unknown as RequestEvent;

        const { db } = await import('$lib/server/database');
        vi.mocked(db.posts.findMany).mockResolvedValue({
          posts: mockPosts,
          total: 2
        });

        const response = await GET(mockEvent);
        const data = await response.json();

        expect(data.posts).toEqual(mockPosts);
        expect(data.pagination.currentPage).toBe(1);
        expect(data.pagination.total).toBe(2);
      });
      ```

---

## Summary Checklist

- [ ] Use file-based routing for automatic route generation
- [ ] Implement load functions for server-side data fetching
- [ ] Create reactive stores for global state management
- [ ] Use derived stores for computed values
- [ ] Build reusable components with proper event handling
- [ ] Implement form validation with reactive statements
- [ ] Create RESTful API routes with proper error handling
- [ ] Set up authentication and authorization hooks
- [ ] Use proper TypeScript types throughout the application
- [ ] Implement lazy loading and code splitting
- [ ] Write comprehensive tests for components and stores
- [ ] Handle loading states and errors gracefully
- [ ] Use SSR and prerendering for performance
- [ ] Implement proper SEO and meta tag management

---

Follow these practices to build fast, scalable, and maintainable full-stack web applications with SvelteKit.
SvelteKit Full-Stack Framework - Cursor IDE AI Rule