# Svelte + Microsoft OAuth Development System **Comprehensive Methodology, Standards, and Reference Tools** --- ## PHASE 1: RESEARCH & ARCHITECTURE (IN PROGRESS) ### 1. Technology Stack (Monica-Enforced Standards) **Frontend Runtime:** Svelte (with SvelteKit for routing/build) **Backend:** Bun + Hono (unchanged - proven working) **Build Tool:** Vite (integrated with SvelteKit) **Language:** TypeScript (both frontend and backend) **Styling:** TailwindCSS + PostCSS **Storage:** IndexedDB (device storage), PocketBase (token persistence) **Auth:** Microsoft OAuth2 directly + Service Worker credential management --- ## PART A: MICROSOFT OAUTH2 ARCHITECTURE ### A1. Overall Flow ``` User clicks "Sign In" → Service Worker intercepts Microsoft OAuth redirect URL → Service Worker extracts auth code → Backend (Hono) exchanges code for tokens using Service Worker credentials → Backend stores refresh token in PocketBase under user collection → Backend returns access token to frontend → Frontend stores short-lived access token in memory/sessionStorage → Service Worker manages token refresh on expiration ``` ### A2. Why This Approach - **Direct OAuth with Microsoft:** No PocketBase auth, eliminates middle-layer complexity - **Service Worker credentials:** Never expose client secret to frontend, server handles all token exchanges - **PocketBase for token storage:** Persistent, synced, secure backend storage of refresh tokens - **Device storage (IndexedDB):** User data (jobs, cache) stored locally without external service - **Token refresh automation:** Service Worker checks token expiry and refreshes proactively ### A3. Key Endpoints Needed ``` POST /api/auth/authorize - Accepts: { code, state } - Returns: { accessToken, expiresIn, user } - Action: Exchanges OAuth code for tokens via service worker credentials POST /api/auth/refresh - Accepts: { } - Returns: { accessToken, expiresIn } - Action: Uses stored refresh token to get new access token GET /api/auth/status - Returns: { isAuthenticated, user, tokenExpiry } POST /api/auth/logout - Clears refresh token from PocketBase ``` ### A4. Microsoft Graph API Integration - Endpoint: `https://graph.microsoft.com/v1.0/me/drive/root/children` - Token required: accessToken in Authorization header - Caching strategy: IndexedDB + device storage for file listings - Refresh strategy: Access token → 1 hour expiry, Service Worker refreshes automatically --- ## PART B: SVELTE ARCHITECTURE ### B1. Project Structure ``` frontend/ src/ routes/ +page.svelte (home/jobs list) signin/ +page.svelte (Microsoft OAuth login) folder/ [id]/ +page.svelte (folder view) components/ JobCard.svelte FileListItem.svelte SearchBar.svelte stores/ auth.ts (writable stores for user, tokens) jobs.ts (derived store for job data) files.ts (derived store for file listings) services/ oauth.ts (OAuth2 flow handler) graph.ts (Microsoft Graph API calls) storage.ts (IndexedDB operations) utils/ constants.ts app.svelte (layout wrapper) svelte.config.js vite.config.ts tailwind.config.ts ``` ### B2. Svelte Stores Strategy ```typescript // auth.ts - Global auth state export const user = writable(null); export const accessToken = writable(null); export const isAuthenticated = derived([user], ([$user]) => !!$user); // jobs.ts - Derived from IndexedDB cache export const jobs = writable([]); export const jobsLoading = writable(false); // files.ts - Derived from Microsoft Graph export const files = writable([]); export const filesLoading = writable(false); ``` ### B3. Service Worker Role ``` Purpose: Token refresh automation + OAuth redirect interception Tasks: - Listens for token expiry (via postMessage from frontend) - Automatically calls POST /api/auth/refresh before expiry - Updates accessToken in frontend via postMessage - Handles Microsoft OAuth redirect URL capture (if needed) - Persists tokens in sessionStorage (never exposed to main thread) ``` --- ## PART C: DEVICE STORAGE STRATEGY (IndexedDB) ### C1. Database Schema ```javascript // Database: "jobinfo-app" // Stores: // 1. jobs // Key: jobId (string) // Value: { id, title, company, postedDate, ... } // Index: "company", "postedDate" // 2. fileCache // Key: folderId (string) // Value: { folderId, files: [...], lastRefreshed: timestamp } // Index: "lastRefreshed" // 3. userCache // Key: "current" // Value: { user object from Microsoft } // 4. tokenMetadata (not storing tokens, just metadata) // Key: "current" // Value: { expiresAt: timestamp, refreshedAt: timestamp } ``` ### C2. IndexedDB Helper Functions ```typescript // storage.ts export async function saveJobs(jobs: Job[]): Promise export async function getJobs(): Promise export async function saveFileCache(folderId: string, files: MicrosoftFile[]): Promise export async function getFileCache(folderId: string): Promise export async function clearExpiredCache(): Promise ``` --- ## PART D: BACKEND (HONO) UPDATES ### D1. New Routes ```typescript // backend/auth-routes.ts app.post('/auth/authorize', async (c) => { // 1. Validate request { code, state } // 2. Exchange code for tokens using Microsoft OAuth credentials // 3. Store refresh token in PocketBase // 4. Return accessToken to frontend }) app.post('/auth/refresh', async (c) => { // 1. Get user from auth header // 2. Retrieve refresh token from PocketBase // 3. Exchange for new access token // 4. Return new access token }) app.get('/auth/status', async (c) => { // Return current auth status }) ``` ### D2. Environment Variables Required ``` MICROSOFT_CLIENT_ID= MICROSOFT_CLIENT_SECRET= MICROSOFT_TENANT_ID= MICROSOFT_REDIRECT_URI=http://localhost:5173/auth/callback POCKETBASE_URL=https://pocketbase.ccllc.pro POCKETBASE_ADMIN_EMAIL= POCKETBASE_ADMIN_PASSWORD= ``` --- ## PART E: DEVELOPMENT RULES (NON-NEGOTIABLE) ### RULE E1: Code Documentation Standard Every file, every function, every store must have: ```typescript /** * MODULE: [Name] * PURPOSE: [What it does] * DEPENDENCIES: [External services, stores, APIs] * PERSISTENCE: [How/where data is stored] * NOTES: [Any gotchas, edge cases, security considerations] */ ``` ### RULE E2: Component Structure Every Svelte component must have: ```svelte ``` ### RULE E3: Store Pattern Every Svelte store follows this pattern: ```typescript /** * STORE: storeName * PURPOSE: [What data it holds] * UPDATES: [How and when it's updated] * SUBSCRIPTIONS: [Components that use it] */ export const storeName = writable(initialValue); // Every update must be wrapped in a clearly named function: export async function updateStoreName(newValue: Type): Promise { // Detailed comment explaining the update storeName.set(newValue); } ``` ### RULE E4: API Call Pattern Every API call to backend must follow: ```typescript /** * API: /endpoint * METHOD: GET/POST/etc * HEADERS REQUIRED: [Auth, Content-Type, etc] * REQUEST BODY: { ... with detailed types } * RESPONSE: { ... with detailed types } * ERRORS: [What can go wrong and how we handle it] * RETRY STRATEGY: [Is this retried? When?] */ export async function apiCallName(params: Type): Promise { const token = get(accessToken); if (!token) throw new Error('Not authenticated'); try { const response = await fetch(`/api/endpoint`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, }, body: JSON.stringify(params), }); if (!response.ok) throw new Error(`API error: ${response.status}`); return response.json(); } catch (error) { console.error('API call failed:', error); throw error; } } ``` ### RULE E5: Error Handling Standard No silent failures. Every promise, every fetch, every async operation: ```typescript try { // Operation } catch (error) { // 1. Log error with context console.error('Context: what were we trying to do', error); // 2. Determine if recoverable if (isRecoverable(error)) { // Attempt recovery } else { // Notify user or escalate } } ``` ### RULE E6: Token Handling - **Never store tokens in localStorage** (vulnerable to XSS) - **Access token:** In memory only (lost on refresh, that's intentional) - **Refresh token:** Only on backend in PocketBase - **Service Worker:** Can read from sessionStorage only, never localStorage - **Token expiry check:** Frontend checks before each API call, Service Worker proactively refreshes ### RULE E7: Code Quality Standards - Every TypeScript file has strict: true in tsconfig - No `any` types without explicit comment explaining why - No console.log in production code (use proper logging) - All async operations have error handling - All state changes are intentional and logged in stores - No magic numbers or strings (use CONST_DEFINED_AT_TOP) --- ## PART F: DEVELOPMENT CHECKLIST ### Pre-Build Checklist - [ ] All imports are TypeScript (.ts, not .js) - [ ] All stores have update functions with documentation - [ ] All API calls have error handling - [ ] All tokens are handled per RULE E6 - [ ] All components follow component structure in RULE E2 - [ ] No hardcoded URLs (use constants) - [ ] No console.log statements - [ ] All environment variables are documented ### Testing Checklist - [ ] Login flow works (OAuth → token storage → API calls) - [ ] Token refresh works (Service Worker updates token) - [ ] File listing loads from Microsoft Graph - [ ] File listing cached in IndexedDB - [ ] Search/filter works from cached files - [ ] Logout clears tokens and cache - [ ] Offline mode works (uses cached data) --- ## PART G: SESSION LOG LOCATION All work logged to: `/home/admin/Job-Info-Test/logs/SVELTE_SESSION_LOG.txt` Format: ``` [2026-01-19 10:00] Component/Store Created: ComponentName - PURPOSE: [What it does] - IMPLEMENTATION: [Key decisions] - DEPENDENCIES: [What it depends on] - STATUS: Completed / In Progress / Blocked [2026-01-19 10:15] Fix: [Issue resolved] - PROBLEM: [What was broken] - DIAGNOSIS: [How we found the issue] - SOLUTION: [What we changed] - TESTING: [How we verified it works] - STATUS: Verified working ``` --- ## NEXT STEPS 1. ✅ Create this document (DONE) 2. ⏳ Research Svelte + SvelteKit best practices 3. ⏳ Research Microsoft OAuth2 + Service Worker patterns 4. ⏳ Create backend OAuth routes 5. ⏳ Create Svelte project structure 6. ⏳ Create auth store and OAuth service 7. ⏳ Create IndexedDB service 8. ⏳ Create Microsoft Graph service 9. ⏳ Build UI components 10. ⏳ Integrate and test end-to-end --- **Status: FOUNDATION DOCUMENT CREATED - Ready for Research Phase**