Files
Job-Info/SVELTE_BUILD_PLAN.md
T
aewing 42ff3e8f33
Build & Deploy / Test & Lint (push) Has been cancelled
Build & Deploy / Security Scan (push) Has been cancelled
Code Quality / Code Quality Checks (push) Has been cancelled
Code Quality / Dependency Vulnerabilities (push) Has been cancelled
Code Quality / Performance Testing (push) Has been cancelled
Build & Deploy / Build Docker Images (push) Has been cancelled
Build & Deploy / Deploy to Kubernetes (push) Has been cancelled
Add Mode6Test: copy of Mode5Test running on port 3000
2026-01-20 13:43:29 +00:00

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/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).