fix(ssr): resolve EventSource SSR violations and implement best practices
- Fix EventSource is not defined error in queue dashboard - Add browser guards for all EventSource usage - Replace static constants (EventSource.OPEN/CLOSED) with numeric values - Fix setInterval SSR violation in LLM health indicator - Replace $effect anti-pattern with onMount in share page - Add comprehensive SvelteKit SSR best practices documentation - Add SSR audit and testing verification All changes follow SvelteKit best practices and are verified against official documentation. Production build succeeds with no SSR errors. Closes: FixEventSourceSSR See: docs/outcomes/FixEventSourceSSR.md
This commit is contained in:
802
docs/plans/FixPushNotificationSSRAndSSL.md
Normal file
802
docs/plans/FixPushNotificationSSRAndSSL.md
Normal file
@@ -0,0 +1,802 @@
|
||||
# Execution Plan: Fix Push Notification SSR Bug, Regenerate SSL, and Code Cleanup
|
||||
|
||||
## Context
|
||||
|
||||
The application is experiencing a critical SSR (Server-Side Rendering) bug where `PushNotificationManager` attempts to access `localStorage` during server-side rendering, causing the application to crash:
|
||||
|
||||
```
|
||||
ReferenceError: localStorage is not defined
|
||||
at PushNotificationManager.generateClientId (src/lib/client/PushNotificationManager.ts:256:20)
|
||||
at new PushNotificationManager (src/lib/client/PushNotificationManager.ts:31:26)
|
||||
```
|
||||
|
||||
Additionally:
|
||||
- The SSL certificate expired on Dec 21, 2025 (yesterday)
|
||||
- The codebase contains dead/unused code that should be deleted
|
||||
- There are opportunities to consolidate duplicate code
|
||||
|
||||
**CRITICAL:** All work must be done in the **current branch** (`feat/async-in-memory-processing-queue`), not a new branch.
|
||||
|
||||
## Research Summary
|
||||
|
||||
### SvelteKit SSR & localStorage Best Practices
|
||||
|
||||
From SvelteKit documentation and community best practices:
|
||||
|
||||
1. **Browser API Detection:** Use `browser` from `$app/environment` to check if code is running in browser
|
||||
2. **Lazy Initialization:** Don't access browser APIs at module level or in constructors
|
||||
3. **onMount Lifecycle:** Use Svelte's `onMount` for browser-only initialization
|
||||
4. **Guard Pattern:** Wrap all browser API access with browser checks
|
||||
|
||||
**Key Pattern:**
|
||||
```typescript
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
if (browser) {
|
||||
// Browser-only code here
|
||||
localStorage.getItem('key');
|
||||
}
|
||||
```
|
||||
|
||||
### SSL Certificate Strategy
|
||||
|
||||
For local development with 10-year validity:
|
||||
- Leverage the external Caddy container's CA (already trusted on the system)
|
||||
- Extract Caddy's CA private key to sign a custom certificate with 10-year validity
|
||||
- Use OpenSSL to generate and sign the certificate with Caddy's CA
|
||||
- No manual trust steps needed - Caddy CA already trusted
|
||||
- Alternative: Use Caddy's automatic generation if 10-year validity not strictly required (90-day certs)
|
||||
|
||||
## User Stories
|
||||
|
||||
### Story 0: Fix PushNotificationManager SSR Issue 🔴 CRITICAL
|
||||
|
||||
**As a** developer
|
||||
**I want** the PushNotificationManager to work correctly in SSR context
|
||||
**So that** the application doesn't crash when components are rendered on the server
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- ✅ PushNotificationManager constructor does not access `localStorage`
|
||||
- ✅ `clientId` is generated lazily only in browser context
|
||||
- ✅ All browser APIs (window, Notification, navigator) are guarded with browser checks
|
||||
- ✅ Module-level singleton instantiation is safe for SSR
|
||||
- ✅ NotificationSettings.svelte component works without errors
|
||||
- ✅ No SSR-related errors in console
|
||||
- ✅ Push notifications still work correctly in browser
|
||||
|
||||
**Technical Approach:**
|
||||
|
||||
1. **Lazy ClientId Generation:**
|
||||
```typescript
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
class PushNotificationManager {
|
||||
private _clientId: string | null = null;
|
||||
|
||||
private get clientId(): string {
|
||||
if (!this._clientId && browser) {
|
||||
this._clientId = this.generateClientId();
|
||||
}
|
||||
return this._clientId || 'ssr-fallback';
|
||||
}
|
||||
|
||||
private generateClientId(): string {
|
||||
if (!browser) return '';
|
||||
|
||||
const stored = localStorage.getItem('push-client-id');
|
||||
if (stored) return stored;
|
||||
|
||||
const id = `client_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
||||
localStorage.setItem('push-client-id', id);
|
||||
return id;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. **Guard Browser API Checks:**
|
||||
```typescript
|
||||
private checkSupport(): void {
|
||||
if (!browser) {
|
||||
this.state.supported = false;
|
||||
this.state.permission = 'denied';
|
||||
return;
|
||||
}
|
||||
|
||||
this.state.supported = (
|
||||
'serviceWorker' in navigator &&
|
||||
'PushManager' in window &&
|
||||
'Notification' in window
|
||||
);
|
||||
this.state.permission = this.state.supported ? Notification.permission : 'denied';
|
||||
}
|
||||
```
|
||||
|
||||
3. **Safe Service Worker Initialization:**
|
||||
```typescript
|
||||
private async initializeServiceWorker(): Promise<void> {
|
||||
if (!browser || !this.state.supported) return;
|
||||
|
||||
// Rest of initialization
|
||||
}
|
||||
```
|
||||
|
||||
**Files:**
|
||||
- `src/lib/client/PushNotificationManager.ts` (update)
|
||||
- `src/routes/components/NotificationSettings.svelte` (verify)
|
||||
|
||||
**Testing:**
|
||||
- Test component renders without errors in SSR
|
||||
- Test push notification subscribe/unsubscribe in browser
|
||||
- Test that clientId persists across browser sessions
|
||||
- Verify no localStorage access during SSR
|
||||
|
||||
---
|
||||
|
||||
### Story 1: Generate 10-Year SSL Certificate Using External Caddy CA
|
||||
|
||||
**As a** developer
|
||||
**I want** a valid SSL certificate with 10-year validity signed by the external Caddy CA
|
||||
**So that** I don't have to regenerate certificates frequently and they're automatically trusted
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- ✅ New SSL certificate valid for 10 years (3650 days)
|
||||
- ✅ Certificate signed by existing Caddy CA (already trusted on system)
|
||||
- ✅ Certificate files in `.ssl/` directory:
|
||||
- `localhost.key` (private key)
|
||||
- `localhost.crt` (certificate signed by Caddy CA)
|
||||
- `root.crt` (Caddy CA certificate - copied from container)
|
||||
- ✅ Certificate automatically trusted (no manual trust needed)
|
||||
- ✅ `vite.config.ts` points to correct certificate files
|
||||
- ✅ Certificate expiration date verified: ~2035
|
||||
- ✅ Caddy container ID identified or documented
|
||||
|
||||
**Technical Approach:**
|
||||
|
||||
This approach leverages the external Caddy container's CA that's already trusted on the system, but generates a certificate with custom 10-year validity.
|
||||
|
||||
1. **Identify Caddy Container:**
|
||||
```bash
|
||||
# Find the Caddy container
|
||||
docker ps | grep caddy
|
||||
# Or use the known ID from previous work (might have changed)
|
||||
CADDY_CONTAINER=$(docker ps --filter "ancestor=caddy" --format "{{.ID}}" | head -1)
|
||||
echo "Caddy container: $CADDY_CONTAINER"
|
||||
```
|
||||
|
||||
2. **Export Caddy's CA Certificate and Private Key:**
|
||||
```bash
|
||||
# Copy the CA certificate (already done, but verify it exists)
|
||||
docker cp $CADDY_CONTAINER:/data/caddy/pki/authorities/local/root.crt .ssl/root.crt
|
||||
|
||||
# Copy the CA private key (needed to sign our custom certificate)
|
||||
docker cp $CADDY_CONTAINER:/data/caddy/pki/authorities/local/root.key .ssl/caddy-ca.key
|
||||
|
||||
# Verify CA certificate
|
||||
openssl x509 -in .ssl/root.crt -text -noout | grep "Subject:"
|
||||
```
|
||||
|
||||
3. **Generate New Server Certificate with 10-Year Validity:**
|
||||
```bash
|
||||
# Generate server private key (2048-bit is sufficient)
|
||||
openssl genrsa -out .ssl/localhost.key 2048
|
||||
|
||||
# Generate Certificate Signing Request (CSR)
|
||||
openssl req -new \
|
||||
-key .ssl/localhost.key \
|
||||
-out .ssl/localhost.csr \
|
||||
-subj "/O=Caddy Local Authority/CN=localhost"
|
||||
|
||||
# Create OpenSSL config for Subject Alternative Names (SAN)
|
||||
cat > .ssl/localhost.ext << 'EOF'
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
basicConstraints=CA:FALSE
|
||||
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
|
||||
extendedKeyUsage = serverAuth
|
||||
subjectAltName = @alt_names
|
||||
|
||||
[alt_names]
|
||||
DNS.1 = localhost
|
||||
DNS.2 = *.localhost
|
||||
IP.1 = 127.0.0.1
|
||||
IP.2 = ::1
|
||||
EOF
|
||||
|
||||
# Sign the certificate with Caddy's CA (10 years = 3650 days)
|
||||
openssl x509 -req \
|
||||
-in .ssl/localhost.csr \
|
||||
-CA .ssl/root.crt \
|
||||
-CAkey .ssl/caddy-ca.key \
|
||||
-CAcreateserial \
|
||||
-out .ssl/localhost.crt \
|
||||
-days 3650 \
|
||||
-sha256 \
|
||||
-extfile .ssl/localhost.ext
|
||||
|
||||
# Cleanup temporary files and CA private key (security)
|
||||
rm .ssl/localhost.csr .ssl/localhost.ext .ssl/caddy-ca.key
|
||||
|
||||
# Set restrictive permissions
|
||||
chmod 600 .ssl/localhost.key
|
||||
chmod 644 .ssl/localhost.crt .ssl/root.crt
|
||||
```
|
||||
|
||||
4. **Verify Certificate:**
|
||||
```bash
|
||||
# Check expiration date (should be ~2035)
|
||||
openssl x509 -enddate -noout -in .ssl/localhost.crt
|
||||
|
||||
# Verify certificate is signed by Caddy CA
|
||||
openssl verify -CAfile .ssl/root.crt .ssl/localhost.crt
|
||||
|
||||
# Check certificate details
|
||||
openssl x509 -in .ssl/localhost.crt -text -noout | grep -A 1 "Subject:"
|
||||
openssl x509 -in .ssl/localhost.crt -text -noout | grep -A 3 "Subject Alternative Name"
|
||||
```
|
||||
|
||||
5. **Verify Vite Configuration:**
|
||||
```bash
|
||||
# Ensure vite.config.ts already points to correct files
|
||||
grep -A 3 "https:" vite.config.ts
|
||||
```
|
||||
|
||||
**Alternative: If Caddy CA Private Key is Not Accessible**
|
||||
|
||||
If the CA private key is not accessible from the container, use Caddy's built-in certificate generation but with a workaround:
|
||||
|
||||
1. **Trigger Caddy Certificate Generation:**
|
||||
```bash
|
||||
# Run temporary Caddy reverse-proxy to trigger cert generation
|
||||
docker exec -d $CADDY_CONTAINER caddy reverse-proxy \
|
||||
--from localhost:8443 \
|
||||
--to localhost:8080
|
||||
|
||||
# Wait for certificate generation (5-10 seconds)
|
||||
sleep 10
|
||||
|
||||
# Stop the temporary process
|
||||
docker exec $CADDY_CONTAINER pkill -f "caddy reverse-proxy"
|
||||
```
|
||||
|
||||
2. **Copy Generated Certificates:**
|
||||
```bash
|
||||
# Copy Caddy-generated certificates
|
||||
docker cp $CADDY_CONTAINER:/data/caddy/certificates/local/localhost/localhost.crt .ssl/
|
||||
docker cp $CADDY_CONTAINER:/data/caddy/certificates/local/localhost/localhost.key .ssl/
|
||||
docker cp $CADDY_CONTAINER:/data/caddy/pki/authorities/local/root.crt .ssl/
|
||||
```
|
||||
|
||||
3. **Note on Validity:**
|
||||
- Caddy-generated certificates typically have 90-day validity
|
||||
- If 10-year validity is required, must use OpenSSL approach with CA key
|
||||
- Document renewal process in README if using short-lived certs
|
||||
|
||||
**Files:**
|
||||
- `.ssl/localhost.key` (create - server private key)
|
||||
- `.ssl/localhost.crt` (create - server certificate signed by Caddy CA)
|
||||
- `.ssl/root.crt` (copy from Caddy container - CA certificate)
|
||||
- `README.md` (update with certificate info and renewal instructions)
|
||||
- `.gitignore` (verify .ssl/ is ignored except for .gitkeep)
|
||||
|
||||
**Testing:**
|
||||
- Verify certificate dates: `openssl x509 -enddate -noout -in .ssl/localhost.crt`
|
||||
- Verify CA signature: `openssl verify -CAfile .ssl/root.crt .ssl/localhost.crt`
|
||||
- Test HTTPS server starts: `npm run dev`
|
||||
- Verify browser shows secure connection (should be automatic - CA already trusted)
|
||||
- Test certificate valid until ~2035 (if using OpenSSL approach)
|
||||
|
||||
**Documentation Note:**
|
||||
Since the Caddy CA is already trusted on the system, no manual trust steps are needed. Document in README:
|
||||
- How to check certificate expiration
|
||||
- How to regenerate using same process
|
||||
- Caddy container identification steps
|
||||
|
||||
---
|
||||
|
||||
### Story 2: Audit and Delete Dead/Unused Code
|
||||
|
||||
**As a** developer
|
||||
**I want** to remove all dead and unused code from the codebase
|
||||
**So that** the codebase is cleaner and easier to maintain
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- ✅ All unused imports removed
|
||||
- ✅ All unreferenced functions/types deleted
|
||||
- ✅ All commented-out code blocks removed
|
||||
- ✅ Unused test fixtures cleaned up
|
||||
- ✅ No deprecation markers (code is deleted, not deprecated)
|
||||
- ✅ All tests still passing
|
||||
- ✅ No broken imports or references
|
||||
|
||||
**Audit Areas:**
|
||||
|
||||
1. **Check for Unused Imports:**
|
||||
```bash
|
||||
# Use TypeScript compiler to find unused imports
|
||||
npx tsc --noEmit
|
||||
|
||||
# Or use eslint if configured
|
||||
npm run lint
|
||||
```
|
||||
|
||||
2. **Scan for Unreferenced Code:**
|
||||
- Search for functions/classes that are never imported
|
||||
- Check test files for unused fixtures
|
||||
- Look for commented-out code blocks (`// `, `/* */`)
|
||||
|
||||
3. **Verify Deprecated Endpoints:**
|
||||
- `/api/extract` returns 410 Gone ✅ KEEP (migration helper)
|
||||
- `/api/extract-stream` already deleted ✅
|
||||
- Check for any other deprecated routes
|
||||
|
||||
4. **Clean Up Test Files:**
|
||||
- `src/tests/fixtures.ts` - review localStorage fixtures
|
||||
- Remove any unused test helpers
|
||||
- Delete obsolete test files
|
||||
|
||||
5. **Review Client Components:**
|
||||
- `ServiceWorkerMessageHandler.ts` - verify usage
|
||||
- Check for unused utility functions
|
||||
|
||||
**Files to Review:**
|
||||
- `src/lib/client/*` - Client utilities
|
||||
- `src/tests/*` - Test files and fixtures
|
||||
- `src/routes/components/*` - UI components
|
||||
- All import statements across codebase
|
||||
|
||||
**Deletion Checklist:**
|
||||
- [ ] Unused imports removed
|
||||
- [ ] Commented-out code deleted
|
||||
- [ ] Unreferenced functions deleted
|
||||
- [ ] Obsolete test fixtures removed
|
||||
- [ ] Dead code paths eliminated
|
||||
- [ ] Verify no broken imports with `npx tsc --noEmit`
|
||||
|
||||
**Testing:**
|
||||
- Run full test suite: `npm test`
|
||||
- Build project: `npm run build`
|
||||
- Check for TypeScript errors: `npx tsc --noEmit`
|
||||
- Verify dev server starts: `npm run dev`
|
||||
|
||||
---
|
||||
|
||||
### Story 3: Consolidate Duplicate Code
|
||||
|
||||
**As a** developer
|
||||
**I want** to consolidate duplicate and similar code
|
||||
**So that** the codebase has less redundancy and is easier to maintain
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- ✅ Duplicate type definitions merged
|
||||
- ✅ Similar utility functions consolidated
|
||||
- ✅ Repeated code blocks extracted to functions
|
||||
- ✅ Common patterns extracted to shared utilities
|
||||
- ✅ No functionality broken
|
||||
- ✅ All tests still passing
|
||||
|
||||
**Consolidation Areas:**
|
||||
|
||||
1. **Type Definitions:**
|
||||
- Check for duplicate interfaces/types across files
|
||||
- Move shared types to appropriate locations:
|
||||
- Domain types → `src/lib/server/queue/types.ts`
|
||||
- Client types → `src/lib/client/types.ts` (create if needed)
|
||||
- Shared types → `src/lib/types.ts` (create if needed)
|
||||
|
||||
2. **Utility Functions:**
|
||||
- Look for similar string formatting functions
|
||||
- Check for duplicate validation logic
|
||||
- Identify common data transformation patterns
|
||||
|
||||
3. **Component Patterns:**
|
||||
- Similar error handling across components
|
||||
- Repeated state management patterns
|
||||
- Common UI patterns
|
||||
|
||||
4. **API Response Handling:**
|
||||
- Similar fetch patterns
|
||||
- Duplicate error handling
|
||||
- Common response transformations
|
||||
|
||||
**Investigation Steps:**
|
||||
|
||||
1. **Search for Duplicate Type Definitions:**
|
||||
```bash
|
||||
# Look for common type names
|
||||
grep -r "interface.*State" src/
|
||||
grep -r "type.*Config" src/
|
||||
```
|
||||
|
||||
2. **Find Similar Function Signatures:**
|
||||
```bash
|
||||
# Look for validation functions
|
||||
grep -r "function validate" src/
|
||||
grep -r "async function.*fetch" src/
|
||||
```
|
||||
|
||||
3. **Identify Repeated Patterns:**
|
||||
- SSE connection setup
|
||||
- Error handling blocks
|
||||
- Loading state management
|
||||
- Form validation
|
||||
|
||||
**Consolidation Strategy:**
|
||||
|
||||
For each duplicate found:
|
||||
1. Determine the most complete/correct version
|
||||
2. Extract to shared location if used in multiple places
|
||||
3. Update all references to use shared version
|
||||
4. Delete duplicate versions
|
||||
5. Verify tests pass
|
||||
|
||||
**Files:**
|
||||
- Potentially create: `src/lib/utils/` directory for shared utilities
|
||||
- Potentially create: `src/lib/types.ts` for shared types
|
||||
- Update all files with consolidated references
|
||||
|
||||
**Testing:**
|
||||
- Run full test suite after each consolidation
|
||||
- Verify no regression in functionality
|
||||
- Check TypeScript compilation succeeds
|
||||
|
||||
---
|
||||
|
||||
### Story 4: Verify and Test Complete Solution
|
||||
|
||||
**As a** developer
|
||||
**I want** to verify all changes work correctly together
|
||||
**So that** the fixes are production-ready
|
||||
|
||||
**Acceptance Criteria:**
|
||||
- ✅ All unit tests passing
|
||||
- ✅ Integration tests passing
|
||||
- ✅ No SSR errors in development
|
||||
- ✅ No SSR errors in production build
|
||||
- ✅ SSL certificate works correctly
|
||||
- ✅ Push notifications work in browser
|
||||
- ✅ No console warnings or errors
|
||||
- ✅ Application builds successfully
|
||||
- ✅ All TypeScript errors resolved
|
||||
|
||||
**Testing Checklist:**
|
||||
|
||||
1. **SSR Testing:**
|
||||
```bash
|
||||
# Test dev server (SSR enabled)
|
||||
npm run dev
|
||||
# Visit pages and check console for errors
|
||||
|
||||
# Test production build
|
||||
npm run build
|
||||
npm run preview
|
||||
```
|
||||
|
||||
2. **Push Notification Testing:**
|
||||
- Open NotificationSettings component
|
||||
- Verify no SSR errors
|
||||
- Test subscribe/unsubscribe in browser
|
||||
- Verify clientId persists across refresh
|
||||
|
||||
3. **SSL Certificate Testing:**
|
||||
- Verify HTTPS connection works
|
||||
- Check certificate validity in browser
|
||||
- Test across different browsers (Chrome, Firefox)
|
||||
|
||||
4. **Code Quality:**
|
||||
```bash
|
||||
# TypeScript check
|
||||
npx tsc --noEmit
|
||||
|
||||
# Linting
|
||||
npm run lint
|
||||
|
||||
# Unit tests
|
||||
npm test
|
||||
|
||||
# Build
|
||||
npm run build
|
||||
```
|
||||
|
||||
5. **Manual Testing:**
|
||||
- Test all queue operations
|
||||
- Test extraction flow
|
||||
- Verify push notifications
|
||||
- Check HTTPS connection
|
||||
- Test on mobile browsers (if applicable)
|
||||
|
||||
**Regression Testing:**
|
||||
- Queue creation works
|
||||
- SSE progress updates work
|
||||
- Extraction completes successfully
|
||||
- Tandoor integration works
|
||||
- All existing features functional
|
||||
|
||||
**Performance Check:**
|
||||
- Bundle size acceptable
|
||||
- No memory leaks
|
||||
- Reasonable load times
|
||||
- No performance degradation
|
||||
|
||||
---
|
||||
|
||||
## Technical Specifications
|
||||
|
||||
### Browser API Guard Pattern
|
||||
|
||||
All browser API access must follow this pattern:
|
||||
|
||||
```typescript
|
||||
import { browser } from '$app/environment';
|
||||
|
||||
// Module level - safe for SSR
|
||||
class MyClass {
|
||||
private browserOnlyState: SomeType | null = null;
|
||||
|
||||
// Constructor - safe for SSR
|
||||
constructor() {
|
||||
// NO browser API access here
|
||||
}
|
||||
|
||||
// Methods can check browser context
|
||||
someMethod() {
|
||||
if (!browser) {
|
||||
return; // or return safe default
|
||||
}
|
||||
|
||||
// Browser APIs safe here
|
||||
const data = localStorage.getItem('key');
|
||||
}
|
||||
|
||||
// Lazy initialization pattern
|
||||
private _clientId: string | null = null;
|
||||
private get clientId(): string {
|
||||
if (!this._clientId && browser) {
|
||||
this._clientId = this.initializeClientId();
|
||||
}
|
||||
return this._clientId || 'fallback-value';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### SSL Certificate File Structure
|
||||
|
||||
```
|
||||
.ssl/
|
||||
├── localhost.key # Server private key (2048-bit RSA)
|
||||
├── localhost.crt # Server certificate (signed by Caddy CA, 10 years)
|
||||
├── root.crt # Caddy CA certificate (copied from container, already trusted)
|
||||
└── .gitkeep # Track directory but ignore contents
|
||||
```
|
||||
|
||||
### Code Deletion Guidelines
|
||||
|
||||
1. **Before Deleting:**
|
||||
- Search entire codebase for references
|
||||
- Check test files for usage
|
||||
- Verify not used in comments or documentation
|
||||
- Check git history for context
|
||||
|
||||
2. **Safe to Delete:**
|
||||
- No references found
|
||||
- Confirmed not used in any import
|
||||
- Not referenced in documentation
|
||||
- Clearly obsolete/deprecated
|
||||
|
||||
3. **Keep but Document:**
|
||||
- Migration helper endpoints (like /api/extract)
|
||||
- Fallback strategies (like legacy extraction)
|
||||
- Backward compatibility shims
|
||||
|
||||
4. **Delete Immediately:**
|
||||
- Commented-out code
|
||||
- Unused imports
|
||||
- Unreferenced functions
|
||||
- Obsolete test fixtures
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Story Dependencies
|
||||
|
||||
- Story 0 (SSR Fix) → No dependencies, can start immediately
|
||||
- Story 1 (SSL) → No dependencies, can start immediately
|
||||
- Story 2 (Dead Code) → Should wait for Story 0 completion
|
||||
- Story 3 (Consolidation) → Should wait for Story 2 completion
|
||||
- Story 4 (Verification) → Depends on all previous stories
|
||||
|
||||
### Execution Order
|
||||
|
||||
1. **Story 0** - Critical SSR fix (blocks development)
|
||||
2. **Story 1** - SSL regeneration (parallel with Story 0)
|
||||
3. **Story 2** - Dead code cleanup
|
||||
4. **Story 3** - Code consolidation
|
||||
5. **Story 4** - Final verification and testing
|
||||
|
||||
---
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
### High Risk
|
||||
|
||||
**Risk:** Breaking push notification functionality
|
||||
- **Impact:** Users lose real-time updates
|
||||
- **Likelihood:** Medium
|
||||
- **Mitigation:** Thorough testing in browser and SSR contexts
|
||||
- **Rollback:** Revert PushNotificationManager changes, keep old version
|
||||
|
||||
**Risk:** SSL certificate not trusted by system
|
||||
- **Impact:** Development blocked, HTTPS warnings
|
||||
- **Likelihood:** Low (clear instructions provided)
|
||||
- **Mitigation:** Detailed trust instructions for all platforms
|
||||
- **Rollback:** Regenerate old certificate or disable HTTPS temporarily
|
||||
|
||||
### Medium Risk
|
||||
|
||||
**Risk:** Deleting code that's actually used
|
||||
- **Impact:** Runtime errors, broken functionality
|
||||
- **Likelihood:** Low (comprehensive search before delete)
|
||||
- **Mitigation:** Thorough searching, test suite verification
|
||||
- **Rollback:** Git revert specific deletions
|
||||
|
||||
**Risk:** Consolidation introducing subtle bugs
|
||||
- **Impact:** Broken functionality in edge cases
|
||||
- **Likelihood:** Low
|
||||
- **Mitigation:** Incremental consolidation, test after each change
|
||||
- **Rollback:** Git revert to pre-consolidation state
|
||||
|
||||
### Low Risk
|
||||
|
||||
**Risk:** TypeScript compilation errors after changes
|
||||
- **Impact:** Development blocked temporarily
|
||||
- **Likelihood:** Very Low
|
||||
- **Mitigation:** Run tsc check frequently
|
||||
- **Rollback:** Easy to fix type errors
|
||||
|
||||
---
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Unit Tests
|
||||
|
||||
- Test PushNotificationManager in isolation
|
||||
- Mock browser APIs for testing
|
||||
- Test lazy initialization patterns
|
||||
- Verify state management
|
||||
|
||||
### Integration Tests
|
||||
|
||||
- Test NotificationSettings component
|
||||
- Verify SSE integration still works
|
||||
- Test queue system end-to-end
|
||||
- Verify extraction pipeline
|
||||
|
||||
### SSR Tests
|
||||
|
||||
- Render components server-side
|
||||
- Verify no localStorage access
|
||||
- Check no window/navigator access
|
||||
- Ensure safe module initialization
|
||||
|
||||
### Manual Tests
|
||||
|
||||
- Browser push notifications
|
||||
- SSL certificate trust
|
||||
- HTTPS connection
|
||||
- Cross-browser compatibility
|
||||
|
||||
---
|
||||
|
||||
## Documentation Updates
|
||||
|
||||
### README.md
|
||||
|
||||
Add/update sections:
|
||||
- SSL Certificate Setup (detailed trust instructions)
|
||||
- HTTPS Development Setup
|
||||
- Browser Requirements
|
||||
- Troubleshooting SSL issues
|
||||
|
||||
### Code Comments
|
||||
|
||||
- Document browser API guard patterns
|
||||
- Explain lazy initialization approach
|
||||
- Note SSR safety considerations
|
||||
- Document clientId generation logic
|
||||
|
||||
---
|
||||
|
||||
## Success Metrics
|
||||
|
||||
1. **Zero SSR Errors:** No localStorage or browser API errors during SSR
|
||||
2. **Push Notifications Working:** Subscribe/unsubscribe functional in browser
|
||||
3. **SSL Valid:** Certificate valid until ~2035, trusted by browsers
|
||||
4. **Clean Codebase:** No unused imports, no dead code, no duplicates
|
||||
5. **All Tests Passing:** 100% test suite success rate
|
||||
6. **TypeScript Clean:** Zero compilation errors
|
||||
7. **No Console Errors:** Clean browser console in dev and prod
|
||||
|
||||
---
|
||||
|
||||
## Rollback Plan
|
||||
|
||||
If critical issues arise:
|
||||
|
||||
1. **SSR Fix Rollback:**
|
||||
```bash
|
||||
git revert <commit-hash-of-ssr-fix>
|
||||
# Or restore old PushNotificationManager.ts
|
||||
```
|
||||
|
||||
2. **SSL Rollback:**
|
||||
```bash
|
||||
# Generate quick temporary certificate
|
||||
openssl req -x509 -newkey rsa:2048 -nodes \
|
||||
-keyout .ssl/localhost.key \
|
||||
-out .ssl/localhost.crt \
|
||||
-days 365 -subj "/CN=localhost"
|
||||
```
|
||||
|
||||
3. **Code Cleanup Rollback:**
|
||||
```bash
|
||||
git revert <cleanup-commit-hash>
|
||||
# Or restore specific deleted files from git history
|
||||
```
|
||||
|
||||
4. **Full Rollback:**
|
||||
```bash
|
||||
# Reset to before all changes
|
||||
git reset --hard <commit-before-changes>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Timeline Estimate
|
||||
|
||||
- **Story 0 (SSR Fix):** 2-3 hours
|
||||
- **Story 1 (SSL):** 1-2 hours (can be parallel)
|
||||
- **Story 2 (Dead Code):** 2-4 hours
|
||||
- **Story 3 (Consolidation):** 3-5 hours
|
||||
- **Story 4 (Verification):** 1-2 hours
|
||||
|
||||
**Total Estimated Time:** 9-16 hours
|
||||
|
||||
---
|
||||
|
||||
## Branch Strategy
|
||||
|
||||
⚠️ **IMPORTANT:** All work MUST be done in the current branch:
|
||||
- Branch: `feat/async-in-memory-processing-queue`
|
||||
- Do NOT create a new feature branch
|
||||
- Commit incrementally with clear messages
|
||||
- Keep all changes contained in this branch
|
||||
|
||||
---
|
||||
|
||||
## Completion Criteria
|
||||
|
||||
The plan is complete when:
|
||||
|
||||
1. ✅ PushNotificationManager works in both SSR and browser contexts
|
||||
2. ✅ No localStorage errors in any context
|
||||
3. ✅ SSL certificate valid for 10 years
|
||||
4. ✅ HTTPS development server working
|
||||
5. ✅ All dead code deleted (not deprecated)
|
||||
6. ✅ All duplicate code consolidated
|
||||
7. ✅ All tests passing
|
||||
8. ✅ No TypeScript errors
|
||||
9. ✅ No console warnings/errors
|
||||
10. ✅ Application builds successfully
|
||||
11. ✅ Documentation updated
|
||||
12. ✅ All changes committed to current branch
|
||||
|
||||
---
|
||||
|
||||
## Notes
|
||||
|
||||
- SvelteKit documentation emphasizes avoiding browser APIs in SSR context
|
||||
- The `browser` environment variable is the recommended pattern
|
||||
- SSL certificates for local development typically don't need to be from a real CA
|
||||
- 10-year validity is reasonable for local development certificates
|
||||
- Code should be deleted, not deprecated, when truly unused
|
||||
- Consolidation should focus on real duplicates, not just similar patterns
|
||||
- Keep backward compatibility for migration helper endpoints
|
||||
Reference in New Issue
Block a user