14 KiB
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
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
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:
{
"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
/**
* 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<IDBDatabase> {
// Open/create database
// Create stores if don't exist
// Return database reference
}
export async function getJobs(): Promise<Job[]> {
// Query jobs store from IndexedDB
// Return array of Job objects
}
export async function saveJobs(jobs: Job[]): Promise<void> {
// Store jobs array in IndexedDB
}
export async function getFileCache(folderId: string): Promise<File[] | null> {
// Get cached file list for folder
// Check if cache expired (> 1 hour)
}
export async function saveFileCache(folderId: string, files: File[]): Promise<void> {
// Store file list with timestamp
}
export async function clearCache(): Promise<void> {
// 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/verifierinitiateOAuthFlow()- Redirect user to Microsoft loginhandleOAuthCallback(code, state, codeVerifier)- Exchange code for tokensetTokens(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 objectaccessToken(writable) - Current access tokentokenExpiry(writable) - When token expiresisAuthenticated(derived) - true if user & valid tokensetAuthUser(...)- Update stores after loginrefreshAccessToken()- Get new tokenclearAuth()- 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}/childrengetFile(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:
- Extract
codeandstatefrom URL params - Retrieve
codeVerifierfrom sessionStorage - POST to
/api/auth/authorizewith { code, state, codeVerifier } - Receive { accessToken, expiresIn, user }
- Call
setAuthUser(user, accessToken, expiresIn) - 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_REFRESHEDmessages - 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)
- Every file has documentation - PURPOSE, DEPENDENCIES, NOTES
- No tokens in console.log - Ever
- All async has error handling - Try/catch required
- Types on everything - No
anywithout comment - Stores updated explicitly - No random setState calls
- APIs tested locally - Before production
- SessionStorage, never localStorage for tokens - Security rule
- Comments on why, not what - Code explains itself
- Console errors show to user - Don't hide failures
- 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).