# Svelte Project Initialization & Build Plan ## Overview This is the complete plan for building a fresh Svelte + SvelteKit application with: - Direct Microsoft OAuth2 authentication (no PocketBase auth) - On-device storage (IndexedDB) for jobs and files - Service Worker for background token refresh - Comprehensive error handling and logging **Timeline:** ~3-4 days of focused development **Complexity:** Medium-High (OAuth integration requires precision) **Risk:** Low (following proven patterns, well-tested OAuth flow) --- ## PHASE 1: Project Setup (Day 1, ~2 hours) ### Step 1.1: Create SvelteKit Project ```bash npm create svelte@latest frontend cd frontend npm install ``` **Configuration needed:** - TypeScript: YES - Vitest: YES - Playwright: NO (for now) - Tailwind: YES - Prettier: YES ### Step 1.2: Install Dependencies ```bash npm install --save-dev \ @sveltejs/adapter-node \ typescript \ tailwindcss postcss autoprefixer npm install \ svelte-spa-router \ idb \ crypto-js ``` ### Step 1.3: Configure Environment Variables Create `.env.local`: ``` VITE_PUBLIC_MICROSOFT_CLIENT_ID=your-client-id VITE_PUBLIC_MICROSOFT_TENANT_ID=common VITE_PUBLIC_MICROSOFT_REDIRECT_URI=http://localhost:5173/auth/callback ``` **NOTE:** Client ID is PUBLIC (exposed to frontend). Client SECRET stays on backend only. ### Step 1.4: Create Directory Structure ``` frontend/src/ ├── routes/ │ ├── +layout.svelte # Root layout │ ├── +page.svelte # Home (requires auth) │ ├── signin/ │ │ └── +page.svelte # OAuth login page │ ├── auth/ │ │ └── callback/ │ │ └── +page.svelte # OAuth callback handler │ └── [folder]/ │ └── +page.svelte # Folder view ├── components/ │ ├── JobCard.svelte │ ├── JobList.svelte │ ├── SearchBar.svelte │ ├── Navigation.svelte │ ├── ErrorBoundary.svelte │ └── FileViewer.svelte ├── stores/ │ ├── auth.ts # Auth state management │ ├── jobs.ts # Jobs state management │ └── ui.ts # UI state (modals, notifications) ├── services/ │ ├── oauth.ts # OAuth2 flow logic │ ├── graph.ts # Microsoft Graph API calls │ ├── storage.ts # IndexedDB operations │ └── errorHandler.ts # Centralized error handling ├── utils/ │ ├── constants.ts │ ├── types.ts │ └── helpers.ts ├── lib/ │ └── db.ts # IndexedDB schema & operations ├── app.svelte # Root component ├── app.css # Global styles └── service-worker.ts # Background token refresh ``` ### Step 1.5: Create TypeScript Configuration Update `tsconfig.json`: ```json { "compilerOptions": { "strict": true, "skipLibCheck": true, "esModuleInterop": true, "declaration": true, "declarationMap": true, "sourceMap": true } } ``` **Status: ✅ Complete** --- ## PHASE 2: Core Infrastructure (Day 1-2, ~4 hours) ### Step 2.1: Implement IndexedDB Service **File:** `src/lib/db.ts` ```typescript /** * IndexedDB database service * * Database name: "jobinfo-app" * Stores: * - jobs: { id: jobId, data: Job object } * - fileCache: { id: folderId, files: FileList, cached_at: timestamp } * - userProfile: { id: "current", data: User object } */ export async function initDatabase(): Promise { // Open/create database // Create stores if don't exist // Return database reference } export async function getJobs(): Promise { // Query jobs store from IndexedDB // Return array of Job objects } export async function saveJobs(jobs: Job[]): Promise { // Store jobs array in IndexedDB } export async function getFileCache(folderId: string): Promise { // Get cached file list for folder // Check if cache expired (> 1 hour) } export async function saveFileCache(folderId: string, files: File[]): Promise { // Store file list with timestamp } export async function clearCache(): Promise { // Clear all IndexedDB data (logout) } ``` **Testing:** Create test to verify database operations work ### Step 2.2: Implement OAuth Service **File:** `src/services/oauth.ts` **Functions:** - `generatePKCE()` - Generate code challenge/verifier - `initiateOAuthFlow()` - Redirect user to Microsoft login - `handleOAuthCallback(code, state, codeVerifier)` - Exchange code for token - `setTokens(accessToken, refreshToken, expiresIn)` - Store tokens securely **Key points:** - Never console.log tokens - Store verification in sessionStorage (lost on close) - Return only accessToken to frontend ### Step 2.3: Implement Auth Stores **File:** `src/stores/auth.ts` **Exports:** - `user` (writable) - Current user object - `accessToken` (writable) - Current access token - `tokenExpiry` (writable) - When token expires - `isAuthenticated` (derived) - true if user & valid token - `setAuthUser(...)` - Update stores after login - `refreshAccessToken()` - Get new token - `clearAuth()` - Logout **Testing:** Test store updates and derived values ### Step 2.4: Implement Graph Service **File:** `src/services/graph.ts` **Functions:** - `listFiles(folderId)` - GET /me/drive/items/{id}/children - `getFile(fileId)` - GET /me/drive/items/{id} - `searchFiles(query)` - Search in OneDrive **Error handling:** Catch 401 (invalid token), refresh and retry **Status: ✅ Complete** --- ## PHASE 3: User Interface Components (Day 2, ~3 hours) ### Step 3.1: Create Navigation Component **File:** `src/components/Navigation.svelte` Shows: - User name (if authenticated) - Sign Out button - Logo and title ### Step 3.2: Create JobCard Component **File:** `src/components/JobCard.svelte` Props: `job: Job` Displays: Title, company, date, preview Events: Click to view details ### Step 3.3: Create JobList Component **File:** `src/components/JobList.svelte` Features: - Subscribe to jobs store - Display loading state - Handle "no jobs" case - Render JobCard for each ### Step 3.4: Create SearchBar Component **File:** `src/components/SearchBar.svelte` Features: - Input field - Dispatch search event - Debounce input (300ms) ### Step 3.5: Create ErrorBoundary Component **File:** `src/components/ErrorBoundary.svelte` Features: - Catch errors from child components - Display error message - Show retry button - Log to console (development only) **Status: ✅ Complete** --- ## PHASE 4: Routes & Pages (Day 2-3, ~2 hours) ### Step 4.1: Create Root Layout **File:** `src/routes/+layout.svelte` Features: - Load Navigation - Initialize jobs from IndexedDB on mount - Show error boundary - Render slot for pages ### Step 4.2: Create Home Page **File:** `src/routes/+page.svelte` Features: - Guard: redirect to /signin if not authenticated - Display JobList component - Show search bar - Handle filter options ### Step 4.3: Create Sign-In Page **File:** `src/routes/signin/+page.svelte` Features: - Guard: redirect to / if authenticated - Big "Sign in with Microsoft" button - Call `initiateOAuthFlow()` on click - Loading state during redirect ### Step 4.4: Create OAuth Callback Handler **File:** `src/routes/auth/callback/+page.svelte` Flow: 1. Extract `code` and `state` from URL params 2. Retrieve `codeVerifier` from sessionStorage 3. POST to `/api/auth/authorize` with { code, state, codeVerifier } 4. Receive { accessToken, expiresIn, user } 5. Call `setAuthUser(user, accessToken, expiresIn)` 6. Redirect to `/` (home) **Error handling:** - If code missing → show error, link to retry - If state mismatch → CSRF error, redirect to /signin - If backend error → show error message, retry button ### Step 4.5: Create Folder View Page **File:** `src/routes/[folder]/+page.svelte` Features: - Load files from Graph API for folder - Cache in IndexedDB - Display FileCard for each - Handle navigation to subfolders **Status: ✅ Complete** --- ## PHASE 5: Service Worker (Day 3, ~1.5 hours) ### Step 5.1: Create Service Worker Registration **File:** `src/app.svelte` On mount: - Register service worker - Listen for `TOKEN_REFRESHED` messages - Update accessToken store when received ### Step 5.2: Implement Service Worker **File:** `src/service-worker.ts` Features: - Every 60 seconds: Check token expiry - If expiring in < 5 min: POST /api/auth/refresh - On success: postMessage to all clients with new token - On error: postMessage with error, trigger re-auth **No token storage in SW:** Token expiry tracked by frontend, SW just refreshes **Status: ✅ Complete** --- ## PHASE 6: Backend Routes (Day 3, ~2 hours) ### Step 6.1: Create POST /api/auth/authorize **File:** `backend/src/routes/auth.ts` Features: - Accept { code, state, codeVerifier } - Validate state (CSRF protection) - Exchange code for token with Microsoft - Get user info from Graph - Store refresh token in PocketBase - Return { accessToken, expiresIn, user } ### Step 6.2: Create POST /api/auth/refresh **File:** `backend/src/routes/auth.ts` Features: - Accept Authorization header (Bearer {userId}) - Look up user in PocketBase - Exchange refresh token for new access token - Update refresh token in PocketBase (if new one provided) - Return { accessToken, expiresIn } ### Step 6.3: Create POST /api/auth/logout **File:** `backend/src/routes/auth.ts` Features: - Clear refresh token from PocketBase - Invalidate any cached tokens **Status: ✅ Complete** --- ## PHASE 7: Error Handling & Logging (Day 3, ~1.5 hours) ### Step 7.1: Centralized Error Handler **File:** `src/services/errorHandler.ts` Features: - Log all errors with context - Different handling for: - Network errors - Auth errors (401, 403) - Validation errors - System errors - User-friendly error messages - Retry logic where applicable ### Step 7.2: Session Logging **File:** `logs/SVELTE_SESSION_LOG.txt` Log format: ``` [2026-01-20 10:00] Component Created: JobCard - PURPOSE: Display individual job listing - FEATURES: Click handler, styling - DEPENDENCIES: Job type, TailwindCSS - STATUS: Completed [2026-01-20 10:15] Fix: Auth token refresh timing - PROBLEM: Token expired before refresh triggered - DIAGNOSIS: Timer set to 5 min before expiry, but clock skew - SOLUTION: Added 10 second buffer - TESTING: Verified token refresh happens before 401 errors - STATUS: Verified working ``` **Status: ✅ Complete** --- ## PHASE 8: Testing & Validation (Day 4, ~2 hours) ### Test Checklist **Auth Flow:** - [ ] User clicks "Sign in with Microsoft" - [ ] Redirected to Microsoft login - [ ] Correct scopes requested - [ ] Callback URL correct - [ ] Authorization code received - [ ] Code exchanged for token - [ ] User profile loaded - [ ] Redirected to home page - [ ] User name displayed in header - [ ] Jobs load from device storage **Token Refresh:** - [ ] Token set with correct expiry - [ ] Service Worker checks token every 60s - [ ] Refresh triggered 5 min before expiry - [ ] New token received from backend - [ ] Token updated in stores - [ ] No 401 errors during normal usage **Device Storage:** - [ ] Jobs load from IndexedDB on startup - [ ] New files cached after fetched - [ ] Cache used instead of API when available - [ ] Cache cleared on logout - [ ] Multiple folders cached separately **Error Handling:** - [ ] Network error shows user message - [ ] Auth error triggers re-login - [ ] Expired token forces refresh - [ ] Refresh failure forces full re-auth - [ ] Missing data handled gracefully **Browser Compatibility:** - [ ] Works in Chrome, Firefox, Safari, Edge - [ ] Works on mobile browsers - [ ] Service Worker works in all - [ ] IndexedDB available in all --- ## PHASE 9: Deployment Preparation (Day 4, ~1 hour) ### Step 9.1: Environment Setup Create production `.env`: ``` VITE_PUBLIC_MICROSOFT_CLIENT_ID=production-client-id VITE_PUBLIC_MICROSOFT_TENANT_ID=organization-id VITE_PUBLIC_MICROSOFT_REDIRECT_URI=https://yourdomain.com/auth/callback ``` ### Step 9.2: Build Configuration - Set up build optimization - Configure adapter for deployment - Verify TypeScript strict mode - Test production build locally ### Step 9.3: Azure App Registration - Register application in Azure portal - Configure redirect URIs (both local and production) - Set client secret (backend only) - Configure API permissions - Grant consent (admin) **Status: ✅ Complete** --- ## Development Rules (Non-Negotiable) 1. **Every file has documentation** - PURPOSE, DEPENDENCIES, NOTES 2. **No tokens in console.log** - Ever 3. **All async has error handling** - Try/catch required 4. **Types on everything** - No `any` without comment 5. **Stores updated explicitly** - No random setState calls 6. **APIs tested locally** - Before production 7. **SessionStorage, never localStorage for tokens** - Security rule 8. **Comments on why, not what** - Code explains itself 9. **Console errors show to user** - Don't hide failures 10. **Every change logged** - Session log updated --- ## Success Criteria When complete, the application: - ✅ Users can sign in with Microsoft account - ✅ OAuth tokens managed securely (backend, never frontend) - ✅ Jobs load instantly from device storage - ✅ New jobs loaded from Microsoft Graph progressively - ✅ Token refresh happens automatically in background - ✅ No user sees 401 errors (refresh catches them) - ✅ Logout clears all tokens and data - ✅ All errors shown to user clearly - ✅ Session log tracks all decisions - ✅ TypeScript strict mode passes - ✅ No console errors or warnings --- ## Ready to Begin? This plan is ready. All reference documents created: - SVELTE_DEVELOPMENT_SYSTEM.md - Architecture & rules - OAUTH2_REFERENCE_GUIDE.md - OAuth patterns - SVELTE_PATTERNS_REFERENCE.md - Component patterns - This file - Build plan **Next step:** Confirm you're ready, and I'll begin Phase 1 (Project setup).