751 lines
18 KiB
Markdown
751 lines
18 KiB
Markdown
# Legacy Code Cleanup & Modernization Plan
|
|
|
|
## Overview
|
|
|
|
This document identifies outdated code, redundant systems, and performance bottlenecks in EasyStream that should be removed or refactored to create a modern, efficient streaming platform.
|
|
|
|
## Table of Contents
|
|
|
|
1. [Critical Removals](#critical-removals)
|
|
2. [Authentication System Cleanup](#authentication-system-cleanup)
|
|
3. [Database Query Optimization](#database-query-optimization)
|
|
4. [Frontend JavaScript Modernization](#frontend-javascript-modernization)
|
|
5. [File Structure Reorganization](#file-structure-reorganization)
|
|
6. [Performance Optimizations](#performance-optimizations)
|
|
7. [Migration Checklist](#migration-checklist)
|
|
|
|
---
|
|
|
|
## Critical Removals
|
|
|
|
### 1. Duplicate Authentication Systems
|
|
|
|
**Problem:** Multiple authentication systems exist, causing confusion and security risks.
|
|
|
|
**Files to Remove/Consolidate:**
|
|
|
|
```
|
|
REMOVE:
|
|
- f_core/f_classes/class.login.php (Old VLogin class)
|
|
- f_core/f_classes/class.session.php (Redundant with VAuth)
|
|
- Any references to VLogin in other files
|
|
|
|
KEEP:
|
|
- f_core/f_classes/class.auth.php (VAuth - Modern system)
|
|
```
|
|
|
|
**Action Plan:**
|
|
1. Search codebase for `VLogin` references
|
|
2. Replace with `VAuth::getInstance()`
|
|
3. Update all login forms to use VAuth
|
|
4. Remove class.login.php entirely
|
|
|
|
**Command to find VLogin usage:**
|
|
```bash
|
|
grep -r "VLogin" f_core/ f_modules/ *.php
|
|
```
|
|
|
|
### 2. Legacy Database Classes
|
|
|
|
**Problem:** Multiple database wrapper classes causing overhead.
|
|
|
|
**Files to Audit:**
|
|
```
|
|
f_core/f_classes/class.database.php - Keep (ADOdb wrapper)
|
|
f_core/f_classes/db*.php - Review for redundancy
|
|
```
|
|
|
|
**Action:** Ensure all code uses `VDatabase::getInstance()` and remove any custom DB wrappers.
|
|
|
|
### 3. Obsolete jQuery Plugins
|
|
|
|
**Problem:** Old jQuery plugins add bloat and security vulnerabilities.
|
|
|
|
**Files to Remove:**
|
|
```
|
|
f_scripts/be/js/init1.min.js - Contains jquery.form plugin (outdated)
|
|
f_scripts/*/jquery.*.min.js - Review each for necessity
|
|
```
|
|
|
|
**Replace With:**
|
|
- Native FormData API
|
|
- Fetch API
|
|
- Modern ES6+ code
|
|
|
|
### 4. Inline JavaScript in PHP Files
|
|
|
|
**Problem:** JavaScript mixed with PHP makes maintenance difficult.
|
|
|
|
**Action:**
|
|
1. Extract all `<script>` tags from PHP files
|
|
2. Move to dedicated .js files
|
|
3. Use data attributes for configuration
|
|
4. Use modern module pattern
|
|
|
|
**Example Files to Clean:**
|
|
```
|
|
browse.php - Contains inline JS
|
|
profile.php - Contains inline JS
|
|
upload.php - Contains inline JS
|
|
```
|
|
|
|
---
|
|
|
|
## Authentication System Cleanup
|
|
|
|
### Current State: 3 Auth Methods
|
|
|
|
1. **Old VLogin** (deprecated)
|
|
2. **VSession** (redundant)
|
|
3. **VAuth** (modern, keep this)
|
|
|
|
### Cleanup Steps
|
|
|
|
#### Step 1: Find All VLogin Usage
|
|
|
|
```bash
|
|
# Find files using VLogin
|
|
grep -r "VLogin" --include="*.php" .
|
|
|
|
# Find session_start calls (should be in VAuth only)
|
|
grep -r "session_start()" --include="*.php" .
|
|
```
|
|
|
|
#### Step 2: Update All References
|
|
|
|
**Before:**
|
|
```php
|
|
$login = new VLogin();
|
|
$login->doLogin($username, $password);
|
|
if ($login->isLoggedIn()) {
|
|
// ...
|
|
}
|
|
```
|
|
|
|
**After:**
|
|
```php
|
|
$auth = VAuth::getInstance();
|
|
$result = $auth->login($identifier, $password);
|
|
if ($auth->isAuthenticated()) {
|
|
// ...
|
|
}
|
|
```
|
|
|
|
#### Step 3: Remove Old Files
|
|
|
|
```bash
|
|
# After migrating all code:
|
|
rm f_core/f_classes/class.login.php
|
|
rm f_core/f_classes/class.session.php
|
|
```
|
|
|
|
### Session Management Consolidation
|
|
|
|
**Keep Only:**
|
|
- VAuth for all authentication
|
|
- VSession for session utilities (if lightweight)
|
|
|
|
**Or:** Merge VSession functionality into VAuth
|
|
|
|
---
|
|
|
|
## Database Query Optimization
|
|
|
|
### Problem: N+1 Query Issues
|
|
|
|
**Current Issue:**
|
|
```php
|
|
// BAD: N+1 queries
|
|
$videos = $db->execute("SELECT * FROM db_videofiles");
|
|
while (!$videos->EOF) {
|
|
$user = $db->execute("SELECT * FROM db_users WHERE usr_id = ?", [$videos->fields['usr_id']]);
|
|
// This runs once per video!
|
|
}
|
|
```
|
|
|
|
**Solution:**
|
|
```php
|
|
// GOOD: Single query with JOIN
|
|
$sql = "SELECT v.*, u.usr_id, u.usr_user, u.usr_dname, u.usr_avatar
|
|
FROM db_videofiles v
|
|
LEFT JOIN db_users u ON v.usr_id = u.usr_id
|
|
WHERE v.approved = 1";
|
|
$videos = $db->execute($sql);
|
|
```
|
|
|
|
### Remove Unnecessary Database Calls
|
|
|
|
#### 1. Count Queries in Loops
|
|
|
|
**Bad:**
|
|
```php
|
|
foreach ($videos as $video) {
|
|
$commentCount = $db->singleFieldValue("SELECT COUNT(*) FROM db_comments WHERE file_key = ?", [$video['file_key']]);
|
|
}
|
|
```
|
|
|
|
**Good:**
|
|
```php
|
|
// Get all counts in one query
|
|
$sql = "SELECT file_key, COUNT(*) as comment_count
|
|
FROM db_comments
|
|
WHERE file_key IN (?)
|
|
GROUP BY file_key";
|
|
```
|
|
|
|
#### 2. Redundant Existence Checks
|
|
|
|
**Bad:**
|
|
```php
|
|
// Check if exists
|
|
$exists = $db->execute("SELECT COUNT(*) FROM db_users WHERE usr_id = ?", [$userId]);
|
|
if ($exists->fields[0] > 0) {
|
|
// Then fetch the user
|
|
$user = $db->execute("SELECT * FROM db_users WHERE usr_id = ?", [$userId]);
|
|
}
|
|
```
|
|
|
|
**Good:**
|
|
```php
|
|
// Just fetch directly, check if result is empty
|
|
$user = $db->execute("SELECT * FROM db_users WHERE usr_id = ?", [$userId]);
|
|
if ($user && $user->RecordCount() > 0) {
|
|
// Use user data
|
|
}
|
|
```
|
|
|
|
### Add Database Indexes
|
|
|
|
Critical indexes to add:
|
|
|
|
```sql
|
|
-- Video queries
|
|
CREATE INDEX idx_videofiles_approved_privacy ON db_videofiles(approved, privacy);
|
|
CREATE INDEX idx_videofiles_usr_id ON db_videofiles(usr_id);
|
|
CREATE INDEX idx_videofiles_upload_date ON db_videofiles(upload_date);
|
|
CREATE INDEX idx_videofiles_file_views ON db_videofiles(file_views);
|
|
|
|
-- Comment queries
|
|
CREATE INDEX idx_comments_file_key ON db_comments(file_key);
|
|
CREATE INDEX idx_comments_parent_id ON db_comments(parent_id);
|
|
CREATE INDEX idx_comments_usr_id ON db_comments(usr_id);
|
|
|
|
-- Subscription queries
|
|
CREATE INDEX idx_subscriptions_usr_id ON db_subscriptions(usr_id);
|
|
CREATE INDEX idx_subscriptions_channel_id ON db_subscriptions(channel_id);
|
|
|
|
-- Like queries
|
|
CREATE INDEX idx_likes_file_key_type ON db_likes(file_key, like_type);
|
|
CREATE INDEX idx_likes_usr_id ON db_likes(usr_id);
|
|
|
|
-- Session queries
|
|
CREATE INDEX idx_sessions_user_id ON db_sessions(user_id);
|
|
CREATE INDEX idx_sessions_expires_at ON db_sessions(expires_at);
|
|
```
|
|
|
|
---
|
|
|
|
## Frontend JavaScript Modernization
|
|
|
|
### Remove jQuery Dependency
|
|
|
|
jQuery is heavy (87KB minified) and no longer necessary.
|
|
|
|
#### Migration Strategy
|
|
|
|
**Phase 1: Utility Functions**
|
|
|
|
Create `f_scripts/fe/js/utils.js`:
|
|
|
|
```javascript
|
|
// Modern replacements for jQuery
|
|
const $ = {
|
|
// $(selector) -> document.querySelectorAll
|
|
select: (selector) => document.querySelectorAll(selector),
|
|
selectOne: (selector) => document.querySelector(selector),
|
|
|
|
// $.ajax -> fetch
|
|
ajax: async (url, options = {}) => {
|
|
const response = await fetch(url, options);
|
|
return response.json();
|
|
},
|
|
|
|
// $.get -> fetch
|
|
get: async (url) => {
|
|
const response = await fetch(url);
|
|
return response.json();
|
|
},
|
|
|
|
// $.post -> fetch
|
|
post: async (url, data) => {
|
|
const response = await fetch(url, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(data)
|
|
});
|
|
return response.json();
|
|
},
|
|
|
|
// $(element).addClass/removeClass
|
|
addClass: (el, className) => el.classList.add(className),
|
|
removeClass: (el, className) => el.classList.remove(className),
|
|
toggleClass: (el, className) => el.classList.toggle(className),
|
|
|
|
// $(element).show/hide
|
|
show: (el) => el.style.display = '',
|
|
hide: (el) => el.style.display = 'none',
|
|
|
|
// $(element).on
|
|
on: (el, event, handler) => el.addEventListener(event, handler),
|
|
off: (el, event, handler) => el.removeEventListener(event, handler),
|
|
|
|
// $.each -> Array.forEach
|
|
each: (arr, callback) => Array.from(arr).forEach(callback)
|
|
};
|
|
```
|
|
|
|
**Phase 2: Replace jQuery Usage**
|
|
|
|
**Before:**
|
|
```javascript
|
|
jQuery(document).ready(function() {
|
|
jQuery('.button').click(function() {
|
|
jQuery(this).addClass('active');
|
|
});
|
|
});
|
|
```
|
|
|
|
**After:**
|
|
```javascript
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
document.querySelectorAll('.button').forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
btn.classList.add('active');
|
|
});
|
|
});
|
|
});
|
|
```
|
|
|
|
Or using event delegation (more efficient):
|
|
```javascript
|
|
document.addEventListener('click', (e) => {
|
|
if (e.target.classList.contains('button')) {
|
|
e.target.classList.add('active');
|
|
}
|
|
});
|
|
```
|
|
|
|
### Files to Modernize
|
|
|
|
Priority order:
|
|
|
|
1. **High Priority (User-facing)**
|
|
- `browse.init.js` - Video browsing
|
|
- `login.init.js` - Authentication
|
|
- `jquery.init.js` - Global utilities
|
|
|
|
2. **Medium Priority**
|
|
- `files.init.js` - File management
|
|
- `channels.init.js` - Channel features
|
|
- `subdashboard.js` - Dashboard
|
|
|
|
3. **Low Priority**
|
|
- Backend admin files
|
|
- Analytics dashboards
|
|
|
|
### Remove Unused Libraries
|
|
|
|
Audit and remove:
|
|
|
|
```
|
|
f_scripts/lib/
|
|
├── jquery.old.js - Remove if exists
|
|
├── bootstrap.v2.js - If using v4+, remove v2
|
|
├── moment.js - Use native Date if possible
|
|
├── lodash.js - Use native ES6 methods
|
|
└── underscore.js - Redundant with lodash
|
|
```
|
|
|
|
---
|
|
|
|
## File Structure Reorganization
|
|
|
|
### Current Issues
|
|
|
|
1. **Flat file structure** - Hard to navigate
|
|
2. **Mixed concerns** - Frontend/backend not separated
|
|
3. **Redundant files** - Multiple versions of same functionality
|
|
|
|
### Proposed Structure
|
|
|
|
```
|
|
api/ # All API endpoints (CLEAN)
|
|
├── auth.php
|
|
├── videos.php
|
|
├── user.php
|
|
├── comments.php
|
|
├── subscriptions.php
|
|
└── cors.config.php
|
|
|
|
f_core/ # Core backend classes (KEEP CLEAN)
|
|
├── config.core.php # Main config
|
|
├── config.database.php # DB config
|
|
├── f_classes/ # Core classes
|
|
│ ├── class.auth.php # KEEP
|
|
│ ├── class.database.php # KEEP
|
|
│ ├── class.security.php # KEEP
|
|
│ ├── class.logger.php # KEEP
|
|
│ ├── class.rbac.php # KEEP
|
|
│ ├── class.middleware.php # KEEP
|
|
│ └── [REMOVE OLD CLASSES]
|
|
└── f_functions/ # Utility functions
|
|
├── functions.security.php
|
|
└── functions.rbac.php
|
|
|
|
f_scripts/
|
|
├── fe/ # Frontend only
|
|
│ ├── js/
|
|
│ │ ├── api-helper.js # MODERN API client
|
|
│ │ ├── utils.js # Native JS utilities
|
|
│ │ └── [page-specific].js
|
|
│ ├── css/
|
|
│ └── img/
|
|
└── be/ # Backend admin
|
|
└── js/
|
|
|
|
f_modules/ # Feature modules
|
|
├── m_frontend/ # User-facing features
|
|
└── m_backend/ # Admin features
|
|
|
|
docs/ # Documentation
|
|
├── API_DOCUMENTATION.md
|
|
├── FRONTEND_BACKEND_INTEGRATION_GUIDE.md
|
|
└── LEGACY_CODE_CLEANUP_PLAN.md
|
|
|
|
[root] # Page entry points
|
|
├── index.php
|
|
├── browse.php
|
|
├── profile.php
|
|
└── ...
|
|
```
|
|
|
|
### Files to Remove
|
|
|
|
```bash
|
|
# Find duplicate/old files
|
|
find . -name "*.old.php"
|
|
find . -name "*.backup.php"
|
|
find . -name "*_old.*"
|
|
find . -name "*_backup.*"
|
|
|
|
# Remove after verification
|
|
rm [files]
|
|
```
|
|
|
|
---
|
|
|
|
## Performance Optimizations
|
|
|
|
### 1. Implement Lazy Loading
|
|
|
|
**Videos/Images:**
|
|
|
|
```javascript
|
|
// Use Intersection Observer instead of scroll events
|
|
const lazyLoadObserver = new IntersectionObserver((entries) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
const img = entry.target;
|
|
img.src = img.dataset.src;
|
|
img.classList.remove('lazy');
|
|
lazyLoadObserver.unobserve(img);
|
|
}
|
|
});
|
|
});
|
|
|
|
document.querySelectorAll('img.lazy').forEach(img => {
|
|
lazyLoadObserver.observe(img);
|
|
});
|
|
```
|
|
|
|
### 2. Implement Caching
|
|
|
|
**Backend (PHP):**
|
|
|
|
```php
|
|
// Use Redis/Memcached for session storage (already configured)
|
|
// Add query result caching
|
|
|
|
class VCache {
|
|
private static $redis;
|
|
|
|
public static function get($key) {
|
|
if (!self::$redis) {
|
|
self::$redis = new Redis();
|
|
self::$redis->connect('127.0.0.1', 6379);
|
|
}
|
|
return self::$redis->get($key);
|
|
}
|
|
|
|
public static function set($key, $value, $ttl = 3600) {
|
|
if (!self::$redis) {
|
|
self::$redis = new Redis();
|
|
self::$redis->connect('127.0.0.1', 6379);
|
|
}
|
|
return self::$redis->setex($key, $ttl, serialize($value));
|
|
}
|
|
}
|
|
|
|
// Usage
|
|
$cacheKey = "videos:popular:page:{$page}";
|
|
$videos = VCache::get($cacheKey);
|
|
|
|
if (!$videos) {
|
|
$videos = $db->execute($sql, $params);
|
|
VCache::set($cacheKey, $videos->GetArray(), 300); // 5 min cache
|
|
}
|
|
```
|
|
|
|
**Frontend:**
|
|
|
|
```javascript
|
|
// Cache API responses in memory
|
|
class APICache {
|
|
constructor(ttl = 60000) { // 1 minute default
|
|
this.cache = new Map();
|
|
this.ttl = ttl;
|
|
}
|
|
|
|
get(key) {
|
|
const item = this.cache.get(key);
|
|
if (!item) return null;
|
|
|
|
if (Date.now() > item.expires) {
|
|
this.cache.delete(key);
|
|
return null;
|
|
}
|
|
|
|
return item.data;
|
|
}
|
|
|
|
set(key, data) {
|
|
this.cache.set(key, {
|
|
data,
|
|
expires: Date.now() + this.ttl
|
|
});
|
|
}
|
|
|
|
clear() {
|
|
this.cache.clear();
|
|
}
|
|
}
|
|
|
|
// Add to api-helper.js
|
|
const apiCache = new APICache();
|
|
|
|
// In request method:
|
|
const cacheKey = `${endpoint}:${JSON.stringify(params)}`;
|
|
const cached = apiCache.get(cacheKey);
|
|
if (cached && config.cache) {
|
|
return cached;
|
|
}
|
|
|
|
// After successful request:
|
|
if (config.cache) {
|
|
apiCache.set(cacheKey, data);
|
|
}
|
|
```
|
|
|
|
### 3. Optimize Database Queries
|
|
|
|
**Use Prepared Statement Caching:**
|
|
|
|
```php
|
|
// In VDatabase class
|
|
private $stmtCache = [];
|
|
|
|
public function execute($sql, $params = []) {
|
|
$cacheKey = md5($sql);
|
|
|
|
if (!isset($this->stmtCache[$cacheKey])) {
|
|
$this->stmtCache[$cacheKey] = $this->connection->Prepare($sql);
|
|
}
|
|
|
|
return $this->connection->Execute($this->stmtCache[$cacheKey], $params);
|
|
}
|
|
```
|
|
|
|
### 4. Minify and Bundle Assets
|
|
|
|
**Create build process:**
|
|
|
|
```json
|
|
// package.json
|
|
{
|
|
"scripts": {
|
|
"build:js": "esbuild f_scripts/fe/js/**/*.js --bundle --minify --outdir=f_scripts/fe/dist/js",
|
|
"build:css": "postcss f_scripts/fe/css/**/*.css --dir f_scripts/fe/dist/css --use cssnano",
|
|
"build": "npm run build:js && npm run build:css",
|
|
"watch": "npm run build -- --watch"
|
|
}
|
|
}
|
|
```
|
|
|
|
### 5. Implement Code Splitting
|
|
|
|
Split JavaScript into chunks:
|
|
|
|
```javascript
|
|
// Load features on demand
|
|
async function loadVideoPlayer() {
|
|
const { VideoPlayer } = await import('./video-player.js');
|
|
return new VideoPlayer();
|
|
}
|
|
|
|
// Only load when needed
|
|
document.querySelector('.video-container').addEventListener('click', async () => {
|
|
const player = await loadVideoPlayer();
|
|
player.play();
|
|
}, { once: true });
|
|
```
|
|
|
|
### 6. Remove Render-Blocking Resources
|
|
|
|
**Move scripts to end of body:**
|
|
|
|
```html
|
|
<!-- Before: -->
|
|
<head>
|
|
<script src="jquery.js"></script>
|
|
<script src="app.js"></script>
|
|
</head>
|
|
|
|
<!-- After: -->
|
|
<body>
|
|
<!-- content -->
|
|
<script src="app.js" defer></script>
|
|
</body>
|
|
```
|
|
|
|
Or use `async` for independent scripts:
|
|
|
|
```html
|
|
<script src="analytics.js" async></script>
|
|
```
|
|
|
|
---
|
|
|
|
## Migration Checklist
|
|
|
|
### Phase 1: Remove Duplicate Auth Systems
|
|
- [ ] Find all VLogin references
|
|
- [ ] Replace with VAuth
|
|
- [ ] Test authentication flows
|
|
- [ ] Remove class.login.php
|
|
- [ ] Remove class.session.php (if redundant)
|
|
- [ ] Update documentation
|
|
|
|
### Phase 2: Database Optimization
|
|
- [ ] Add missing indexes
|
|
- [ ] Audit for N+1 queries
|
|
- [ ] Implement query caching
|
|
- [ ] Use JOINs instead of separate queries
|
|
- [ ] Enable prepared statement caching
|
|
- [ ] Monitor slow query log
|
|
|
|
### Phase 3: Frontend Modernization
|
|
- [ ] Create native JS utility library
|
|
- [ ] Migrate browse.init.js to modern JS
|
|
- [ ] Migrate login.init.js to modern JS
|
|
- [ ] Migrate jquery.init.js to modern JS
|
|
- [ ] Remove jQuery dependency
|
|
- [ ] Test all user interactions
|
|
- [ ] Update build process
|
|
|
|
### Phase 4: File Cleanup
|
|
- [ ] Remove obsolete files (.old, .backup)
|
|
- [ ] Reorganize file structure
|
|
- [ ] Remove unused libraries
|
|
- [ ] Clean up inline JavaScript
|
|
- [ ] Move JS to external files
|
|
|
|
### Phase 5: Performance Optimization
|
|
- [ ] Implement lazy loading for images
|
|
- [ ] Add Redis caching for queries
|
|
- [ ] Enable browser caching headers
|
|
- [ ] Minify and bundle assets
|
|
- [ ] Implement code splitting
|
|
- [ ] Add service worker for offline support (optional)
|
|
|
|
### Phase 6: Testing & Validation
|
|
- [ ] Load test with Apache Bench
|
|
- [ ] Profile with Chrome DevTools
|
|
- [ ] Check for memory leaks
|
|
- [ ] Verify all features work
|
|
- [ ] Test on slow connections (throttling)
|
|
- [ ] Mobile device testing
|
|
|
|
---
|
|
|
|
## Performance Metrics to Track
|
|
|
|
### Before Cleanup
|
|
|
|
Measure these metrics before starting:
|
|
|
|
```bash
|
|
# Page load time
|
|
curl -o /dev/null -s -w 'Total: %{time_total}s\n' http://localhost/
|
|
|
|
# Time to first byte
|
|
curl -o /dev/null -s -w 'TTFB: %{time_starttransfer}s\n' http://localhost/
|
|
|
|
# Database query count (add logging)
|
|
grep "SELECT" /var/log/mysql/query.log | wc -l
|
|
```
|
|
|
|
### After Cleanup - Target Metrics
|
|
|
|
- Page load time: < 2 seconds
|
|
- Time to first byte: < 500ms
|
|
- Total JavaScript size: < 200KB
|
|
- Database queries per page: < 10
|
|
- Memory usage: < 128MB per request
|
|
|
|
---
|
|
|
|
## Resource Savings Estimate
|
|
|
|
### Expected Improvements
|
|
|
|
| Metric | Before | After | Improvement |
|
|
|--------|--------|-------|-------------|
|
|
| Page Load Time | 4-6s | 1-2s | 70% faster |
|
|
| JavaScript Size | 500KB | 150KB | 70% smaller |
|
|
| Database Queries | 30-50 | 5-10 | 80% fewer |
|
|
| Memory per Request | 256MB | 64MB | 75% less |
|
|
| Server Requests | 40+ | 15-20 | 60% fewer |
|
|
|
|
### Cost Savings
|
|
|
|
For a platform with 10,000 daily active users:
|
|
|
|
- **Server costs**: 50% reduction (fewer resources needed)
|
|
- **Bandwidth**: 60% reduction (smaller assets)
|
|
- **Database load**: 75% reduction (fewer queries, better caching)
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
1. **Backup everything** before making changes
|
|
2. **Start with authentication** cleanup (lowest risk)
|
|
3. **Test thoroughly** after each phase
|
|
4. **Monitor performance** metrics
|
|
5. **Document changes** as you go
|
|
|
|
---
|
|
|
|
**Created:** January 2025
|
|
**Status:** Planning Phase
|