mirror of
https://github.com/plexguide/Huntarr-Sonarr.git
synced 2025-12-16 20:04:16 -06:00
1226 lines
50 KiB
Markdown
1226 lines
50 KiB
Markdown
# Huntarr Development Guidelines
|
|
|
|
Quick reference for development patterns, common issues, and critical requirements.
|
|
|
|
## 🚨 CRITICAL RULES
|
|
|
|
### 🚫 NO AUTO-COMMITTING
|
|
**NEVER automatically commit changes without explicit user approval.**
|
|
- Present fixes to user first
|
|
- Get explicit approval before committing
|
|
- Let user decide when to commit
|
|
|
|
### 🔄 MANDATORY TESTING WORKFLOW
|
|
```bash
|
|
# ALWAYS rebuild and test changes
|
|
cd /Users/home/Huntarr/Huntarr.io && docker-compose down && COMPOSE_BAKE=true docker-compose up -d --build
|
|
|
|
# Check logs for errors
|
|
docker logs huntarr
|
|
```
|
|
|
|
### 🌐 CROSS-PLATFORM REQUIREMENTS
|
|
- **NEVER use hard-coded absolute paths** (e.g., `/config/file.json`)
|
|
- **ALWAYS use `os.path.join()`** for path construction
|
|
- **ALWAYS use relative URLs** in frontend (e.g., `./api/` not `/api/`)
|
|
- **ALWAYS test**: Docker, Windows, Mac, Linux, subpaths (`domain.com/huntarr/`)
|
|
|
|
### 🎛️ SIDEBAR NAVIGATION ARCHITECTURE
|
|
**Huntarr uses a multi-sidebar system for organized navigation:**
|
|
|
|
#### **Sidebar Types:**
|
|
1. **Main Sidebar** (`#sidebar`) - Default navigation (Home, Apps, Swaparr, Requestarr, etc.)
|
|
2. **Apps Sidebar** (`#apps-sidebar`) - App-specific navigation (Sonarr, Radarr, Lidarr, etc.)
|
|
3. **Settings Sidebar** (`#settings-sidebar`) - Settings navigation (Main, Scheduling, Notifications, Backup/Restore, User)
|
|
4. **Requestarr Sidebar** (`#requestarr-sidebar`) - Requestarr navigation (Home, History)
|
|
|
|
#### **Navigation Logic Pattern:**
|
|
```javascript
|
|
// CRITICAL: All sidebar sections must be included in initialization logic
|
|
if (this.currentSection === 'settings' || this.currentSection === 'scheduling' ||
|
|
this.currentSection === 'notifications' || this.currentSection === 'backup-restore' ||
|
|
this.currentSection === 'user') {
|
|
this.showSettingsSidebar();
|
|
} else if (this.currentSection === 'requestarr' || this.currentSection === 'requestarr-history') {
|
|
this.showRequestarrSidebar();
|
|
} else if (this.currentSection === 'apps' || this.currentSection === 'sonarr' ||
|
|
this.currentSection === 'radarr' || this.currentSection === 'lidarr' ||
|
|
this.currentSection === 'readarr' || this.currentSection === 'whisparr' ||
|
|
this.currentSection === 'eros' || this.currentSection === 'prowlarr') {
|
|
this.showAppsSidebar();
|
|
} else {
|
|
this.showMainSidebar();
|
|
}
|
|
```
|
|
|
|
#### **Apps Navigation Behavior:**
|
|
- **Clicking "Apps"** → Automatically redirects to Sonarr (most commonly used app)
|
|
- **Apps nav item stays highlighted** when viewing any app (Sonarr, Radarr, etc.)
|
|
- **Apps sidebar provides navigation** between individual apps
|
|
- **Direct URLs still work** (`#sonarr`, `#radarr`, etc.) for bookmarking specific apps
|
|
|
|
#### **Sidebar Switching Functions:**
|
|
```javascript
|
|
showMainSidebar: function() {
|
|
document.getElementById('sidebar').style.display = 'flex';
|
|
document.getElementById('apps-sidebar').style.display = 'none';
|
|
document.getElementById('settings-sidebar').style.display = 'none';
|
|
document.getElementById('requestarr-sidebar').style.display = 'none';
|
|
},
|
|
|
|
showAppsSidebar: function() {
|
|
document.getElementById('sidebar').style.display = 'none';
|
|
document.getElementById('apps-sidebar').style.display = 'flex';
|
|
document.getElementById('settings-sidebar').style.display = 'none';
|
|
document.getElementById('requestarr-sidebar').style.display = 'none';
|
|
}
|
|
// ... etc for other sidebars
|
|
```
|
|
|
|
#### **Required Elements for New Sidebars:**
|
|
1. **HTML Structure** - Must include logo, nav-menu, return button, and section groups
|
|
2. **Navigation Logic** - Must be added to both section switching AND initialization logic
|
|
3. **localStorage Management** - Set preferences like `localStorage.setItem('huntarr-apps-sidebar', 'true')`
|
|
4. **Mobile Responsiveness** - Ensure proper display on mobile devices
|
|
5. **Return Button** - Always include return navigation to main sidebar
|
|
|
|
#### **Mobile Behavior:**
|
|
- **Desktop**: Sidebars switch seamlessly with full navigation
|
|
- **Mobile**: Sidebars collapse to icons only, maintain switching functionality
|
|
- **Touch-friendly**: All navigation elements sized appropriately for mobile interaction
|
|
|
|
## 🐛 COMMON ISSUE PATTERNS
|
|
|
|
### 1. Frontend Log Regex Issues
|
|
**Symptoms:** Logs generated but not displayed for specific apps
|
|
**Root Cause:** Malformed regex with double backslashes
|
|
**Fix:**
|
|
```javascript
|
|
// ❌ BROKEN
|
|
const logRegex = /^(?:\\[(\\w+)\\]\\s)?([\\d\\-]+\\s[\\d:]+)\\s-\\s([\\w\\.]+)\\s-\\s(\\w+)\\s-\\s(.*)$/;
|
|
|
|
// ✅ FIXED
|
|
const logRegex = /^(?:\[(\w+)\]\s)?([^\s]+\s[^\s]+)\s-\s([\w\.]+)\s-\s(\w+)\s-\s(.*)$/;
|
|
```
|
|
**File:** `/frontend/static/js/new-main.js` - `connectEventSource()` method
|
|
|
|
### 2. DEBUG Log Filtering Race Condition
|
|
**Symptoms:** DEBUG logs appear in wrong filters (Info, Warning, Error)
|
|
**Root Cause:** EventSource adds logs without checking current filter
|
|
**Fix:** Apply filter to new entries as they arrive
|
|
```javascript
|
|
// In EventSource onmessage handler, after appendChild:
|
|
const currentLogLevel = this.elements.logLevelSelect ? this.elements.logLevelSelect.value : 'all';
|
|
if (currentLogLevel !== 'all') {
|
|
this.applyFilterToSingleEntry(logEntry, currentLogLevel);
|
|
}
|
|
```
|
|
**File:** `/frontend/static/js/new-main.js` - `connectEventSource()` method
|
|
|
|
### 3. Database Connection Issues
|
|
**Symptoms:** "Database error", "No such table", settings not persisting
|
|
**Root Cause:** Database path issues or missing tables
|
|
**Fix:** Use DatabaseManager with environment detection
|
|
```python
|
|
# ❌ BROKEN - Direct SQLite calls with hardcoded paths
|
|
import sqlite3
|
|
conn = sqlite3.connect('/config/huntarr.db')
|
|
|
|
# ✅ FIXED - Use DatabaseManager with auto-detection
|
|
from src.primary.utils.database import DatabaseManager
|
|
db = DatabaseManager()
|
|
db.get_setting('sonarr', 'api_key')
|
|
```
|
|
**Debug Steps:**
|
|
1. Check database exists: `docker exec huntarr ls -la /config/huntarr.db`
|
|
2. Verify tables: `docker exec huntarr sqlite3 /config/huntarr.db ".tables"`
|
|
3. Check environment detection: Look for `/config` directory existence
|
|
4. Test local vs Docker paths: `./data/huntarr.db` vs `/config/huntarr.db`
|
|
|
|
### 4. Hard-Coded Path Issues (Legacy)
|
|
**Symptoms:** "Error Loading" on bare metal, works in Docker
|
|
**Root Cause:** Hard-coded Docker paths don't exist on bare metal
|
|
**Fix:** Environment detection pattern (now handled by DatabaseManager)
|
|
```python
|
|
# ❌ LEGACY - Old JSON file approach
|
|
def _detect_environment():
|
|
return os.path.exists('/config') and os.path.exists('/app')
|
|
|
|
def _get_paths():
|
|
if _detect_environment():
|
|
return {'data': '/config/tally/sleep.json'}
|
|
else:
|
|
base_dir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
return {'data': os.path.join(base_dir, 'data', 'tally', 'sleep.json')}
|
|
|
|
# ✅ NEW - Database approach
|
|
from src.primary.utils.database import DatabaseManager
|
|
db = DatabaseManager() # Automatically detects environment and uses correct database path
|
|
```
|
|
|
|
### 4. JavaScript Variable Undefined Errors
|
|
**Symptoms:** `ReferenceError: variableName is not defined` in settings
|
|
**Root Cause:** Missing variable declarations in form generation
|
|
**Fix:** Ensure all variables are declared before use
|
|
```javascript
|
|
generateAppForm: function(container, settings = {}) {
|
|
let instancesHtml = `...`;
|
|
let searchSettingsHtml = `...`; // CRITICAL - must declare
|
|
container.innerHTML = instancesHtml + searchSettingsHtml;
|
|
}
|
|
```
|
|
**File:** `/frontend/static/js/settings_forms.js`
|
|
|
|
### 5. Subpath Compatibility Breaks
|
|
**Symptoms:** Works at root domain but fails in subdirectories
|
|
**Root Cause:** Absolute URLs in JavaScript/templates
|
|
**Fix:** Use relative URLs everywhere
|
|
```javascript
|
|
// ❌ BROKEN
|
|
window.location.href = '/';
|
|
fetch('/api/endpoint');
|
|
|
|
// ✅ FIXED
|
|
window.location.href = './';
|
|
fetch('./api/endpoint');
|
|
```
|
|
|
|
### 6. CSS Loading Order/Specificity Issues
|
|
**Symptoms:** Inline component CSS styles not applying, especially mobile responsive changes
|
|
**Root Cause:** External CSS files (`responsive-fix.css`, `new-style.css`) load after component templates and override inline styles
|
|
**Fix:** Add critical responsive CSS to external files with higher specificity
|
|
```css
|
|
/* ❌ BROKEN - Inline component CSS gets overridden */
|
|
<!-- In component template -->
|
|
<style>
|
|
.app-stats-card.swaparr .stats-numbers {
|
|
grid-template-columns: 1fr !important;
|
|
}
|
|
</style>
|
|
|
|
/* ✅ FIXED - Add to external CSS file */
|
|
/* File: frontend/static/css/responsive-fix.css */
|
|
@media (max-width: 768px) {
|
|
.app-stats-card.swaparr .stats-numbers {
|
|
display: grid !important;
|
|
grid-template-columns: 1fr !important;
|
|
/* Debug border for testing */
|
|
border: 2px solid lime !important;
|
|
}
|
|
}
|
|
```
|
|
**Debugging Technique:** Use colored debug borders to confirm CSS is loading
|
|
**Files:** `/frontend/static/css/responsive-fix.css`, `/frontend/static/css/new-style.css`
|
|
|
|
### 7. Info Icon Documentation Link Issues
|
|
**Symptoms:** Info icons (i) linking to wrong domains, localhost, or broken forum links
|
|
**Root Cause:** Hard-coded old links instead of GitHub documentation links
|
|
**Fix:** Use proper GitHub documentation pattern with specific anchors
|
|
```javascript
|
|
// ❌ BROKEN - Old forum or localhost links
|
|
<label><a href="https://huntarr.io/threads/name-field.18/" class="info-icon">
|
|
<label><a href="/Huntarr.io/docs/#/configuration" class="info-icon">
|
|
<label><a href="#" class="info-icon">
|
|
|
|
// ✅ FIXED - GitHub documentation with anchors
|
|
<label><a href="https://plexguide.github.io/Huntarr.io/apps/radarr.html#instances" class="info-icon">
|
|
<label><a href="https://plexguide.github.io/Huntarr.io/apps/radarr.html#skip-future-movies" class="info-icon">
|
|
<label><a href="https://plexguide.github.io/Huntarr.io/apps/swaparr.html#enable-swaparr" class="info-icon">
|
|
```
|
|
**Pattern:** `https://plexguide.github.io/Huntarr.io/apps/[app-name].html#[anchor]`
|
|
**Requirements:**
|
|
- Always use `https://plexguide.github.io/Huntarr.io/` domain
|
|
- Include `target="_blank" rel="noopener"` attributes
|
|
- Use specific anchors that match documentation headers
|
|
- Ensure documentation anchors exist before linking
|
|
**File:** `/frontend/static/js/settings_forms.js`
|
|
|
|
### 8. GitHub API Rate Limiting & Timeout Issues
|
|
**Symptoms:** Sponsor sections showing timeouts, empty data, or rate limit errors
|
|
**Root Cause:** Direct GitHub API calls from each installation hitting rate limits
|
|
**Fix:** Use GitHub Actions + static manifest approach (Matthieu's solution)
|
|
```python
|
|
# ❌ BROKEN - Direct API calls from each installation
|
|
response = requests.post('https://api.github.com/graphql', json={'query': query}, headers=headers)
|
|
|
|
# ✅ FIXED - Fetch from static manifest updated by GitHub Actions
|
|
response = requests.get("https://plexguide.github.io/Huntarr.io/manifest.json", timeout=10)
|
|
manifest_data = response.json()
|
|
sponsors = manifest_data.get('sponsors', [])
|
|
```
|
|
**Solution Pattern:**
|
|
1. **GitHub Action** runs on releases + daily schedule
|
|
2. **Fetches sponsors** using authenticated GraphQL API
|
|
3. **Publishes manifest.json** to GitHub Pages with sponsors + version data
|
|
4. **Installations fetch** from static manifest (no authentication needed)
|
|
5. **No rate limits** since only the GitHub Action hits the API
|
|
|
|
**Benefits:**
|
|
- Each installation doesn't need GitHub API access
|
|
- No rate limiting issues for users
|
|
- Faster response times (static file vs API call)
|
|
- Automatic updates via GitHub Actions
|
|
- Fallback to cached data if manifest unavailable
|
|
|
|
**Files:**
|
|
- `.github/workflows/update-manifest.yml` - GitHub Action workflow
|
|
- `src/primary/web_server.py` - Backend API endpoint
|
|
- GitHub Pages serves `manifest.json` automatically
|
|
|
|
## 🗄️ DATABASE ARCHITECTURE (SQLite Migration Complete)
|
|
|
|
### Overview
|
|
**Huntarr has migrated from JSON files to SQLite database for all persistent data storage.**
|
|
|
|
**Database Location:**
|
|
- **Docker:** `/config/huntarr.db` (persistent volume)
|
|
- **Local Development:** `{project_root}/data/huntarr.db`
|
|
- **Auto-detection:** Uses environment detection to choose correct path
|
|
|
|
### Database Tables & Schema
|
|
```sql
|
|
-- Settings storage (replaces settings.json)
|
|
CREATE TABLE settings (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
app_name TEXT NOT NULL,
|
|
setting_key TEXT NOT NULL,
|
|
setting_value TEXT NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(app_name, setting_key)
|
|
);
|
|
|
|
-- Stateful management (replaces stateful.json)
|
|
CREATE TABLE stateful_data (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
app_name TEXT NOT NULL UNIQUE,
|
|
data TEXT NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Tally/sleep data (replaces tally/sleep.json files)
|
|
CREATE TABLE tally_data (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
app_name TEXT NOT NULL UNIQUE,
|
|
data TEXT NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- History tracking (replaces history.json)
|
|
CREATE TABLE history (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
app_name TEXT NOT NULL,
|
|
action TEXT NOT NULL,
|
|
details TEXT,
|
|
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Scheduler data (replaces scheduler.json)
|
|
CREATE TABLE scheduler_data (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
app_name TEXT NOT NULL UNIQUE,
|
|
data TEXT NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- State management (replaces state.json)
|
|
CREATE TABLE state_data (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
app_name TEXT NOT NULL UNIQUE,
|
|
data TEXT NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
|
|
-- Reset requests (replaces reset_requests.json)
|
|
CREATE TABLE reset_requests (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
app_name TEXT NOT NULL,
|
|
request_data TEXT NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
```
|
|
|
|
### Database Manager (`src/primary/utils/database.py`)
|
|
**Core database operations with automatic environment detection:**
|
|
|
|
```python
|
|
class DatabaseManager:
|
|
def _get_database_path(self):
|
|
"""Auto-detect environment and return appropriate database path"""
|
|
if os.path.exists('/config'): # Docker environment
|
|
return '/config/huntarr.db'
|
|
else: # Local development
|
|
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
|
|
return os.path.join(project_root, 'data', 'huntarr.db')
|
|
|
|
def get_setting(self, app_name, setting_key, default=None)
|
|
def set_setting(self, app_name, setting_key, setting_value)
|
|
def get_stateful_data(self, app_name, default=None)
|
|
def set_stateful_data(self, app_name, data)
|
|
# ... other methods for each table
|
|
```
|
|
|
|
### Local Development Setup
|
|
```bash
|
|
# 1. Set up Python virtual environment
|
|
cd /Users/home/Huntarr/Huntarr.io
|
|
python3 -m venv venv
|
|
source venv/bin/activate # On Windows: venv\Scripts\activate
|
|
|
|
# 2. Install dependencies
|
|
pip install -r requirements.txt
|
|
|
|
# 3. Database will be auto-created at: ./data/huntarr.db
|
|
# 4. Run locally for development
|
|
python main.py
|
|
|
|
# 5. For Docker testing
|
|
docker-compose down && COMPOSE_BAKE=true docker-compose up -d --build
|
|
```
|
|
|
|
### Migration Status
|
|
**✅ COMPLETED MIGRATIONS:**
|
|
- Settings management (settings.json → settings table)
|
|
- Stateful data (stateful.json → stateful_data table)
|
|
- Tally/sleep data (tally/*.json → tally_data table)
|
|
- History tracking (history.json → history table)
|
|
- Scheduler data (scheduler.json → scheduler_data table)
|
|
- State management (state.json → state_data table)
|
|
- Reset requests (reset_requests.json → reset_requests table)
|
|
|
|
**🗑️ REMOVED FILES:**
|
|
- All JSON files in `/data/` directory
|
|
- Migration utilities (`db_manager.py`, `migrate_configs.py`)
|
|
- Test files for migration process
|
|
|
|
### Database Debugging Commands
|
|
```bash
|
|
# Access database in Docker container
|
|
docker exec -it huntarr sqlite3 /config/huntarr.db
|
|
|
|
# Common queries for debugging
|
|
.tables # List all tables
|
|
.schema settings # Show table schema
|
|
SELECT * FROM settings WHERE app_name='sonarr'; # Check app settings
|
|
SELECT COUNT(*) FROM history; # Check history entries
|
|
SELECT app_name, COUNT(*) FROM settings GROUP BY app_name; # Settings per app
|
|
|
|
# Check database file size and location
|
|
docker exec huntarr ls -la /config/huntarr.db
|
|
docker exec huntarr du -h /config/huntarr.db
|
|
```
|
|
|
|
### Database Best Practices
|
|
1. **Always use DatabaseManager class** - Never direct SQLite calls
|
|
2. **Environment detection is automatic** - Don't hardcode paths
|
|
3. **JSON data stored as TEXT** - Complex data serialized as JSON strings
|
|
4. **Timestamps are automatic** - created_at/updated_at handled by database
|
|
5. **Unique constraints prevent duplicates** - app_name combinations are unique
|
|
6. **Transactions for consistency** - DatabaseManager handles commit/rollback
|
|
|
|
## 💾 BACKUP & RESTORE SYSTEM
|
|
|
|
### Overview
|
|
**Huntarr includes a comprehensive backup and restore system for database protection and recovery.**
|
|
|
|
**Key Features:**
|
|
- **Automatic scheduled backups** based on user-defined frequency
|
|
- **Manual backup creation** with progress tracking
|
|
- **Multi-database backup** (huntarr.db, logs.db, manager.db)
|
|
- **Database integrity verification** before and after operations
|
|
- **Cross-platform backup storage** with environment detection
|
|
- **Backup retention management** with automatic cleanup
|
|
- **Safe restoration** with pre-restore backup creation
|
|
|
|
### Backup Storage Structure
|
|
```
|
|
/config/backups/ # Docker environment
|
|
├── scheduled_backup_2025-08-24_02-05-16/ # Backup folder (timestamp-based)
|
|
│ ├── backup_info.json # Backup metadata
|
|
│ ├── huntarr.db # Main database backup
|
|
│ ├── logs.db # Logs database backup
|
|
│ └── manager.db # Manager database backup (if exists)
|
|
└── manual_backup_2025-08-24_14-30-00/ # Manual backup folder
|
|
├── backup_info.json
|
|
└── [database files...]
|
|
```
|
|
|
|
**Storage Locations:**
|
|
- **Docker:** `/config/backups/` (persistent volume)
|
|
- **Windows:** `%APPDATA%/Huntarr/backups/`
|
|
- **Local Development:** `{project_root}/data/backups/`
|
|
|
|
### Backup System Architecture
|
|
|
|
#### **BackupManager Class** (`src/routes/backup_routes.py`)
|
|
```python
|
|
class BackupManager:
|
|
def create_backup(self, backup_type='manual', name=None) # Creates verified backup
|
|
def restore_backup(self, backup_id) # Restores with pre-backup
|
|
def list_backups(self) # Lists available backups
|
|
def delete_backup(self, backup_id) # Deletes specific backup
|
|
def get_backup_settings(self) # Gets user settings
|
|
def save_backup_settings(self, settings) # Saves user settings
|
|
def _cleanup_old_backups(self) # Retention management
|
|
```
|
|
|
|
#### **BackupScheduler Class** (`src/routes/backup_routes.py`)
|
|
```python
|
|
class BackupScheduler:
|
|
def start(self) # Starts background scheduler thread
|
|
def stop(self) # Gracefully stops scheduler
|
|
def _should_create_backup(self) # Checks if backup is due
|
|
def _scheduler_loop(self) # Main scheduling loop (hourly checks)
|
|
```
|
|
|
|
### API Endpoints
|
|
```python
|
|
# Backup Settings
|
|
GET/POST /api/backup/settings # Get/set backup frequency & retention
|
|
|
|
# Backup Operations
|
|
POST /api/backup/create # Create manual backup
|
|
GET /api/backup/list # List available backups
|
|
POST /api/backup/restore # Restore from backup
|
|
POST /api/backup/delete # Delete specific backup
|
|
GET /api/backup/next-scheduled # Get next scheduled backup time
|
|
|
|
# Destructive Operations
|
|
POST /api/backup/delete-database # Delete current database (testing/reset)
|
|
```
|
|
|
|
### Frontend Integration
|
|
|
|
#### **Settings Navigation** (`frontend/templates/components/sidebar.html`)
|
|
```html
|
|
<!-- Added to Settings Sidebar -->
|
|
<a href="./#backup-restore" class="nav-item" id="settingsBackupRestoreNav">
|
|
<div class="nav-icon-wrapper">
|
|
<i class="fas fa-database"></i>
|
|
</div>
|
|
<span>Backup / Restore</span>
|
|
</a>
|
|
```
|
|
|
|
#### **Section Handling** (`frontend/static/js/new-main.js`)
|
|
```javascript
|
|
// CRITICAL: backup-restore must be included in settings sections
|
|
if (this.currentSection === 'settings' || this.currentSection === 'scheduling' ||
|
|
this.currentSection === 'notifications' || this.currentSection === 'backup-restore' ||
|
|
this.currentSection === 'user') {
|
|
this.showSettingsSidebar();
|
|
}
|
|
|
|
// Section initialization
|
|
} else if (section === 'backup-restore' && document.getElementById('backupRestoreSection')) {
|
|
document.getElementById('backupRestoreSection').classList.add('active');
|
|
document.getElementById('backupRestoreSection').style.display = 'block';
|
|
if (document.getElementById('settingsBackupRestoreNav'))
|
|
document.getElementById('settingsBackupRestoreNav').classList.add('active');
|
|
this.currentSection = 'backup-restore';
|
|
this.showSettingsSidebar();
|
|
this.initializeBackupRestore();
|
|
}
|
|
```
|
|
|
|
#### **JavaScript Module** (`frontend/static/js/backup-restore.js`)
|
|
```javascript
|
|
const BackupRestore = {
|
|
initialize: function() // Main initialization
|
|
createManualBackup: function() // Manual backup with progress
|
|
restoreBackup: function() // Restore with confirmations
|
|
deleteDatabase: function() # Destructive operation with safeguards
|
|
loadBackupList: function() // Refresh backup list
|
|
validateRestoreConfirmation: function() // "RESTORE" confirmation
|
|
validateDeleteConfirmation: function() // "huntarr" confirmation
|
|
}
|
|
```
|
|
|
|
### Safety & Security Features
|
|
|
|
#### **Multi-Level Confirmations**
|
|
1. **Restore Operations:**
|
|
- Select backup from dropdown
|
|
- Type "RESTORE" to enable button
|
|
- Final browser confirmation dialog
|
|
- Pre-restore backup creation
|
|
|
|
2. **Database Deletion:**
|
|
- Type "huntarr" to enable deletion
|
|
- Final browser confirmation dialog
|
|
- Multiple warning messages
|
|
|
|
#### **Data Integrity**
|
|
```python
|
|
def _verify_database_integrity(self, db_path):
|
|
"""Verify database integrity using SQLite PRAGMA"""
|
|
conn = sqlite3.connect(db_path)
|
|
result = conn.execute("PRAGMA integrity_check").fetchone()
|
|
return result and result[0] == "ok"
|
|
```
|
|
|
|
#### **Backup Verification Process**
|
|
1. **Pre-backup:** Force WAL checkpoint
|
|
2. **During backup:** Copy all database files
|
|
3. **Post-backup:** Verify each backup file integrity
|
|
4. **Cleanup:** Remove corrupted backups automatically
|
|
|
|
### Configuration & Settings
|
|
|
|
#### **Default Settings**
|
|
```python
|
|
backup_settings = {
|
|
'frequency': 3, # Days between automatic backups
|
|
'retention': 3 # Number of backups to keep
|
|
}
|
|
```
|
|
|
|
#### **Settings Storage** (Database)
|
|
```sql
|
|
-- Stored in general_settings table
|
|
INSERT INTO general_settings (setting_key, setting_value) VALUES
|
|
('backup_frequency', '3'),
|
|
('backup_retention', '3'),
|
|
('last_backup_time', '2025-08-24T02:05:16');
|
|
```
|
|
|
|
### Troubleshooting Backup Issues
|
|
|
|
#### **Common Problems & Solutions**
|
|
|
|
1. **Backup Directory Not Writable**
|
|
```python
|
|
# System falls back to alternative locations
|
|
# Windows: Documents/Huntarr/ if AppData fails
|
|
# Check logs for "Database directory not writable"
|
|
```
|
|
|
|
2. **Database Corruption During Backup**
|
|
```bash
|
|
# Check integrity manually
|
|
docker exec huntarr sqlite3 /config/huntarr.db "PRAGMA integrity_check"
|
|
|
|
# Backup system auto-detects and handles corruption
|
|
# Creates corrupted_backup_[timestamp].db for recovery
|
|
```
|
|
|
|
3. **Scheduler Not Running**
|
|
```bash
|
|
# Check logs for scheduler startup
|
|
docker logs huntarr | grep -i "backup scheduler"
|
|
|
|
# Should see: "Backup scheduler started"
|
|
```
|
|
|
|
4. **Restore Failures**
|
|
```python
|
|
# System creates pre-restore backup automatically
|
|
# Check /config/backups/ for pre_restore_backup_[timestamp] folders
|
|
# Original data preserved even if restore fails
|
|
```
|
|
|
|
#### **Debugging Commands**
|
|
```bash
|
|
# Check backup directory
|
|
docker exec huntarr ls -la /config/backups/
|
|
|
|
# Verify backup integrity
|
|
docker exec huntarr sqlite3 /config/backups/[backup_folder]/huntarr.db "PRAGMA integrity_check"
|
|
|
|
# Check backup settings
|
|
docker exec huntarr sqlite3 /config/huntarr.db "SELECT * FROM general_settings WHERE setting_key LIKE 'backup_%'"
|
|
|
|
# Monitor backup scheduler
|
|
docker logs huntarr | grep -i backup
|
|
```
|
|
|
|
### Development Guidelines for Backup System
|
|
|
|
#### **Adding New Database Files**
|
|
```python
|
|
def _get_all_database_paths(self):
|
|
"""Update this method when adding new database files"""
|
|
databases = {
|
|
'huntarr': str(main_db_path),
|
|
'logs': str(logs_db_path),
|
|
'manager': str(manager_db_path),
|
|
'new_db': str(new_db_path) # Add new databases here
|
|
}
|
|
return databases
|
|
```
|
|
|
|
#### **Backup Metadata Format**
|
|
```json
|
|
{
|
|
"id": "backup_name",
|
|
"name": "backup_name",
|
|
"type": "manual|scheduled|pre-restore",
|
|
"timestamp": "2025-08-24T02:05:16",
|
|
"databases": [
|
|
{
|
|
"name": "huntarr",
|
|
"size": 249856,
|
|
"path": "/config/backups/backup_name/huntarr.db"
|
|
}
|
|
],
|
|
"size": 1331200
|
|
}
|
|
```
|
|
|
|
#### **Critical Requirements**
|
|
1. **Always verify backup integrity** before considering backup complete
|
|
2. **Create pre-restore backup** before any restore operation
|
|
3. **Use cross-platform paths** - never hardcode `/config/`
|
|
4. **Handle backup corruption gracefully** with user notifications
|
|
5. **Implement proper cleanup** based on retention settings
|
|
6. **Provide clear user feedback** for all operations
|
|
|
|
## 🔧 DEVELOPMENT WORKFLOW
|
|
|
|
### Before Any Changes
|
|
- [ ] Check current working directory: `/Users/home/Huntarr/Huntarr.io`
|
|
- [ ] Ensure you're on correct branch
|
|
- [ ] Review .github/listen.md for latest patterns
|
|
- [ ] **NEW:** Activate venv for local development: `source venv/bin/activate`
|
|
|
|
### Making Changes
|
|
- [ ] Edit source code (never modify inside container)
|
|
- [ ] **For local testing:** `python main.py` (uses ./data/huntarr.db)
|
|
- [ ] **For Docker testing:** `docker-compose down && COMPOSE_BAKE=true docker-compose up -d --build`
|
|
- [ ] Check logs: `docker logs huntarr`
|
|
- [ ] **NEW:** Verify database operations work in both environments
|
|
- [ ] Test functionality
|
|
|
|
### Before Committing
|
|
- [ ] Test in Docker environment (database at /config/huntarr.db)
|
|
- [ ] Test in local environment (database at ./data/huntarr.db)
|
|
- [ ] Test cross-platform compatibility
|
|
- [ ] Test subpath scenarios (`domain.com/huntarr/`)
|
|
- [ ] Check browser console for errors
|
|
- [ ] **NEW:** Verify database persistence across container restarts
|
|
- [ ] **NEW:** Test backup/restore functionality if modified:
|
|
- [ ] Verify backup creation and integrity
|
|
- [ ] Test backup scheduler startup
|
|
- [ ] Verify backup directory creation (`/config/backups/`)
|
|
- [ ] Test restore confirmation workflow
|
|
- [ ] Get user approval before committing
|
|
|
|
### Proactive Violation Scanning
|
|
**Run these before every release to catch violations early:**
|
|
```bash
|
|
# 1. Absolute URL violations (most critical for subpath deployment)
|
|
echo "=== SCANNING FOR ABSOLUTE URL VIOLATIONS ==="
|
|
grep -r "fetch('/api/" frontend/ --include="*.js" | wc -l | xargs echo "fetch() absolute URLs:"
|
|
grep -r "window.location.href.*= '/" frontend/ --include="*.js" --include="*.html" | wc -l | xargs echo "redirect absolute URLs:"
|
|
|
|
# 2. Documentation link violations
|
|
echo "=== SCANNING FOR DOCUMENTATION LINK VIOLATIONS ==="
|
|
grep -r "href.*plexguide.github.io" frontend/ --include="*.js" | grep -v "plexguide.github.io/Huntarr.io" | wc -l | xargs echo "wrong domain links:"
|
|
|
|
# 3. Hard-coded path violations
|
|
echo "=== SCANNING FOR HARD-CODED PATH VIOLATIONS ==="
|
|
grep -r "/config" src/ --include="*.py" | grep -v "_detect_environment\|_get.*path" | wc -l | xargs echo "hard-coded /config paths:"
|
|
grep -r "/app" src/ --include="*.py" | grep -v "_detect_environment\|_get.*path" | wc -l | xargs echo "hard-coded /app paths:"
|
|
|
|
# 4. Frontend-docs alignment check
|
|
echo "=== CHECKING FRONTEND-DOCS ALIGNMENT ==="
|
|
echo "Frontend anchor references:"
|
|
grep -r "href.*plexguide\.github\.io.*#" frontend/static/js/ | grep -o "#[^\"]*" | sort | uniq | wc -l
|
|
echo "Documentation anchors available:"
|
|
grep -r 'id="[^"]*"' docs/apps/ | grep -o 'id="[^"]*"' | sort | uniq | wc -l
|
|
```
|
|
|
|
### Database & Path Hunting Commands
|
|
```bash
|
|
# Search for database violations
|
|
grep -r "sqlite3.connect\|import sqlite3" src/ --include="*.py" | grep -v "database.py"
|
|
grep -r "\.json\|json.load\|json.dump" src/ --include="*.py" | grep -v "requests.*json\|response.json\|Content-Type.*json"
|
|
grep -r "/config/.*\.db\|/app/.*\.db" src/ --include="*.py" | grep -v "DatabaseManager\|_get_database_path"
|
|
|
|
# Search for legacy hard-coded paths
|
|
grep -r "/config" src/ --include="*.py" | grep -v "_detect_environment\|_get.*path\|DatabaseManager"
|
|
grep -r "/app" src/ --include="*.py" | grep -v "_detect_environment\|_get.*path\|DatabaseManager"
|
|
|
|
# Search for frontend URL violations
|
|
grep -r "href=\"/" frontend/
|
|
grep -r "window.location.href = '/" frontend/
|
|
grep -r "fetch('/api/" frontend/ --include="*.js"
|
|
```
|
|
|
|
## 📁 KEY FILE LOCATIONS
|
|
|
|
### Backend Core
|
|
- `/src/routes.py` - API endpoints
|
|
- `/src/primary/cycle_tracker.py` - Timer functionality
|
|
- `/src/primary/utils/logger.py` - Logging configuration
|
|
- `/src/primary/utils/database.py` - **NEW:** DatabaseManager class (replaces settings_manager.py)
|
|
- `/src/routes/backup_routes.py` - **NEW:** Backup & Restore API endpoints and BackupManager
|
|
|
|
### Frontend Core
|
|
- `/frontend/static/js/new-main.js` - Main UI logic
|
|
- `/frontend/static/js/settings_forms.js` - Settings forms
|
|
- `/frontend/static/js/backup-restore.js` - **NEW:** Backup & Restore functionality
|
|
- `/frontend/templates/components/` - UI components
|
|
- `/frontend/templates/components/backup_restore_section.html` - **NEW:** Backup & Restore UI
|
|
|
|
### Database & Storage
|
|
- `/config/huntarr.db` - **Docker:** Main database file (persistent)
|
|
- `./data/huntarr.db` - **Local:** Main database file (development)
|
|
- `/config/backups/` - **Docker:** Backup storage directory (persistent)
|
|
- `./data/backups/` - **Local:** Backup storage directory (development)
|
|
- `/src/primary/utils/database.py` - DatabaseManager with auto-detection
|
|
- **REMOVED:** All JSON files (settings.json, stateful.json, etc.)
|
|
|
|
### Critical Files for Cross-Platform
|
|
- `/src/primary/utils/database.py` - **NEW:** Database operations with environment detection
|
|
- `/src/primary/cycle_tracker.py` - Timer functionality (now uses database)
|
|
- Any `*_routes.py` files
|
|
|
|
## 🎯 DEBUGGING QUICK REFERENCE
|
|
|
|
### Systematic Issue Discovery
|
|
**When things don't work, don't guess - scan systematically:**
|
|
```bash
|
|
# 1. Check for violation patterns first
|
|
./violation_scan.sh # From proactive practices above
|
|
|
|
# 2. Specific issue hunting
|
|
grep -r "EXACT_ERROR_TEXT" frontend/ src/ --include="*.js" --include="*.py"
|
|
grep -r "functionName\|variableName" frontend/ --include="*.js"
|
|
```
|
|
|
|
### Subpath Deployment Issues
|
|
**Symptoms:** Works on localhost, fails on domain.com/huntarr/
|
|
**Root Cause:** Absolute URLs that don't work in subdirectories
|
|
**Debug Process:**
|
|
1. Check browser network tab for 404s on absolute URLs
|
|
2. Search for absolute patterns: `grep -r "fetch('/api" frontend/`
|
|
3. Check redirects: `grep -r "window.location.href.*= '/" frontend/`
|
|
4. Verify all URLs are relative: `./api/` not `/api/`
|
|
|
|
### Frontend-Documentation Link Issues
|
|
**Symptoms:** Info icons (i) lead to 404 or wrong pages
|
|
**Root Cause:** Mismatched frontend links vs documentation anchors
|
|
**Debug Process:**
|
|
1. Extract frontend anchor references: `grep -r "href.*#" frontend/static/js/ | grep -o "#[^\"]*"`
|
|
2. Extract doc anchors: `grep -r 'id="[^"]*"' docs/ | grep -o 'id="[^"]*"'`
|
|
3. Compare lists to find mismatches
|
|
4. Add missing anchors or fix links
|
|
|
|
### Log Issues
|
|
1. Check logs in database: `docker exec huntarr python3 -c "import sys; sys.path.insert(0, '/app/src'); from primary.utils.logs_database import get_logs_database; db = get_logs_database(); logs = db.get_logs(limit=10); [print(f'{log[\"timestamp\"]} - {log[\"app_type\"]} - {log[\"level\"]} - {log[\"message\"]}') for log in logs]"`
|
|
2. Test backend streaming: `curl -N -s "http://localhost:9705/logs?app=[app]"`
|
|
3. Check browser console for JavaScript errors
|
|
4. Verify regex patterns in `new-main.js`
|
|
|
|
### Database Issues
|
|
1. **Check database exists and is accessible:**
|
|
```bash
|
|
# Docker environment
|
|
docker exec huntarr ls -la /config/huntarr.db
|
|
docker exec huntarr sqlite3 /config/huntarr.db ".tables"
|
|
|
|
# Local environment
|
|
ls -la ./data/huntarr.db
|
|
sqlite3 ./data/huntarr.db ".tables"
|
|
```
|
|
|
|
2. **Verify table schemas and data:**
|
|
```bash
|
|
# Check specific table structure
|
|
docker exec huntarr sqlite3 /config/huntarr.db ".schema settings"
|
|
|
|
# Check data exists
|
|
docker exec huntarr sqlite3 /config/huntarr.db "SELECT COUNT(*) FROM settings;"
|
|
docker exec huntarr sqlite3 /config/huntarr.db "SELECT app_name, COUNT(*) FROM settings GROUP BY app_name;"
|
|
```
|
|
|
|
3. **Test DatabaseManager operations:**
|
|
```python
|
|
# In Python console or test script
|
|
from src.primary.utils.database import DatabaseManager
|
|
db = DatabaseManager()
|
|
|
|
# Test basic operations
|
|
db.set_setting('test_app', 'test_key', 'test_value')
|
|
result = db.get_setting('test_app', 'test_key')
|
|
print(f"Database test result: {result}")
|
|
```
|
|
|
|
4. **Check environment detection:**
|
|
```python
|
|
import os
|
|
print(f"Docker environment detected: {os.path.exists('/config')}")
|
|
print(f"Database path would be: {'/config/huntarr.db' if os.path.exists('/config') else './data/huntarr.db'}")
|
|
```
|
|
|
|
5. **Database migration verification:**
|
|
```bash
|
|
# Ensure no old JSON files exist
|
|
find . -name "*.json" -path "./data/*" 2>/dev/null || echo "No JSON files found (good)"
|
|
|
|
# Check database size (should be > 0 if data exists)
|
|
docker exec huntarr du -h /config/huntarr.db
|
|
```
|
|
|
|
### Path Issues (Legacy)
|
|
1. Check environment detection logic
|
|
2. Verify paths exist in target environment
|
|
3. Test with both Docker and bare metal
|
|
4. Check file permissions
|
|
5. **LEGACY:** Scan for hard-coded paths: `grep -r "/config\|/app" src/ | grep -v "_detect_environment"`
|
|
6. **NEW:** Use DatabaseManager instead of direct file operations
|
|
|
|
### JavaScript Issues
|
|
1. Check browser console for errors
|
|
2. Search for undefined variables: `grep -r "variableName" frontend/`
|
|
3. Verify HTML structure matches selectors
|
|
4. Compare with working functions
|
|
5. **NEW:** Check for absolute URL patterns causing 404s in subpaths
|
|
|
|
### CSS Issues
|
|
1. Check browser console for errors
|
|
2. Add debug borders: `border: 2px solid lime !important;`
|
|
3. Verify CSS loading order (external files vs inline)
|
|
4. Test specificity with `!important` declarations
|
|
5. Search for conflicting rules: `grep -r "className" frontend/static/css/`
|
|
|
|
### Settings Issues
|
|
1. Check form generation functions
|
|
2. Verify `getFormSettings()` method
|
|
3. Test save/load cycle
|
|
4. Check API endpoints
|
|
5. **NEW:** Verify info icon links point to existing documentation anchors
|
|
|
|
### Documentation Issues
|
|
**Symptoms:** Broken links, 404s, outdated information
|
|
**Debug Process:**
|
|
1. Test all links manually or with link checker
|
|
2. Verify features mentioned actually exist in codebase
|
|
3. Check frontend alignment with documentation
|
|
4. Audit FAQ against real support requests
|
|
|
|
## 📊 RECENT IMPROVEMENTS
|
|
|
|
### Systematic Code Violation Fixes (2024-12)
|
|
**Issue:** 71 systematic code violations discovered through comprehensive codebase analysis
|
|
**Root Cause:** Lack of proactive violation scanning and systematic fixing approach
|
|
**Solution:** Implemented systematic approach to finding and fixing violations
|
|
|
|
**Fixed Violations:**
|
|
1. **51 absolute fetch URLs** - All `/api/` calls converted to `./api/` for subpath compatibility
|
|
2. **15 outdated documentation links** - Fixed old domain references in settings_forms.js
|
|
3. **5 window.location.href absolute URLs** - Converted `/` redirects to `./`
|
|
4. **Missing documentation anchors** - Added proper IDs to all referenced doc sections
|
|
|
|
**Key Files Modified:**
|
|
- `/frontend/static/js/settings_forms.js` - Documentation links and form generation
|
|
- `/frontend/static/js/new-main.js` - URL handling and redirects
|
|
- `/frontend/static/js/apps.js` - API calls and fetch operations
|
|
- All documentation files - Added missing anchor IDs
|
|
|
|
**Prevention Strategy:** Use systematic grep searches to catch violations early:
|
|
```bash
|
|
# Catch absolute URLs before they become problems
|
|
grep -r "fetch('/api/" frontend/ --include="*.js"
|
|
grep -r "window.location.href.*= '/" frontend/ --include="*.js" --include="*.html"
|
|
grep -r "href.*plexguide.github.io" frontend/ --include="*.js" | grep -v "plexguide.github.io/Huntarr.io"
|
|
```
|
|
|
|
### Documentation Reality Check & User Experience (2024-12)
|
|
**Issue:** Documentation promised features that didn't exist (standalone logs/history pages)
|
|
**Root Cause:** Feature documentation grew organically without reality checks
|
|
**Solution:** Systematic audit of promised vs actual features
|
|
|
|
**Changes:**
|
|
- Removed broken links to non-existent logs.html and history.html
|
|
- Updated features page to reflect actual functionality (Swaparr, Search Automation)
|
|
- Completely rewrote FAQ with real-world Docker problems and practical solutions
|
|
- Added prominent community help section on homepage with proper user flow
|
|
|
|
**Lessons Learned:**
|
|
- **Document what exists, not what's planned** - Only link to documentation that actually exists
|
|
- **FAQ should solve real problems** - Base content on actual support requests, not theoretical issues
|
|
- **User journey matters** - Help → Explanation → Setup → Community is better than promotional content
|
|
|
|
### Frontend-Documentation Alignment System (2024-12)
|
|
**Issue:** Frontend info icons linked to anchors that didn't exist in documentation
|
|
**Root Cause:** No systematic checking of frontend links against actual documentation
|
|
**Solution:** Implemented verification system for frontend→docs alignment
|
|
|
|
**Process:**
|
|
1. Extract all documentation links from frontend: `grep -r "plexguide.github.io.*#" frontend/`
|
|
2. Extract all anchor IDs from docs: `grep -r 'id="[^"]*"' docs/`
|
|
3. Cross-reference and fix mismatches
|
|
4. Add missing anchor IDs where content exists but ID missing
|
|
|
|
**Prevention:** Before any documentation changes, verify link alignment:
|
|
```bash
|
|
# Extract frontend links
|
|
grep -r "href.*plexguide\.github\.io.*#" frontend/static/js/ | grep -o "#[^\"]*" | sort | uniq
|
|
|
|
# Extract doc anchors
|
|
grep -r 'id="[^"]*"' docs/apps/ | grep -o 'id="[^"]*"' | sort | uniq
|
|
|
|
# Compare results to catch mismatches
|
|
```
|
|
|
|
### Radarr Release Date Consistency (2024-12)
|
|
**Issue:** Missing movie searches respected `skip_future_releases` setting, but upgrade searches ignored it
|
|
**Solution:** Made upgrade behavior consistent with missing movie logic
|
|
**Changes:**
|
|
- Updated `src/primary/apps/radarr/upgrade.py` to check release dates
|
|
- Both missing and upgrade searches now respect `skip_future_releases` and `process_no_release_dates`
|
|
- Documentation updated to clarify behavior affects both search types
|
|
|
|
### Apps Navigation Redesign (2024-12)
|
|
**Issue:** Apps section showed a dashboard that users had to navigate through to reach individual app settings
|
|
**User Feedback:** "Instead of an apps dashboard; make it where when a user clicks apps, it goes to the sonarr apps being selected by default"
|
|
**Solution:** Direct navigation to Sonarr when clicking Apps, eliminating the dashboard step
|
|
|
|
**Implementation Changes:**
|
|
|
|
1. **Modified Apps Section Navigation** (`frontend/static/js/new-main.js`):
|
|
```javascript
|
|
// OLD: Showed apps dashboard
|
|
} else if (section === 'apps') {
|
|
document.getElementById('appsSection').classList.add('active');
|
|
// ... dashboard logic
|
|
|
|
// NEW: Direct redirect to Sonarr
|
|
} else if (section === 'apps') {
|
|
console.log('[huntarrUI] Apps section requested - redirecting to Sonarr by default');
|
|
this.switchSection('sonarr');
|
|
window.location.hash = '#sonarr';
|
|
return;
|
|
```
|
|
|
|
2. **Updated Navigation Highlighting** (`frontend/templates/components/sidebar.html`):
|
|
```javascript
|
|
// Keep "Apps" nav item active when viewing Sonarr
|
|
} else if (currentHash === '#apps' || currentHash === '#sonarr') {
|
|
selector = '#appsNav';
|
|
```
|
|
|
|
3. **Preserved Apps Sidebar Functionality**:
|
|
- Apps sidebar still provides navigation between all apps (Sonarr, Radarr, Lidarr, etc.)
|
|
- Return button allows going back to main navigation
|
|
- Individual app sections remain fully functional
|
|
|
|
**User Experience Improvements:**
|
|
- **Faster Access**: Click "Apps" → Immediately see Sonarr settings (most commonly used)
|
|
- **Intuitive Navigation**: Apps nav item stays highlighted when viewing any app
|
|
- **Preserved Functionality**: All apps still accessible via Apps sidebar
|
|
- **Consistent Behavior**: Maintains existing sidebar switching patterns
|
|
|
|
**Navigation Flow:**
|
|
```
|
|
Main Sidebar: Apps → Sonarr (default)
|
|
Apps Sidebar: Sonarr ↔ Radarr ↔ Lidarr ↔ Readarr ↔ Whisparr V2 ↔ Whisparr V3 ↔ Prowlarr
|
|
```
|
|
|
|
**Files Modified:**
|
|
- `frontend/static/js/new-main.js` - Apps section redirect logic
|
|
- `frontend/templates/components/sidebar.html` - Navigation highlighting logic
|
|
- Removed dashboard functionality from `frontend/templates/components/apps_section.html`
|
|
|
|
**Benefits:**
|
|
- Eliminates unnecessary dashboard step
|
|
- Provides direct access to most commonly used app (Sonarr)
|
|
- Maintains all existing functionality through sidebar navigation
|
|
- Improves user workflow efficiency
|
|
- Frontend info icons fixed to use GitHub documentation links
|
|
|
|
**User Benefit:** Consistent behavior - no more unexpected future movie upgrades
|
|
|
|
### Complete Database Migration (2024-12)
|
|
**Issue:** JSON file-based storage caused data loss, concurrency issues, and deployment complexity
|
|
**Root Cause:** Multiple JSON files scattered across filesystem with no transactional consistency
|
|
**Solution:** Complete migration to SQLite database with automatic environment detection
|
|
|
|
**Migration Scope:**
|
|
- **Settings:** `settings.json` → `settings` table (7 tables total)
|
|
- **Stateful Data:** `stateful.json` → `stateful_data` table
|
|
- **Tally/Sleep:** `tally/*.json` → `tally_data` table
|
|
- **History:** `history.json` → `history` table
|
|
- **Scheduler:** `scheduler.json` → `scheduler_data` table
|
|
- **State:** `state.json` → `state_data` table
|
|
- **Reset Requests:** `reset_requests.json` → `reset_requests` table
|
|
|
|
**Key Improvements:**
|
|
- **Persistent Storage:** Database survives container updates/rebuilds
|
|
- **Environment Detection:** Auto-detects Docker vs local development
|
|
- **Transactional Consistency:** ACID compliance prevents data corruption
|
|
- **Simplified Deployment:** Single database file instead of multiple JSON files
|
|
- **Better Performance:** SQLite indexing and query optimization
|
|
- **Automatic Timestamps:** created_at/updated_at handled by database
|
|
|
|
**Database Locations:**
|
|
- **Docker:** `/config/huntarr.db` (persistent volume)
|
|
- **Local:** `{project_root}/data/huntarr.db`
|
|
- **Auto-detection:** Uses `/config` directory existence to choose path
|
|
|
|
**Development Impact:**
|
|
- **Local Setup:** Added `venv` requirement for Python dependencies
|
|
- **Testing:** Must verify both Docker and local database operations
|
|
- **Debugging:** New SQLite commands for data inspection
|
|
- **No Backward Compatibility:** JSON files completely removed
|
|
|
|
**Files Modified:**
|
|
- `src/primary/utils/database.py` - New DatabaseManager class
|
|
- All app modules updated to use DatabaseManager instead of JSON
|
|
- Development workflow updated for dual-environment testing
|
|
- Removed migration utilities after completion
|
|
|
|
**User Benefits:**
|
|
- ✅ No more data loss on container recreation
|
|
- ✅ Faster application startup (no JSON parsing)
|
|
- ✅ Consistent data across app restarts
|
|
- ✅ Better error handling and recovery
|
|
- ✅ Simplified backup (single database file)
|
|
|
|
## ⚠️ ANTI-PATTERNS TO AVOID
|
|
|
|
1. **❌ Direct SQLite calls:** Use DatabaseManager class, never `sqlite3.connect()` directly
|
|
2. **❌ Hard-coded database paths:** `/config/huntarr.db` - Use DatabaseManager auto-detection
|
|
3. **❌ JSON file operations:** All data storage must use database tables
|
|
4. **❌ Absolute URLs in frontend:** `/api/endpoint`, `window.location.href = '/'`
|
|
5. **❌ Modifying files inside containers**
|
|
6. **❌ Creating temporary/helper files instead of fixing source**
|
|
7. **❌ Auto-committing without approval**
|
|
8. **❌ Double backslashes in regex patterns**
|
|
9. **❌ Testing only in Docker (must test bare metal with local database)**
|
|
10. **❌ Adding responsive CSS to component templates (use external CSS files)**
|
|
11. **❌ Not using debug borders to test CSS loading**
|
|
12. **❌ Inconsistent behavior between missing/upgrade logic** - Always check both implement same filtering
|
|
13. **❌ Reactive violation fixing** - Don't wait for problems to appear, scan proactively
|
|
14. **❌ Documentation that promises non-existent features** - Only document what actually exists
|
|
15. **❌ Frontend links without verifying documentation anchors exist** - Always cross-check
|
|
16. **❌ Organic feature growth without reality checks** - Audit promised vs actual features regularly
|
|
17. **❌ Theoretical FAQ content** - Base FAQ on real user problems and support requests
|
|
18. **❌ Skipping venv activation** - Always use virtual environment for local development
|
|
19. **❌ Not testing database persistence** - Verify data survives container restarts
|
|
|
|
## 🚨 PROACTIVE DEVELOPMENT PRACTICES
|
|
|
|
### Pre-Commit Violation Scanning
|
|
**ALWAYS run before any commit to catch violations early:**
|
|
```bash
|
|
# Create violation_scan.sh for easy reuse
|
|
echo "=== HUNTARR VIOLATION SCAN ==="
|
|
echo "1. Absolute URL violations (breaks subpath deployment):"
|
|
echo " fetch() absolute URLs: $(grep -r "fetch('/api/" frontend/ --include="*.js" | wc -l)"
|
|
echo " redirect absolute URLs: $(grep -r "window.location.href.*= '/" frontend/ --include="*.js" --include="*.html" | wc -l)"
|
|
echo ""
|
|
echo "2. Documentation violations:"
|
|
echo " Wrong domain links: $(grep -r "href.*plexguide.github.io" frontend/ --include="*.js" | grep -v "plexguide.github.io/Huntarr.io" | wc -l)"
|
|
echo ""
|
|
echo "3. Database violations:"
|
|
echo " Direct SQLite calls: $(grep -r "sqlite3.connect\|import sqlite3" src/ --include="*.py" | grep -v "database.py" | wc -l)"
|
|
echo " JSON file operations: $(grep -r "\.json\|json.load\|json.dump" src/ --include="*.py" | grep -v "requests.*json\|response.json\|Content-Type.*json" | wc -l)"
|
|
echo " Hard-coded DB paths: $(grep -r "/config/.*\.db\|/app/.*\.db" src/ --include="*.py" | grep -v "DatabaseManager\|_get_database_path" | wc -l)"
|
|
echo ""
|
|
echo "4. Legacy path violations:"
|
|
echo " /config paths: $(grep -r "/config" src/ --include="*.py" | grep -v "_detect_environment\|_get.*path\|DatabaseManager" | wc -l)"
|
|
echo " /app paths: $(grep -r "/app" src/ --include="*.py" | grep -v "_detect_environment\|_get.*path\|DatabaseManager" | wc -l)"
|
|
echo ""
|
|
echo "5. Frontend-docs alignment:"
|
|
echo " Frontend anchors: $(grep -r "href.*plexguide\.github\.io.*#" frontend/static/js/ 2>/dev/null | grep -o "#[^\"]*" | sort | uniq | wc -l)"
|
|
echo " Doc anchors: $(grep -r 'id="[^"]*"' docs/apps/ 2>/dev/null | grep -o 'id="[^"]*"' | sort | uniq | wc -l)"
|
|
echo "=== SCAN COMPLETE ==="
|
|
```
|
|
|
|
### Documentation Reality Audit Process
|
|
**Before any documentation changes:**
|
|
1. **Verify features exist**: Don't document planned features, only existing ones
|
|
2. **Check all links work**: Test every link in documentation
|
|
3. **Verify frontend alignment**: Ensure info icons point to existing anchors
|
|
4. **FAQ reality check**: Base content on actual support requests, not theoretical issues
|
|
|
|
**Commands to audit documentation:**
|
|
```bash
|
|
# 1. Find all links in documentation
|
|
grep -r "href=" docs/ | grep -v "^#" | cut -d'"' -f2 | sort | uniq
|
|
|
|
# 2. Find all frontend documentation links
|
|
grep -r "plexguide.github.io" frontend/static/js/ | grep -o "https://[^\"]*"
|
|
|
|
# 3. Check anchor mismatches
|
|
diff <(grep -r "href.*#" frontend/static/js/ | grep -o "#[^\"]*" | sort | uniq) \
|
|
<(grep -r 'id="[^"]*"' docs/ | grep -o 'id="[^"]*"' | sed 's/id="//' | sed 's/"$//' | sort | uniq)
|
|
```
|
|
|
|
### User Experience Validation
|
|
**Before major UI changes:**
|
|
1. **Test user journey**: Help → Explanation → Setup → Community
|
|
2. **Verify community links work**: Discord, GitHub Issues, Reddit
|
|
3. **Check mobile responsiveness**: Test all breakpoints
|
|
4. **Validate against real user problems**: Base features on actual use cases
|
|
|
|
## 🚀 DATABASE-FIRST DEVELOPMENT PATTERN
|
|
|
|
**Use DatabaseManager for all data operations - no direct file operations needed:**
|
|
|
|
```python
|
|
# ✅ CORRECT - Use DatabaseManager (handles environment detection automatically)
|
|
from src.primary.utils.database import DatabaseManager
|
|
|
|
db = DatabaseManager() # Auto-detects Docker vs local environment
|
|
|
|
# Settings operations
|
|
db.set_setting('sonarr', 'api_key', 'your_api_key')
|
|
api_key = db.get_setting('sonarr', 'api_key')
|
|
|
|
# Stateful data operations
|
|
db.set_stateful_data('sonarr', {'last_run': '2024-12-25'})
|
|
state = db.get_stateful_data('sonarr', {})
|
|
|
|
# History operations
|
|
db.add_history('sonarr', 'search_completed', 'Found 5 missing episodes')
|
|
history = db.get_history('sonarr', limit=10)
|
|
```
|
|
|
|
**Legacy Environment Detection (for non-database operations only):**
|
|
```python
|
|
import os
|
|
|
|
def _detect_environment():
|
|
"""Detect if running in Docker or bare metal"""
|
|
return os.path.exists('/config') # Simplified - just check /config
|
|
|
|
def _get_cross_platform_path(relative_path):
|
|
"""Get appropriate path based on environment (for logs, temp files only)"""
|
|
if _detect_environment():
|
|
# Docker environment
|
|
return os.path.join('/config', relative_path)
|
|
else:
|
|
# Bare metal environment
|
|
project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
|
return os.path.join(project_root, 'data', relative_path)
|
|
```
|
|
|
|
**Note:** Only use legacy pattern for non-database files (logs, temp files). All persistent data should use DatabaseManager.
|
|
|
|
## 📝 MEMORY GUIDELINES
|
|
|
|
**Create memories for:**
|
|
- ✅ Bug fixes with root cause analysis
|
|
- ✅ New features
|
|
- ✅ Cross-platform compatibility fixes
|
|
- ✅ Performance improvements
|
|
|
|
**Format:**
|
|
```
|
|
Title: Brief description
|
|
Content: Root cause, files modified, solution approach, testing notes
|
|
Tags: ["bug_fix", "feature", "frontend", "backend"]
|
|
```
|
|
|
|
---
|
|
|
|
*Quick reference for Huntarr development. Update when new patterns are discovered.*
|