refactor: organize codebase and remove redundant files

- Removed all backup/duplicate files
- Removed test files from root
- Consolidated documentation to /docs/
- Moved scripts to /scripts/
- Renamed f_* directories (removed prefix)
- Organized icons and assets
- Removed unused vendor directories
- Cleaned up redundant config files
This commit is contained in:
Krystie
2026-03-30 16:34:45 -07:00
parent 5dc8eacf2a
commit 092a8bc7ce
5789 changed files with 0 additions and 315506 deletions
+84
View File
@@ -0,0 +1,84 @@
# Continuous Delivery - Quick Start
## Start Auto-Deployment in 10 Seconds
```powershell
.\start-cd.ps1 watch
```
That's it! Your changes will now automatically commit and push to GitHub.
## What Happens Now?
1. Edit any file and save
2. Wait 30 seconds after your last change
3. Automatically commits with change summary
4. Automatically pushes to GitHub
5. Repeat!
## Common Commands
```powershell
# Start file watcher (recommended)
.\start-cd.ps1 watch
# Start timer mode (every 5 minutes)
.\start-cd.ps1 start
# Commit and push once, right now
.\start-cd.ps1 once
# Stop all CD processes
.\start-cd.ps1 stop
# Check git status
.\start-cd.ps1 status
```
## Example Output
```
[14:23:45] Changed: setup.php
[14:23:47] Changed: docker-compose.yml
Debounce period elapsed. Processing 2 changes...
Found 2 changed files
✓ Committed changes
✓ Successfully pushed to GitHub
Continuing to watch for changes...
```
## What Gets Auto-Committed?
- Application code (PHP, JS, CSS)
- Configuration files
- Documentation
- SQL schemas
## What's Excluded?
- Session files (`f_data/data_sessions/`)
- Cache files (`f_data/data_cache/`)
- Database files (`db_data/`)
- Log files (`*.log`)
- Dependencies (`node_modules/`, `vendor/`)
## Troubleshooting
**Not detecting changes?**
- Check if file is in `.gitignore`
**Need to stop?**
- Press `Ctrl+C` or run `.\start-cd.ps1 stop`
**Want custom settings?**
- Edit `.cd-config.json`
## Full Documentation
See [CONTINUOUS_DELIVERY_GUIDE.md](CONTINUOUS_DELIVERY_GUIDE.md) for complete documentation.
---
**Ready?** Run `.\start-cd.ps1 watch` and start coding!
+22
View File
@@ -0,0 +1,22 @@
Privacy, Data Export/Delete, and Admin Audit
This document outlines how to implement user privacy controls and admin auditing in EasyStream.
User Data Export
- Endpoint: `api/privacy.php?action=export` (requires login)
- Returns a JSON bundle of key user data (profile, uploads, subscriptions). The current implementation returns a stub template; extend to include all relevant fields.
User Data Delete (Account Deletion)
- Endpoint: `api/privacy.php?action=delete` (requires login and CSRF token)
- Performs a soft-delete or anonymization pass across user-owned content and PII. The current implementation is a stub returning 202; extend with real logic gated by configuration and admin review.
Admin Audit Logs
- Enable database logging in `f_core/config.logging.php` via `logging_database_logging`.
- The logger writes to `db_logs` with request id, user id, IP, and optional context.
- Use `f_modules/m_backend/log_viewer.php` to browse logs; it supports search and time filtering.
Security Considerations
- Require authentication and CSRF validation for destructive actions.
- Enforce rate limiting via `VSecurity::checkRateLimit`.
- Consider adding a review workflow for delete requests.
+428
View File
@@ -0,0 +1,428 @@
# EasyStream Continuous Delivery Guide
Automatically commit and push your changes to GitHub with zero manual intervention.
## Features
- **File Watcher Mode**: Detects file changes in real-time and auto-commits after 30 seconds of inactivity
- **Timer Mode**: Commits and pushes at regular intervals (default: 5 minutes)
- **Smart Exclusions**: Automatically excludes temporary files, sessions, cache, and database files
- **Retry Logic**: Automatically retries failed pushes with exponential backoff
- **Change Summaries**: Generates detailed commit messages with file change lists
- **Zero Configuration**: Works out of the box with sensible defaults
## Quick Start
### Option 1: File Watcher Mode (Recommended)
This mode monitors your files and automatically commits changes 30 seconds after you stop editing:
```powershell
.\start-cd.ps1 watch
```
You'll see:
```
========================================
EasyStream File Watcher Started
========================================
Watching: E:\repos\easystream-main
Branch: dev
Debounce: 30 seconds after last change
========================================
✓ File watcher active. Monitoring for changes...
```
When you save a file:
```
[14:23:45] Changed: setup.php
[14:23:47] Changed: f_core/config.href.php
[14:23:50] Changed: docker-compose.yml
Debounce period elapsed. Processing 3 changes...
Found 3 changed files
✓ Committed changes
✓ Successfully pushed to GitHub
```
### Option 2: Timer Mode
Commits and pushes at regular intervals (every 5 minutes by default):
```powershell
.\start-cd.ps1 start
```
Change the interval to 1 minute:
```powershell
.\start-cd.ps1 start -Interval 60
```
### Option 3: One-Time Commit
Manually trigger a single commit and push:
```powershell
.\start-cd.ps1 once
```
## Configuration
Edit [.cd-config.json](.cd-config.json) to customize behavior:
```json
{
"intervalSeconds": 300,
"branch": "dev",
"commitPrefix": "auto:",
"excludePatterns": [
"f_data/data_sessions/*",
"f_data/data_cache/_c_tpl/*",
".setup_complete",
"*.log",
"db_data/*",
"node_modules/*",
"vendor/*"
],
"enableNotifications": true,
"autoStart": false
}
```
### Configuration Options
| Option | Description | Default |
|--------|-------------|---------|
| `intervalSeconds` | Time between auto-commits (timer mode) | 300 (5 min) |
| `branch` | Git branch to push to | "dev" |
| `commitPrefix` | Prefix for auto-generated commit messages | "auto:" |
| `excludePatterns` | File patterns to ignore | See above |
| `enableNotifications` | Show Windows notifications (future) | true |
| `autoStart` | Start CD on system boot (future) | false |
## Commands Reference
### start-cd.ps1 Commands
```powershell
# Start file watcher mode
.\start-cd.ps1 watch
# Start timer mode (default interval: 5 minutes)
.\start-cd.ps1 start
# Start timer mode with custom interval (60 seconds)
.\start-cd.ps1 start -Interval 60
# Run one-time commit and push
.\start-cd.ps1 once
# Check git status
.\start-cd.ps1 status
# Stop all running CD processes
.\start-cd.ps1 stop
# Show help
.\start-cd.ps1 help
```
### auto-deploy.ps1 Advanced Usage
Direct script usage for advanced scenarios:
```powershell
# File watcher mode with verbose output
.\auto-deploy.ps1 -WatchMode -Verbose
# Timer mode with custom interval and branch
.\auto-deploy.ps1 -IntervalSeconds 120 -Branch main -Verbose
# Custom commit prefix
.\auto-deploy.ps1 -CommitPrefix "wip:" -IntervalSeconds 60
```
## How It Works
### File Watcher Mode
1. **Monitors**: Watches all files in the repository using .NET FileSystemWatcher
2. **Debounces**: Waits 30 seconds after the last file change to avoid committing partial edits
3. **Excludes**: Filters out temporary files based on `.gitignore` and config patterns
4. **Commits**: Stages all changes and creates a commit with file change summary
5. **Pushes**: Uploads to GitHub with retry logic
6. **Repeats**: Continues monitoring for the next change
### Timer Mode
1. **Checks**: Scans for changes at regular intervals
2. **Stages**: Adds all modified, new, and deleted files
3. **Commits**: Creates a timestamped commit with change summary
4. **Pushes**: Uploads to GitHub if there are new commits
5. **Waits**: Sleeps for the configured interval before next check
## Commit Message Format
Auto-generated commits include:
```
auto: Update at 2025-10-26 14:30:00
Changed files:
- setup.php
- docker-compose.yml
- f_core/config.href.php
- ... and 5 more files
🤖 Generated with Claude Code Continuous Delivery
Co-Authored-By: Claude <noreply@anthropic.com>
```
## Excluded Files
The following files are automatically excluded from commits:
- Session files: `f_data/data_sessions/sess_*`
- Cache files: `f_data/data_cache/_c_tpl/*`
- Setup marker: `.setup_complete`
- Database files: `db_data/*`
- Log files: `*.log`
- Dependencies: `node_modules/*`, `vendor/*`
- IDE files: `.vscode/*`, `.idea/*`
## Troubleshooting
### CD not detecting changes
**Problem**: Files changed but no commit triggered
**Solution**:
```powershell
# Check if files are excluded
git status
# Verify .gitignore doesn't over-exclude
cat .gitignore
# Check CD config
cat .cd-config.json
```
### Push failed: Authentication required
**Problem**: Git asks for credentials
**Solution**:
```powershell
# Set up Git credential helper (Windows)
git config --global credential.helper manager
# Or use SSH keys
git remote set-url origin git@github.com:SamiAhmed7777/easystream-main.git
```
### Multiple CD processes running
**Problem**: CD commits too frequently
**Solution**:
```powershell
# Stop all CD processes
.\start-cd.ps1 stop
# Restart with single instance
.\start-cd.ps1 watch
```
### Large files rejected by GitHub
**Problem**: `db_data/*` files are too large
**Solution**:
These files are already excluded in `.gitignore`. If they're already tracked:
```powershell
# Remove from git but keep locally
git rm --cached -r db_data/
git commit -m "Remove database files from tracking"
git push
```
## Running as Background Service
### Option 1: Windows Task Scheduler
1. Open Task Scheduler
2. Create Basic Task
3. Trigger: At system startup
4. Action: Start a program
- Program: `powershell.exe`
- Arguments: `-WindowStyle Hidden -File "E:\repos\easystream-main\start-cd.ps1" watch`
### Option 2: PowerShell Background Job
```powershell
# Start in background
Start-Job -ScriptBlock {
Set-Location "E:\repos\easystream-main"
.\start-cd.ps1 watch
}
# Check status
Get-Job
# View output
Receive-Job -Id 1 -Keep
# Stop
Stop-Job -Id 1
Remove-Job -Id 1
```
### Option 3: Screen/Tmux (Windows Terminal)
```powershell
# Open new Windows Terminal tab
wt -w 0 nt -d E:\repos\easystream-main powershell -NoExit -Command ".\start-cd.ps1 watch"
```
## Security Considerations
### What Gets Committed
- Application code (PHP, JavaScript, CSS)
- Configuration files (docker-compose.yml, .env templates)
- Documentation (Markdown files)
- SQL schema files
### What's Excluded
- Session data (user sessions)
- Cache (compiled templates)
- Database runtime files (actual data)
- Secrets (`.env` files are tracked but should only contain templates)
### Best Practices
1. **Review `.gitignore`**: Ensure sensitive files are excluded
2. **Use environment variables**: Never commit actual passwords or API keys
3. **Separate repos for secrets**: Use a private repo for production `.env` files
4. **Monitor commits**: Occasionally review auto-commits for unwanted files
## Performance Tips
### For Large Repositories
```json
{
"intervalSeconds": 600,
"excludePatterns": [
"f_data/*",
"uploads/*",
"*.mp4",
"*.mkv"
]
}
```
### For Active Development
```json
{
"intervalSeconds": 180,
"commitPrefix": "wip:"
}
```
## Integration with IDE
### VS Code
Add to `.vscode/tasks.json`:
```json
{
"version": "2.0.0",
"tasks": [
{
"label": "Start Continuous Delivery",
"type": "shell",
"command": ".\\start-cd.ps1 watch",
"presentation": {
"reveal": "always",
"panel": "dedicated"
},
"problemMatcher": []
}
]
}
```
Run with: `Ctrl+Shift+P``Tasks: Run Task``Start Continuous Delivery`
## FAQ
**Q: Will this commit every keystroke?**
A: No. File watcher mode waits 30 seconds after the last change before committing.
**Q: Can I customize commit messages?**
A: Yes, edit the commit message generation in [auto-deploy.ps1:176-188](auto-deploy.ps1#L176-L188)
**Q: Does this work with pull requests?**
A: Yes, but you may want to squash auto-commits before merging. Consider using a feature branch.
**Q: Can I run this on Linux/Mac?**
A: The scripts are PowerShell-specific. For Linux/Mac, use Git hooks or tools like `watchman` + bash scripts.
**Q: Will this conflict with manual commits?**
A: No. The CD system checks for changes and only commits if there are uncommitted files.
**Q: How do I temporarily pause CD?**
A: Press `Ctrl+C` in the CD terminal, or run `.\start-cd.ps1 stop`
## Examples
### Development Workflow
```powershell
# Morning: Start CD
.\start-cd.ps1 watch
# Work normally - changes auto-commit as you save
# End of day: Review commits
git log --oneline --since="8 hours ago"
# Squash if needed before PR
git rebase -i HEAD~20
```
### Emergency Hotfix
```powershell
# Stop CD
.\start-cd.ps1 stop
# Make critical fix
# ... edit files ...
# Manual commit with detailed message
git add .
git commit -m "fix: Critical security patch for XSS vulnerability"
git push
# Resume CD
.\start-cd.ps1 watch
```
## Support
For issues or questions:
- GitHub Issues: https://github.com/SamiAhmed7777/easystream-main/issues
- Check logs in terminal output
- Use `-Verbose` flag for detailed diagnostics
---
**Next Steps**: [Start using CD now!](#quick-start)
+584
View File
@@ -0,0 +1,584 @@
# EasyStream - Complete Docker Deployment Guide
## Table of Contents
- [Prerequisites](#prerequisites)
- [Quick Start (Development)](#quick-start-development)
- [Production Deployment](#production-deployment)
- [Folder Sync Setup](#folder-sync-setup)
- [Database Management](#database-management)
- [Troubleshooting](#troubleshooting)
- [Security Checklist](#security-checklist)
---
## Prerequisites
### System Requirements
- **OS**: Windows 10/11, Linux, or macOS
- **Docker**: Version 20.10 or higher
- **Docker Compose**: Version 2.0 or higher
- **RAM**: Minimum 4GB (8GB recommended)
- **Disk**: Minimum 20GB free space
### Check Your Installation
```bash
docker --version
docker-compose --version
```
---
## Quick Start (Development)
### 1. Clone or Navigate to Project
```bash
cd E:\repos\easystream-main
```
### 2. Configure Environment
```bash
# Copy the example environment file
copy .env.example .env
# Edit .env with your settings (optional for development)
notepad .env
```
### 3. Start All Services
```bash
# Start in detached mode
docker-compose up -d
# View logs
docker-compose logs -f
```
### 4. Wait for Database Initialization
The database will automatically initialize with all tables and default data. This takes about 2-3 minutes.
```bash
# Check database health
docker-compose ps
# Watch database logs
docker-compose logs -f db
```
### 5. Access the Application
- **Frontend**: http://localhost:8083
- **Admin Panel**: http://localhost:8083/admin
- **Default Admin Credentials**:
- Username: `admin`
- Password: `admin123` (⚠️ **CHANGE THIS IMMEDIATELY!**)
### 6. Test RTMP Streaming
```bash
# Stream URL (use in OBS or streaming software)
rtmp://localhost:1935/live/testkey
# View HLS stream
http://localhost:8083/hls/testkey/index.m3u8
```
---
## Production Deployment
### Step 1: Prepare Production Environment
#### 1.1 Copy Production Configuration
```bash
copy .env.production .env
```
#### 1.2 Generate Secure Secrets
Create the secrets directory:
```bash
mkdir secrets
```
Generate secure random keys (use one of these methods):
**Method A: Using OpenSSL (Linux/Mac)**
```bash
openssl rand -hex 32 > secrets/api_key.txt
openssl rand -hex 32 > secrets/jwt_secret.txt
openssl rand -hex 32 > secrets/encryption_key.txt
openssl rand -hex 32 > secrets/cron_secret.txt
openssl rand -hex 24 > secrets/db_password.txt
openssl rand -hex 24 > secrets/db_root_password.txt
```
**Method B: Using PowerShell (Windows)**
```powershell
.\generate-secrets.ps1
```
**Method C: Using Docker**
```bash
docker run --rm alpine sh -c "head -c 32 /dev/urandom | base64" > secrets/api_key.txt
docker run --rm alpine sh -c "head -c 32 /dev/urandom | base64" > secrets/jwt_secret.txt
docker run --rm alpine sh -c "head -c 32 /dev/urandom | base64" > secrets/encryption_key.txt
docker run --rm alpine sh -c "head -c 32 /dev/urandom | base64" > secrets/cron_secret.txt
docker run --rm alpine sh -c "head -c 24 /dev/urandom | base64" > secrets/db_password.txt
docker run --rm alpine sh -c "head -c 24 /dev/urandom | base64" > secrets/db_root_password.txt
```
#### 1.3 Update Production Configuration
Edit `.env` and update these critical values:
```env
MAIN_URL=https://your-domain.com
DB_PASS=<content of secrets/db_password.txt>
API_KEY=<content of secrets/api_key.txt>
JWT_SECRET=<content of secrets/jwt_secret.txt>
ENCRYPTION_KEY=<content of secrets/encryption_key.txt>
```
### Step 2: Set Up SSL/TLS
#### Option A: Let's Encrypt (Automatic - Recommended)
Update your `Caddyfile`:
```
your-domain.com {
encode gzip
root * /srv/easystream
php_fastcgi php:9000
file_server
}
```
Caddy will automatically obtain and renew SSL certificates.
#### Option B: Custom Certificates
Place your certificates in `./deploy/ssl/`:
```bash
mkdir -p deploy/ssl
# Copy your certificate files
copy your-cert.pem deploy/ssl/
copy your-key.pem deploy/ssl/
```
### Step 3: Create Production Volumes
```bash
# Create directories for persistent data
mkdir -p /var/lib/easystream/db
mkdir -p /var/lib/easystream/uploads
mkdir -p /var/lib/easystream/recordings
mkdir -p /var/log/easystream
```
### Step 4: Deploy Production Stack
```bash
# Pull latest images
docker-compose -f docker-compose.prod.yml pull
# Build custom images
docker-compose -f docker-compose.prod.yml build
# Start services
docker-compose -f docker-compose.prod.yml up -d
# Check status
docker-compose -f docker-compose.prod.yml ps
# View logs
docker-compose -f docker-compose.prod.yml logs -f
```
### Step 5: Post-Deployment Verification
```bash
# Test database connection
docker-compose -f docker-compose.prod.yml exec php php -r "new PDO('mysql:host=db;dbname=easystream', 'easystream', getenv('DB_PASS')); echo 'DB OK\n';"
# Test Redis connection
docker-compose -f docker-compose.prod.yml exec php php -r "\$redis = new Redis(); \$redis->connect('redis', 6379); echo 'Redis OK\n';"
# Check all services are healthy
docker-compose -f docker-compose.prod.yml ps
```
---
## Folder Sync Setup
EasyStream includes an automatic folder sync tool to keep your development and Docker directories in sync.
### Windows Setup
#### One-Time Sync
```bash
# Navigate to project directory
cd E:\repos\easystream-main
# Run one-time sync
.\sync-to-docker-progs.bat
```
#### Continuous Sync (Watch Mode)
```bash
# Start file watcher
.\sync-to-docker-progs.bat watch
# This will continuously monitor E:\repos\easystream-main
# and sync changes to E:\docker-progs\easystream-main
```
#### Using PowerShell Directly
```powershell
# One-time sync
.\sync-to-docker-progs.ps1
# Watch mode
.\sync-to-docker-progs.ps1 -Watch
# Verbose mode
.\sync-to-docker-progs.ps1 -Watch -Verbose
# Dry run (see what would be synced)
.\sync-to-docker-progs.ps1 -DryRun
```
### What Gets Synced
- All source code files (PHP, CSS, JS, etc.)
- Configuration files
- Templates
- Database schema files
- Docker configuration
### What Gets Excluded
- `.git` directory
- `node_modules`
- `vendor` (Composer dependencies)
- Cache and temporary files
- Log files
- Uploaded media files
- Session files
---
## Database Management
### Initial Setup
The database is automatically initialized on first startup with:
1. **Main Schema** (270 tables) - Core platform
2. **Advanced Features** (40 tables) - API, analytics, monetization, etc.
3. **Default Settings** - Site configuration
4. **Default Admin User** - `admin` / `admin123`
5. **Default Categories** - 10 video categories
6. **Template Builder Components** - 7 pre-built components
### Manual Database Operations
#### Access Database CLI
```bash
# Development
docker-compose exec db mysql -u easystream -peasystream easystream
# Production
docker-compose -f docker-compose.prod.yml exec db mysql -u easystream -p easystream
```
#### Backup Database
```bash
# Create backup directory
mkdir -p backups
# Backup with compression
docker-compose exec db mysqldump -u easystream -peasystream easystream | gzip > backups/easystream-$(date +%Y%m%d-%H%M%S).sql.gz
# Backup without compression
docker-compose exec db mysqldump -u easystream -peasystream easystream > backups/easystream-$(date +%Y%m%d-%H%M%S).sql
```
#### Restore Database
```bash
# From compressed backup
gunzip -c backups/easystream-20250101-120000.sql.gz | docker-compose exec -T db mysql -u easystream -peasystream easystream
# From uncompressed backup
docker-compose exec -T db mysql -u easystream -peasystream easystream < backups/easystream-20250101-120000.sql
```
#### Reset Database
```bash
# Stop services
docker-compose down
# Remove database volume
docker volume rm easystream-main_db_data
# Start services (will re-initialize)
docker-compose up -d
```
### Database Schema Updates
#### Apply New Tables
If you have new SQL files to apply:
```bash
docker-compose exec -T db mysql -u easystream -peasystream easystream < new_schema.sql
```
#### Check Table Count
```bash
docker-compose exec db mysql -u easystream -peasystream easystream -e "SELECT COUNT(*) as table_count FROM information_schema.tables WHERE table_schema = 'easystream';"
```
#### List All Tables
```bash
docker-compose exec db mysql -u easystream -peasystream easystream -e "SHOW TABLES;"
```
---
## Troubleshooting
### Common Issues
#### 1. Database Container Won't Start
```bash
# Check logs
docker-compose logs db
# Common causes:
# - Volume mount errors (missing SQL files)
# - Port 3306 already in use
# - Insufficient memory
# Fix: Check if SQL files exist
ls -la __install/easystream.sql
ls -la __install/add_advanced_features.sql
ls -la deploy/init_settings.sql
```
#### 2. Port Already in Use
```bash
# Check what's using the port
netstat -ano | findstr :8083 # Windows
lsof -i :8083 # Linux/Mac
# Solution: Either stop the other service or change port in docker-compose.yml
```
#### 3. PHP Container Can't Connect to Database
```bash
# Check if database is healthy
docker-compose ps
# Wait for database to be ready (may take 2-3 minutes)
docker-compose logs -f db
# Verify database connection from PHP container
docker-compose exec php php -r "new PDO('mysql:host=db;dbname=easystream', 'easystream', 'easystream'); echo 'OK\n';"
```
#### 4. Video Upload Not Working
```bash
# Check PHP upload limits
docker-compose exec php php -i | grep upload_max_filesize
docker-compose exec php php -i | grep post_max_size
# Check directory permissions
docker-compose exec php ls -la /srv/easystream/f_data/uploads
# Fix permissions
docker-compose exec php chown -R www-data:www-data /srv/easystream/f_data/uploads
```
#### 5. RTMP Streaming Not Working
```bash
# Check SRS logs
docker-compose logs srs
# Test RTMP connection
docker-compose exec srs curl http://localhost:1985/api/v1/streams
# Verify HLS output directory
docker-compose exec php ls -la /var/www/hls
```
#### 6. Sync Script Not Working
```bash
# Check PowerShell execution policy
Get-ExecutionPolicy
# If Restricted, allow scripts to run:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# Check if paths exist
Test-Path E:\repos\easystream-main
Test-Path E:\docker-progs\easystream-main
```
### Service Management
#### View All Logs
```bash
docker-compose logs -f
```
#### View Specific Service Logs
```bash
docker-compose logs -f php
docker-compose logs -f db
docker-compose logs -f caddy
docker-compose logs -f srs
```
#### Restart Specific Service
```bash
docker-compose restart php
docker-compose restart caddy
```
#### Rebuild Service
```bash
docker-compose up -d --build php
```
#### Check Service Health
```bash
docker-compose ps
docker-compose top
```
### Performance Issues
#### Check Resource Usage
```bash
docker stats
```
#### Optimize Database
```bash
docker-compose exec db mysql -u easystream -peasystream easystream -e "OPTIMIZE TABLE db_videofiles, db_accountuser, db_sessions;"
```
#### Clear Cache
```bash
docker-compose exec php rm -rf /srv/easystream/f_data/cache/*
docker-compose exec redis redis-cli FLUSHALL
```
---
## Security Checklist
### Pre-Production Checklist
- [ ] **Changed default admin password** (`admin123` → strong password)
- [ ] **Generated secure API keys** (not using defaults)
- [ ] **Generated secure JWT secret** (not using defaults)
- [ ] **Generated secure encryption key** (not using defaults)
- [ ] **Changed database password** (not using `easystream`)
- [ ] **Set up SSL/TLS certificates** (HTTPS enabled)
- [ ] **Configured firewall rules** (only necessary ports exposed)
- [ ] **Set up database backups** (automated daily backups)
- [ ] **Configured email server** (for notifications)
- [ ] **Set up monitoring** (health checks, alerts)
- [ ] **Reviewed file permissions** (proper ownership)
- [ ] **Enabled rate limiting** (API and login protection)
- [ ] **Configured CORS properly** (only allow trusted domains)
- [ ] **Set secure session cookies** (httpOnly, secure, sameSite)
- [ ] **Disabled debug mode** (`DEBUG=false`)
- [ ] **Set up log rotation** (prevent disk fill)
- [ ] **Configured Redis password** (if exposed)
- [ ] **Reviewed .env file** (no defaults in production)
- [ ] **Set up CDN** (for static assets)
- [ ] **Configured S3/object storage** (for user uploads)
### File Permissions (Linux/Mac)
```bash
# Set proper ownership
chown -R www-data:www-data /srv/easystream
# Set secure permissions
chmod 755 /srv/easystream
chmod 644 /srv/easystream/.env
chmod 600 /srv/easystream/secrets/*
chmod 755 /srv/easystream/f_data/uploads
chmod 755 /srv/easystream/f_data/cache
```
### Network Security
```bash
# Only expose necessary ports to public
# In production docker-compose.yml:
# - Database: 127.0.0.1:3306 (localhost only)
# - Redis: 127.0.0.1:6379 (localhost only)
# - HTTP: 80 (public)
# - HTTPS: 443 (public)
# - RTMP: 1935 (public, if needed)
```
---
## Maintenance Tasks
### Daily
- Monitor application logs
- Check disk space usage
- Review error logs
### Weekly
- Backup database
- Review security logs
- Check service health
### Monthly
- Update Docker images
- Review and optimize database
- Test backup restoration
- Security audit
### Backup Strategy
```bash
# Create automated backup script
cat > backup.sh << 'EOF'
#!/bin/bash
DATE=$(date +%Y%m%d-%H%M%S)
BACKUP_DIR="/backups/easystream"
mkdir -p $BACKUP_DIR
# Database backup
docker-compose exec -T db mysqldump -u easystream -peasystream easystream | gzip > $BACKUP_DIR/db-$DATE.sql.gz
# Files backup (user uploads)
tar czf $BACKUP_DIR/uploads-$DATE.tar.gz /var/lib/easystream/uploads
# Cleanup old backups (keep last 30 days)
find $BACKUP_DIR -type f -mtime +30 -delete
echo "Backup completed: $DATE"
EOF
chmod +x backup.sh
# Add to crontab (daily at 2 AM)
# 0 2 * * * /path/to/backup.sh >> /var/log/easystream-backup.log 2>&1
```
---
## Additional Resources
- **Docker Documentation**: https://docs.docker.com/
- **Caddy Web Server**: https://caddyserver.com/docs/
- **SRS Streaming Server**: https://github.com/ossrs/srs
- **MariaDB**: https://mariadb.org/documentation/
- **Redis**: https://redis.io/documentation
---
## Support
For issues, questions, or contributions:
- Check the troubleshooting section above
- Review application logs
- Check Docker container health
- Consult the main README.md file
---
**Last Updated**: 2025-10-25
**Version**: 2.0
+427
View File
@@ -0,0 +1,427 @@
# EasyStream - Docker Quick Start
**Get your video platform running in under 5 minutes!**
---
## Prerequisites
- Docker installed
- Docker Compose installed
- 2GB free disk space
---
## Installation
### Step 1: Start the Platform
```bash
docker-compose up -d --build
```
This starts all required services:
- **db** - MariaDB database
- **php** - PHP-FPM 8.2 application server
- **caddy** - Web server with automatic HTTPS
- **srs** - Live streaming server (RTMP/HLS)
- **cron** - Background jobs
- **abr** - Adaptive bitrate transcoding
---
### Step 2: Initialize Database (single SQL file)
Run this **once** after first launch:
```bash
docker exec -i easystream-db mysql -u easystream -peasystream easystream < __install/easystream.sql
```
This loads the full schema and default settings in one pass.
---
### Step 3: Access Your Platform
- **Main Site:** http://localhost:8083
- **Admin Panel:** http://localhost:8083/admin_login.php
- **Settings:** http://localhost:8083/admin_settings.php
**Default Admin Login:**
- Username: `admin`
- Password: `admin123`
---
## First Steps After Installation
### 1. Configure Basic Settings
Go to: http://localhost:8083/admin_settings.php
**General Tab:**
- Set your site name
- Update admin email
- Configure main URL (if not localhost)
**Modules Tab:**
- Enable/disable features you want (videos, live, blogs, etc.)
**Branding Tab:**
- Set your brand colors
- Upload logo and favicon
---
### 2. Set Up Email (Optional)
**Email Tab:**
- Configure SMTP settings for transactional emails
- Test with providers like SendGrid, Mailgun, or Gmail
Example for Gmail:
- Host: `smtp.gmail.com`
- Port: `587`
- Encryption: `TLS`
- Username: Your Gmail address
- Password: App-specific password ([Create here](https://myaccount.google.com/apppasswords))
---
### 3. Configure Payments (Optional)
**Payments Tab:**
**For PayPal:**
- Add PayPal email
- Add Client ID and Secret
- Toggle test mode (disable for production)
**For Stripe:**
- Enable Stripe
- Add Publishable Key
- Add Secret Key
- Add Webhook Secret
---
### 4. Set Up Creator Payouts (Optional)
**Payouts Tab:**
- Enable creator payout system
- Set revenue share percentage (e.g., 70% to creators)
- Set minimum payout amount
- Choose payout schedule (monthly recommended)
---
## Environment Variables
Create `.env` file to override defaults:
```env
# Database
DB_HOST=db
DB_NAME=easystream
DB_USER=easystream
DB_PASS=easystream
# Application
MAIN_URL=http://localhost:8083
DEBUG_MODE=0
# Email (optional - can also configure via admin panel)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=your-email@gmail.com
SMTP_PASS=your-app-password
```
---
## Common Commands
### View Logs
```bash
# All services
docker-compose logs -f
# Specific service
docker-compose logs -f php
docker-compose logs -f caddy
docker-compose logs -f db
```
### Restart Services
```bash
# All services
docker-compose restart
# Specific service
docker-compose restart php
```
### Stop Platform
```bash
docker-compose down
```
### Stop and Remove Data
```bash
docker-compose down -v
```
### Database Access
```bash
# MySQL shell
docker exec -it easystream-db mysql -u easystream -peasystream easystream
# Run SQL file
docker exec -i easystream-db mysql -u easystream -peasystream easystream < file.sql
```
---
## File Structure
```
easystream/
├── docker-compose.yml # Container orchestration
├── Caddyfile # Web server config
├── __install/ # Installation scripts
│ └── install_settings_system.sql # Settings installation
├── admin/ # Admin panel
│ └── admin_settings.php # Settings UI
├── f_core/ # Core framework
│ ├── f_classes/ # PHP classes
│ └── config.*.php # Configuration files
├── f_data/ # Runtime data (auto-created)
│ ├── logs/ # Application logs
│ └── cache/ # Cache files
└── SETTINGS_GUIDE.md # Complete settings documentation
```
---
## Live Streaming
### Start Streaming
**Push RTMP stream to:**
```
rtmp://localhost:1935/live/YOUR_STREAM_KEY
```
**View HLS stream at:**
```
http://localhost:8083/hls/live/YOUR_STREAM_KEY/index.m3u8
```
### OBS Studio Setup
1. Open OBS Studio
2. Settings → Stream
3. Service: `Custom`
4. Server: `rtmp://localhost:1935/live`
5. Stream Key: `YOUR_STREAM_KEY`
6. Click "Start Streaming"
---
## Troubleshooting
### Database Connection Errors
```bash
# Check if database is running
docker-compose ps
# Restart database
docker-compose restart db
# Check database logs
docker-compose logs db
```
---
### Settings Not Loading
```bash
# Re-run settings installation
docker exec -i easystream-db mysql -u easystream -peasystream easystream < __install/easystream.sql
# Check if settings exist
docker exec -it easystream-db mysql -u easystream -peasystream -e "SELECT COUNT(*) FROM easystream.db_settings;"
```
---
### Port Already in Use
If port 8083 is already in use, edit `docker-compose.yml`:
```yaml
services:
caddy:
ports:
- "8084:80" # Change 8083 to 8084
- "443:443"
```
Then restart:
```bash
docker-compose down
docker-compose up -d
```
---
### Permission Errors
```bash
# Fix data directory permissions
sudo chown -R $(whoami):$(whoami) f_data/
# Or make writable by all (less secure)
chmod -R 777 f_data/
```
---
### Email Not Sending
1. Check SMTP settings in admin panel
2. Test credentials with a mail client
3. Check firewall allows port 587/465
4. Review application logs:
```bash
docker-compose logs php | grep -i mail
```
---
## Production Deployment
### 1. Update Environment
Create `.env.production`:
```env
DB_HOST=db
DB_NAME=easystream
DB_USER=easystream
DB_PASS=STRONG_PASSWORD_HERE
MAIN_URL=https://yourdomain.com
DEBUG_MODE=0
```
### 2. Configure Domain
Edit `Caddyfile`:
```
yourdomain.com {
root * /var/www/html
php_fastcgi php:9000
file_server
encode gzip
}
```
### 3. SSL/HTTPS
Caddy automatically handles HTTPS with Let's Encrypt. Just point your domain to your server's IP.
### 4. Security Checklist
- [ ] Change default admin password
- [ ] Disable debug mode
- [ ] Use strong database password
- [ ] Enable HTTPS
- [ ] Configure firewall
- [ ] Set up regular backups
- [ ] Review security settings in admin panel
### 5. Backups
```bash
# Backup database
docker exec easystream-db mysqldump -u easystream -peasystream easystream > backup_$(date +%Y%m%d).sql
# Backup settings to JSON
# (from admin panel: Settings → Export)
# Backup uploaded files
tar -czf uploads_backup.tar.gz f_data/
```
---
## Performance Tips
### 1. Enable Redis Caching
Settings automatically use Redis when available for 10-100x faster performance.
Add to `docker-compose.yml`:
```yaml
services:
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
volumes:
redis_data:
```
### 2. Enable OPcache
Already enabled in the Docker PHP image for optimal performance.
### 3. Database Optimization
```bash
# Check database size
docker exec -it easystream-db mysql -u easystream -peasystream -e "
SELECT table_schema AS 'Database',
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS 'Size (MB)'
FROM information_schema.tables
WHERE table_schema = 'easystream'
GROUP BY table_schema;"
# Optimize tables
docker exec -it easystream-db mysqlcheck -u easystream -peasystream --optimize easystream
```
---
## Next Steps
1. **Read Full Documentation:** [SETTINGS_GUIDE.md](SETTINGS_GUIDE.md)
2. **Configure Your Platform:** Use the admin settings panel
3. **Upload Content:** Start creating videos, streams, or blogs
4. **Invite Users:** Share your platform URL
5. **Monitor Performance:** Check logs and system status regularly
---
## Support
- **Documentation:** See [SETTINGS_GUIDE.md](SETTINGS_GUIDE.md) for complete settings reference
- **Logs:** Check `f_data/logs/` for error logs
- **Admin Panel:** Use log viewer at `/admin/log_viewer.php`
---
## License
EasyStream Proprietary License Agreement
Copyright (c) 2025 Sami Ahmed. All rights reserved.
+871
View File
@@ -0,0 +1,871 @@
# 📚 EasyStream REST API Documentation
## 🎯 **Complete Guide to Using the EasyStream API**
The EasyStream API is a comprehensive RESTful API that allows you to integrate with the EasyStream video platform. This API enables mobile app development, third-party integrations, content syndication, and automation.
---
## 🚀 **Getting Started**
### **Base URL**
```
https://yourdomain.com/api/v1/
```
### **Content Type**
All requests and responses use JSON format:
```
Content-Type: application/json
```
### **CORS Support**
The API supports Cross-Origin Resource Sharing (CORS) for web applications.
---
## 🔐 **Authentication**
### **1. JWT Bearer Token (Recommended)**
**Step 1: Login to get JWT token**
```bash
curl -X POST "https://yourdomain.com/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{
"username": "your_username",
"password": "your_password"
}'
```
**Response:**
```json
{
"status": 200,
"data": {
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
"user": {
"id": 123,
"username": "your_username",
"email": "user@example.com",
"display_name": "Your Name"
},
"expires_in": 86400
},
"timestamp": 1642518000,
"version": "v1"
}
```
**Step 2: Use token in subsequent requests**
```bash
curl -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
```
### **2. API Key Authentication**
**Generate API Key** (via admin panel or user settings)
```bash
curl -H "Authorization: ApiKey your_api_key_here"
```
---
## 📊 **Rate Limiting**
| Endpoint Type | Limit | Window |
|---------------|-------|--------|
| Authentication | 10 requests | 5 minutes |
| Upload | 5 requests | 1 hour |
| Default | 100 requests | 1 hour |
**Rate limit headers in response:**
```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1642521600
```
---
## 🎬 **Video Endpoints**
### **Get Videos**
```bash
GET /api/v1/videos
```
**Parameters:**
- `page` (int): Page number (default: 1)
- `limit` (int): Items per page (max: 50, default: 20)
- `category` (string): Filter by category
- `sort` (string): Sort order (`recent`, `popular`, `rating`)
- `search` (string): Search query
**Example:**
```bash
curl -X GET "https://yourdomain.com/api/v1/videos?limit=10&category=gaming&sort=popular" \
-H "Authorization: Bearer your_token"
```
**Response:**
```json
{
"status": 200,
"data": {
"videos": [
{
"id": "video_123",
"title": "Epic Gaming Moments",
"description": "Amazing highlights from today's stream",
"views": 1250,
"rating": 4.8,
"duration": 300,
"size": 52428800,
"uploaded_at": "2025-01-18 10:30:00",
"uploader": {
"username": "gamer_pro",
"display_name": "Pro Gamer"
},
"thumbnail_url": "/thumbnails/video_123_medium.jpg",
"video_url": "/watch/video_123"
}
],
"pagination": {
"page": 1,
"limit": 10,
"total": 150
}
}
}
```
### **Get Single Video**
```bash
GET /api/v1/videos/{video_id}
```
**Example:**
```bash
curl -X GET "https://yourdomain.com/api/v1/videos/video_123" \
-H "Authorization: Bearer your_token"
```
**Response:**
```json
{
"status": 200,
"data": {
"id": "video_123",
"title": "Epic Gaming Moments",
"description": "Amazing highlights from today's stream",
"full_description": "Full detailed description with timestamps...",
"views": 1250,
"rating": 4.8,
"duration": 300,
"size": 52428800,
"category": "gaming",
"tags": ["gaming", "highlights", "stream"],
"privacy": "public",
"uploaded_at": "2025-01-18 10:30:00",
"uploader": {
"id": 456,
"username": "gamer_pro",
"display_name": "Pro Gamer"
},
"thumbnail_urls": {
"small": "/thumbnails/video_123_small.jpg",
"medium": "/thumbnails/video_123_medium.jpg",
"large": "/thumbnails/video_123_large.jpg"
},
"video_files": {
"1080p": "/videos/video_123_1080p.mp4",
"720p": "/videos/video_123_720p.mp4",
"480p": "/videos/video_123_480p.mp4"
},
"hls_url": "/hls/video_123/master.m3u8"
}
}
```
### **Upload Video**
```bash
POST /api/v1/videos
```
**Multipart form data:**
```bash
curl -X POST "https://yourdomain.com/api/v1/videos" \
-H "Authorization: Bearer your_token" \
-F "video=@video.mp4" \
-F "title=My Amazing Video" \
-F "description=This is my video description" \
-F "category=entertainment" \
-F "tags=fun,awesome,video" \
-F "privacy=public"
```
**Response:**
```json
{
"status": 201,
"data": {
"id": "video_456",
"title": "My Amazing Video",
"status": "processing",
"upload_progress": 100,
"processing_status": "queued"
}
}
```
### **Update Video**
```bash
PUT /api/v1/videos/{video_id}
```
**Example:**
```bash
curl -X PUT "https://yourdomain.com/api/v1/videos/video_123" \
-H "Authorization: Bearer your_token" \
-H "Content-Type: application/json" \
-d '{
"title": "Updated Video Title",
"description": "Updated description",
"privacy": "unlisted"
}'
```
### **Delete Video**
```bash
DELETE /api/v1/videos/{video_id}
```
### **Like Video**
```bash
POST /api/v1/videos/{video_id}/like
```
### **Comment on Video**
```bash
POST /api/v1/videos/{video_id}/comment
```
**Body:**
```json
{
"comment": "Great video! Love the content."
}
```
### **Get Video Comments**
```bash
GET /api/v1/videos/{video_id}/comments?page=1&limit=20
```
---
## 👤 **User Endpoints**
### **Get Users**
```bash
GET /api/v1/users?page=1&limit=20&search=username
```
### **Get User Profile**
```bash
GET /api/v1/users/{user_id}
```
**Response:**
```json
{
"status": 200,
"data": {
"id": 123,
"username": "gamer_pro",
"display_name": "Pro Gamer",
"email": "gamer@example.com",
"avatar_url": "/avatars/123.jpg",
"bio": "Professional gamer and content creator",
"followers_count": 1250,
"following_count": 89,
"videos_count": 45,
"total_views": 125000,
"joined_at": "2024-01-15 09:30:00",
"is_verified": true,
"social_links": {
"twitter": "https://twitter.com/gamer_pro",
"youtube": "https://youtube.com/c/gamerpro"
}
}
}
```
### **Update Profile**
```bash
PUT /api/v1/users/me
```
**Body:**
```json
{
"display_name": "New Display Name",
"bio": "Updated bio",
"social_links": {
"twitter": "https://twitter.com/newhandle"
}
}
```
### **Follow User**
```bash
POST /api/v1/users/{user_id}/follow
```
### **Unfollow User**
```bash
DELETE /api/v1/users/{user_id}/follow
```
### **Get User's Videos**
```bash
GET /api/v1/users/{user_id}/videos?page=1&limit=20
```
### **Get User's Followers**
```bash
GET /api/v1/users/{user_id}/followers?page=1&limit=20
```
### **Get User's Following**
```bash
GET /api/v1/users/{user_id}/following?page=1&limit=20
```
---
## 🎥 **Live Streaming Endpoints**
### **Get Live Streams**
```bash
GET /api/v1/live?category=gaming&status=live
```
**Response:**
```json
{
"status": 200,
"data": {
"streams": [
{
"id": 789,
"title": "Live Gaming Session",
"description": "Playing the latest games",
"category": "gaming",
"status": "live",
"viewer_count": 45,
"started_at": "2025-01-18 14:30:00",
"streamer": {
"username": "live_gamer",
"display_name": "Live Gamer"
},
"thumbnail_url": "/live/thumbnails/789.jpg",
"hls_url": "https://yourdomain.com/live/hls/stream_789.m3u8"
}
]
}
}
```
### **Create Live Stream**
```bash
POST /api/v1/live
```
**Body:**
```json
{
"title": "My Live Stream",
"description": "Live gaming session",
"category": "gaming",
"privacy": "public"
}
```
**Response:**
```json
{
"status": 201,
"data": {
"stream_id": 789,
"stream_key": "stream_123_abc456_1642518000",
"rtmp_url": "rtmp://yourdomain.com:1935/live",
"stream_url": "rtmp://yourdomain.com:1935/live/stream_123_abc456_1642518000",
"hls_url": "https://yourdomain.com/live/hls/stream_123_abc456_1642518000.m3u8",
"dashboard_url": "/live/dashboard/789"
}
}
```
### **Get Stream Details**
```bash
GET /api/v1/live/{stream_id}
```
### **Start Stream**
```bash
POST /api/v1/live/{stream_id}/start
```
### **Stop Stream**
```bash
POST /api/v1/live/{stream_id}/stop
```
### **Update Stream**
```bash
PUT /api/v1/live/{stream_id}
```
---
## 🔍 **Search Endpoint**
### **Search Content**
```bash
GET /api/v1/search?q=gaming&type=videos&limit=20
```
**Parameters:**
- `q` (string): Search query
- `type` (string): Content type (`videos`, `users`, `channels`, `all`)
- `category` (string): Filter by category
- `sort` (string): Sort order (`relevance`, `recent`, `popular`)
**Response:**
```json
{
"status": 200,
"data": {
"query": "gaming",
"results": {
"videos": [...],
"users": [...],
"total_results": 150
},
"suggestions": ["gaming highlights", "gaming tutorial", "gaming review"]
}
}
```
---
## 📊 **Analytics Endpoints**
### **Get Platform Overview**
```bash
GET /api/v1/analytics/overview?start_date=2025-01-01&end_date=2025-01-31
```
**Response:**
```json
{
"status": 200,
"data": {
"users": {
"total_users": 10000,
"active_users": 2500,
"new_users": 150
},
"content": {
"total_videos": 5000,
"new_videos": 45,
"total_views": 1000000
},
"engagement": {
"total_likes": 50000,
"total_comments": 25000,
"total_shares": 5000
},
"streaming": {
"total_streams": 500,
"live_streams": 12,
"total_viewers": 1500
}
}
}
```
### **Get Video Analytics**
```bash
GET /api/v1/analytics/videos/{video_id}?period=30d
```
### **Get User Analytics**
```bash
GET /api/v1/analytics/users/{user_id}?period=7d
```
### **Generate Report**
```bash
POST /api/v1/analytics/reports
```
**Body:**
```json
{
"report_type": "user_growth",
"parameters": {
"start_date": "2025-01-01",
"end_date": "2025-01-31",
"format": "json"
}
}
```
---
## 🔧 **Error Handling**
### **HTTP Status Codes**
- `200` - Success
- `201` - Created
- `400` - Bad Request
- `401` - Unauthorized
- `403` - Forbidden
- `404` - Not Found
- `405` - Method Not Allowed
- `429` - Rate Limited
- `500` - Internal Server Error
### **Error Response Format**
```json
{
"status": 400,
"data": {
"error": "Invalid request parameters",
"details": {
"field": "title",
"message": "Title is required"
}
},
"timestamp": 1642518000,
"version": "v1"
}
```
---
## 💻 **Code Examples**
### **JavaScript/Node.js**
```javascript
// Login and get token
const login = async (username, password) => {
const response = await fetch('https://yourdomain.com/api/v1/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
const data = await response.json();
return data.data.token;
};
// Get videos
const getVideos = async (token, limit = 20) => {
const response = await fetch(`https://yourdomain.com/api/v1/videos?limit=${limit}`, {
headers: { 'Authorization': `Bearer ${token}` }
});
const data = await response.json();
return data.data.videos;
};
// Upload video
const uploadVideo = async (token, videoFile, title, description) => {
const formData = new FormData();
formData.append('video', videoFile);
formData.append('title', title);
formData.append('description', description);
const response = await fetch('https://yourdomain.com/api/v1/videos', {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` },
body: formData
});
return await response.json();
};
```
### **Python**
```python
import requests
class EasyStreamAPI:
def __init__(self, base_url):
self.base_url = base_url.rstrip('/')
self.token = None
def login(self, username, password):
response = requests.post(f'{self.base_url}/api/v1/auth/login', json={
'username': username,
'password': password
})
if response.status_code == 200:
self.token = response.json()['data']['token']
return True
return False
def get_videos(self, limit=20, category=None):
headers = {'Authorization': f'Bearer {self.token}'}
params = {'limit': limit}
if category:
params['category'] = category
response = requests.get(f'{self.base_url}/api/v1/videos',
headers=headers, params=params)
if response.status_code == 200:
return response.json()['data']['videos']
return []
def upload_video(self, video_path, title, description):
headers = {'Authorization': f'Bearer {self.token}'}
with open(video_path, 'rb') as video_file:
files = {'video': video_file}
data = {'title': title, 'description': description}
response = requests.post(f'{self.base_url}/api/v1/videos',
headers=headers, files=files, data=data)
return response.json()
# Usage
api = EasyStreamAPI('https://yourdomain.com')
api.login('username', 'password')
videos = api.get_videos(limit=10, category='gaming')
```
### **PHP**
```php
class EasyStreamAPI {
private $baseUrl;
private $token;
public function __construct($baseUrl) {
$this->baseUrl = rtrim($baseUrl, '/');
}
public function login($username, $password) {
$data = json_encode(['username' => $username, 'password' => $password]);
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $this->baseUrl . '/api/v1/auth/login',
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $data,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
if ($result['status'] === 200) {
$this->token = $result['data']['token'];
return true;
}
return false;
}
public function getVideos($limit = 20, $category = null) {
$url = $this->baseUrl . '/api/v1/videos?limit=' . $limit;
if ($category) {
$url .= '&category=' . urlencode($category);
}
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $this->token],
CURLOPT_RETURNTRANSFER => true
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
return $result['status'] === 200 ? $result['data']['videos'] : [];
}
}
// Usage
$api = new EasyStreamAPI('https://yourdomain.com');
$api->login('username', 'password');
$videos = $api->getVideos(10, 'gaming');
```
---
## 🔄 **Content Syndication Use Cases**
### **1. Cross-Platform Posting**
Extract video metadata and post to YouTube, TikTok, Twitter, Facebook:
```python
# Get video data
videos = api.get_videos(limit=10, category='gaming')
for video in videos:
# Extract metadata
title = video['title']
description = video['description']
tags = video.get('tags', [])
# Post to YouTube
youtube_api.upload_video(title, description, tags)
# Post to Twitter
tweet = f"🎥 {title[:100]}... Watch: {video['video_url']}"
twitter_api.post_tweet(tweet)
# Post to Facebook
facebook_api.post_video_link(title, description, video['video_url'])
```
### **2. Content Aggregation**
Build content aggregation services:
```javascript
// Aggregate content from multiple EasyStream instances
const instances = [
'https://gaming.example.com',
'https://music.example.com',
'https://education.example.com'
];
const aggregatedContent = [];
for (const instance of instances) {
const api = new EasyStreamAPI(instance);
const videos = await api.getVideos(20);
aggregatedContent.push(...videos);
}
// Sort by popularity and recency
aggregatedContent.sort((a, b) => b.views - a.views);
```
### **3. Analytics Dashboard**
Build external analytics dashboards:
```python
# Collect analytics from multiple channels
analytics_data = []
for user_id in user_ids:
user_analytics = api.get_user_analytics(user_id, period='30d')
analytics_data.append(user_analytics)
# Generate reports
generate_performance_report(analytics_data)
send_weekly_summary_email(analytics_data)
```
---
## 🛠️ **SDK and Tools**
### **Official SDKs** (Coming Soon)
- JavaScript/TypeScript SDK
- Python SDK
- PHP SDK
- Mobile SDKs (iOS/Android)
### **Postman Collection**
Import the EasyStream API collection for easy testing:
```
https://yourdomain.com/api/v1/postman-collection.json
```
### **OpenAPI Specification**
Full API specification available at:
```
https://yourdomain.com/api/v1/openapi.json
```
---
## 🔒 **Security Best Practices**
### **1. Token Management**
- Store JWT tokens securely
- Refresh tokens before expiration
- Never expose tokens in client-side code
### **2. Rate Limiting**
- Implement client-side rate limiting
- Handle 429 responses gracefully
- Use exponential backoff for retries
### **3. Input Validation**
- Validate all input data
- Sanitize user-generated content
- Use HTTPS for all requests
### **4. Error Handling**
- Handle all HTTP status codes
- Implement proper error logging
- Provide user-friendly error messages
---
## 📞 **Support and Resources**
### **API Status**
Check API status and uptime:
```
https://yourdomain.com/api/v1/status
```
### **Rate Limit Status**
Check your current rate limit status:
```
https://yourdomain.com/api/v1/rate-limit-status
```
### **Documentation Updates**
This documentation is updated regularly. Check the version and last updated date:
```json
{
"version": "v1",
"last_updated": "2025-01-18",
"documentation_version": "1.0.0"
}
```
---
## 🎉 **Conclusion**
The EasyStream API provides comprehensive access to all platform features, enabling you to:
**Build mobile applications** with full video platform functionality
**Create content syndication tools** for cross-platform posting
**Develop analytics dashboards** with real-time metrics
**Integrate live streaming** into your applications
**Automate content management** workflows
**Build third-party integrations** and tools
**The API is production-ready and designed for scalability, security, and ease of use.**
For additional support, examples, or feature requests, please refer to the platform documentation or contact the development team.
**🚀 Start building amazing applications with the EasyStream API today!**
+104
View File
@@ -0,0 +1,104 @@
# Enable PowerShell Script Execution
You need to enable PowerShell script execution to use the Continuous Delivery system.
## Quick Fix (Recommended)
Run this **one-time command** in PowerShell **as Administrator**:
```powershell
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```
This allows you to run local scripts while still protecting against remote scripts.
### Step-by-Step:
1. **Right-click** the **Start Menu** or press `Win+X`
2. Select **"Windows PowerShell (Admin)"** or **"Terminal (Admin)"**
3. When UAC prompts, click **Yes**
4. Run: `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`
5. Type `Y` and press Enter
6. Close the admin window
7. Go back to your normal PowerShell terminal
8. Run: `.\start-cd.ps1 watch`
## Alternative: No Admin Required (Bypass Method)
If you **can't get admin access**, use the bypass method for each run:
```powershell
# Instead of:
.\start-cd.ps1 watch
# Use this:
powershell -ExecutionPolicy Bypass -File .\start-cd.ps1 watch
```
### Create a Shortcut (No Admin)
Create `run-cd-watch.bat` with this content:
```batch
@echo off
powershell -ExecutionPolicy Bypass -File "%~dp0start-cd.ps1" watch
pause
```
Then just double-click `run-cd-watch.bat` to start CD!
## Verify It's Working
After enabling, run:
```powershell
Get-ExecutionPolicy
```
Should show: `RemoteSigned` or `Bypass`
Then test the CD system:
```powershell
.\start-cd.ps1 watch
```
## Security Notes
**What does RemoteSigned mean?**
- ✅ You can run scripts you create locally
- ✅ You can run scripts from your organization
- ⚠️ Downloaded scripts must be signed by a trusted publisher
- ✅ This is the Microsoft-recommended policy for developers
**Is this safe?**
Yes! `RemoteSigned` is the recommended policy for developers. It protects you from running malicious scripts downloaded from the internet while allowing you to run your own scripts.
## Troubleshooting
**Still getting "UnauthorizedAccess"?**
Try this sequence:
```powershell
# Check current policy
Get-ExecutionPolicy -List
# Set for current user only (no admin needed)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# If that fails, use bypass method
powershell -ExecutionPolicy Bypass -File .\start-cd.ps1 watch
```
**Group Policy is blocking?**
Some corporate environments block script execution via Group Policy. If you see "cannot be changed" errors, you must use the bypass method:
```powershell
powershell -ExecutionPolicy Bypass -File .\start-cd.ps1 watch
```
---
**Once enabled**, you're ready to use the CD system! See [CD_QUICK_START.md](CD_QUICK_START.md) for usage.
+739
View File
@@ -0,0 +1,739 @@
# EasyStream Design System - Integration Snippets
Quick copy-paste snippets to integrate the new design system into EasyStream templates.
## Table of Contents
1. [HTML Head Updates](#html-head-updates)
2. [Skip Links](#skip-links)
3. [Theme Switcher UI](#theme-switcher-ui)
4. [Accessibility Improvements](#accessibility-improvements)
5. [Responsive Components](#responsive-components)
---
## HTML Head Updates
### Add to Smarty Template Headers
**For frontend templates** ([f_templates/tpl_frontend/tpl_head_min.tpl](f_templates/tpl_frontend/tpl_head_min.tpl)):
```smarty
{* Add after existing CSS includes *}
<!-- Design System v2.0 -->
<link rel="stylesheet" href="{$main_url}/f_scripts/shared/design-system.css">
<link rel="stylesheet" href="{$main_url}/f_scripts/shared/accessibility.css">
<link rel="stylesheet" href="{$main_url}/f_scripts/shared/responsive.css">
<!-- Meta tags for PWA -->
<meta name="theme-color" content="#06a2cb">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="EasyStream">
<!-- Manifest -->
<link rel="manifest" href="{$main_url}/manifest.json">
<!-- Preload critical fonts -->
<link rel="preload" as="font" type="font/woff2" crossorigin>
```
### Add to Footer Scripts
**For frontend templates** ([f_templates/tpl_frontend/tpl_footerjs_min.tpl](f_templates/tpl_frontend/tpl_footerjs_min.tpl)):
```smarty
{* Add before closing body tag *}
<!-- Theme Switcher -->
<script src="{$main_url}/f_scripts/shared/theme-switcher.js"></script>
<!-- Service Worker Registration (already in index.js but ensure it's loaded) -->
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js?v=2')
.then(reg => console.log('[SW] Registered'))
.catch(err => console.error('[SW] Registration failed:', err));
}
</script>
```
---
## Skip Links
### Add to Body Start
**Add to** ([f_templates/tpl_frontend/tpl_body.tpl](f_templates/tpl_frontend/tpl_body.tpl:1)) at the very beginning:
```smarty
<body class="fe media-width-768 is-fw{if $is_mobile eq 1} is-mobile{/if}" data-theme="{$theme_name|default:'blue'}">
{* Skip links for accessibility *}
<div class="skip-links" role="navigation" aria-label="Skip links">
<a href="#main-content" class="skip-to-content">Skip to main content</a>
<a href="#navigation" class="skip-to-content">Skip to navigation</a>
<a href="#search" class="skip-to-content">Skip to search</a>
</div>
{* Rest of body content *}
```
### Add Main Content ID
**Update main wrapper** in [f_templates/tpl_frontend/tpl_body_main.tpl](f_templates/tpl_frontend/tpl_body_main.tpl):
```smarty
<main id="main-content" role="main" class="container">
{* Your main content *}
</main>
```
---
## Theme Switcher UI
### Option 1: Add to Header Navigation
**Add to** [f_templates/tpl_frontend/tpl_header/tpl_headernav_yt.tpl](f_templates/tpl_frontend/tpl_header/tpl_headernav_yt.tpl):
```smarty
{* Add to header navigation area *}
<div class="header-controls">
{* Theme toggle button *}
<button
id="theme-toggle"
class="btn btn-secondary touch-target"
aria-label="Toggle dark mode"
title="Toggle dark mode">
<i class="icon-moon"></i>
<span class="sr-only">Toggle theme</span>
</button>
{* Existing notification bell, user menu, etc. *}
</div>
```
### Option 2: Full Theme Picker Modal
Create new template: `f_templates/tpl_frontend/tpl_theme_picker.tpl`
```smarty
{* Theme Picker Modal *}
<div id="theme-picker-modal" class="modal" role="dialog" aria-labelledby="theme-modal-title" aria-hidden="true">
<div class="modal-backdrop" data-dismiss="modal"></div>
<div class="modal-content card">
<div class="modal-header">
<h2 id="theme-modal-title" class="text-xl font-semibold">Appearance Settings</h2>
<button class="modal-close" data-dismiss="modal" aria-label="Close">
<i class="icon-close"></i>
</button>
</div>
<div class="modal-body p-lg">
{* Theme mode toggle *}
<div class="theme-setting">
<label class="theme-label flex justify-between items-center">
<span class="font-medium">Theme Mode</span>
<button id="theme-toggle" class="btn btn-secondary touch-target" aria-label="Toggle theme mode">
<i class="icon-moon"></i>
</button>
</label>
</div>
<div class="hr m-y-md"></div>
{* Color picker *}
<div class="theme-setting">
<span class="theme-label font-medium block m-b-sm">Color Theme</span>
<div class="color-options flex gap-sm flex-wrap" role="group" aria-label="Color themes">
<button class="color-btn color-blue touch-target" data-color-theme="blue" aria-label="Blue theme" title="Blue">
<span class="sr-only">Blue</span>
</button>
<button class="color-btn color-red touch-target" data-color-theme="red" aria-label="Red theme" title="Red">
<span class="sr-only">Red</span>
</button>
<button class="color-btn color-cyan touch-target" data-color-theme="cyan" aria-label="Cyan theme" title="Cyan">
<span class="sr-only">Cyan</span>
</button>
<button class="color-btn color-green touch-target" data-color-theme="green" aria-label="Green theme" title="Green">
<span class="sr-only">Green</span>
</button>
<button class="color-btn color-orange touch-target" data-color-theme="orange" aria-label="Orange theme" title="Orange">
<span class="sr-only">Orange</span>
</button>
<button class="color-btn color-pink touch-target" data-color-theme="pink" aria-label="Pink theme" title="Pink">
<span class="sr-only">Pink</span>
</button>
<button class="color-btn color-purple touch-target" data-color-theme="purple" aria-label="Purple theme" title="Purple">
<span class="sr-only">Purple</span>
</button>
</div>
</div>
</div>
</div>
</div>
<style>
.color-btn {
width: 44px;
height: 44px;
border-radius: var(--border-radius-full);
border: 3px solid transparent;
cursor: pointer;
transition: all var(--transition-base);
position: relative;
}
.color-btn:hover {
transform: scale(1.1);
box-shadow: var(--shadow-md);
}
.color-btn.active {
border-color: var(--color-text-primary);
box-shadow: var(--shadow-lg);
}
.color-btn.active::after {
content: '✓';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-weight: bold;
font-size: 1.25rem;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
}
.color-blue { background: #06a2cb; }
.color-red { background: #dd1e2f; }
.color-cyan { background: #00997a; }
.color-green { background: #199900; }
.color-orange { background: #f28410; }
.color-pink { background: #ec7ab9; }
.color-purple { background: #b25c8b; }
</style>
```
---
## Accessibility Improvements
### Form Labels
**Before:**
```html
<input type="text" name="username" placeholder="Username">
```
**After:**
```html
<label for="username" class="font-medium m-b-xs">
Username
<span class="required" aria-label="required">*</span>
</label>
<input
type="text"
id="username"
name="username"
class="input"
aria-required="true"
aria-describedby="username-error">
<div id="username-error" class="error-message" role="alert" style="display: none;">
Please enter a username
</div>
```
### Image Alt Text
**Before:**
```smarty
<img src="{$video.thumbnail}">
```
**After:**
```smarty
<img
src="{$video.thumbnail}"
alt="{$video.title|escape} - Thumbnail"
loading="lazy"
width="320"
height="180">
```
### Button Accessibility
**Before:**
```html
<button onclick="likeVideo()">
<i class="icon-like"></i>
</button>
```
**After:**
```html
<button
onclick="likeVideo()"
class="btn btn-secondary touch-target"
aria-label="Like this video"
aria-pressed="false">
<i class="icon-like" aria-hidden="true"></i>
<span class="sr-only">Like</span>
</button>
```
### Heading Hierarchy
**Before:**
```html
<div class="title">Featured Videos</div>
<div class="video-title">My Video</div>
```
**After:**
```html
<h2 class="content-title text-2xl font-semibold">Featured Videos</h2>
<h3 class="video-title text-lg">My Video</h3>
```
### ARIA Landmarks
**Add to templates:**
```smarty
<header role="banner">
{* Header content *}
</header>
<nav role="navigation" aria-label="Main navigation">
{* Navigation menu *}
</nav>
<main role="main" id="main-content">
{* Main content *}
</main>
<aside role="complementary" aria-label="Sidebar">
{* Sidebar content *}
</aside>
<footer role="contentinfo">
{* Footer content *}
</footer>
```
---
## Responsive Components
### Video Grid
**Before:**
```smarty
<div class="thumbs-wrapper">
{foreach from=$videos item=video}
<div class="vs-column">
{* Video thumbnail *}
</div>
{/foreach}
</div>
```
**After:**
```smarty
<div class="video-grid">
{foreach from=$videos item=video}
<article class="video-card">
<a href="{$video.url}" class="video-link">
<div class="aspect-video">
<img
src="{$video.thumbnail}"
alt="{$video.title|escape} - Thumbnail"
loading="lazy"
class="video-thumbnail">
</div>
<div class="video-info p-sm">
<h3 class="video-title text-md font-medium">{$video.title}</h3>
<p class="video-meta text-sm text-secondary">
<span>{$video.views} views</span>
<span aria-hidden="true">•</span>
<span>{$video.date}</span>
</p>
</div>
</a>
</article>
{/foreach}
</div>
```
### Responsive Container
**Before:**
```html
<div class="inner-block">
{* Content *}
</div>
```
**After:**
```html
<div class="container">
{* Content auto-sizes with padding *}
</div>
```
### Flex Layout
**Before:**
```html
<div style="display: flex; justify-content: space-between; align-items: center;">
<div>{$title}</div>
<div>{$actions}</div>
</div>
```
**After:**
```html
<div class="flex justify-between items-center gap-md">
<div>{$title}</div>
<div>{$actions}</div>
</div>
```
### Responsive Text
**Before:**
```html
<h1 style="font-size: 36px;">{$title}</h1>
```
**After:**
```html
<h1 class="text-responsive-xl font-bold">{$title}</h1>
```
### Responsive Spacing
**Before:**
```html
<div style="padding: 16px; margin-bottom: 24px;">
{* Content *}
</div>
```
**After:**
```html
<div class="p-responsive m-b-lg">
{* Content *}
</div>
```
### Card Component
**New pattern:**
```html
<div class="card shadow-md">
<div class="card-header p-md">
<h2 class="text-lg font-semibold">Card Title</h2>
</div>
<div class="card-body p-lg">
{* Card content *}
</div>
<div class="card-footer p-md">
<button class="btn btn-primary">Action</button>
</div>
</div>
```
### Alert Messages
**Before:**
```smarty
{if $error_message}
<div class="error-message-text">{$error_message}</div>
{/if}
```
**After:**
```smarty
{if $error_message}
<div class="alert alert-error" role="alert">
<i class="icon-warning" aria-hidden="true"></i>
<span>{$error_message}</span>
</div>
{/if}
{if $success_message}
<div class="alert alert-success" role="alert">
<i class="icon-check" aria-hidden="true"></i>
<span>{$success_message}</span>
</div>
{/if}
```
---
## JavaScript Enhancements
### Theme Switcher Events
```javascript
// Listen for theme changes
document.addEventListener('easystream:theme-change', (e) => {
console.log('Theme changed:', e.detail);
// Update other components if needed
});
// Programmatically change theme
window.themeSwitcher.toggleMode(); // Toggle light/dark
window.themeSwitcher.setColor('red'); // Change color
// Get current theme
const theme = window.themeSwitcher.getCurrentTheme();
console.log(theme); // { mode: 'dark', color: 'blue', ... }
```
### Service Worker Updates
```javascript
// Update service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js?v=2')
.then(reg => {
// Check for updates
reg.update();
// Listen for updates
reg.addEventListener('updatefound', () => {
const newWorker = reg.installing;
newWorker.addEventListener('statechange', () => {
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
// New version available
if (confirm('New version available! Reload to update?')) {
window.location.reload();
}
}
});
});
});
}
```
### Offline Detection
```javascript
// Detect online/offline
window.addEventListener('online', () => {
console.log('Back online!');
// Show success message
showNotification('You are back online', 'success');
});
window.addEventListener('offline', () => {
console.log('Gone offline');
// Show warning message
showNotification('You are offline. Some features may be unavailable.', 'warning');
});
function showNotification(message, type) {
const alert = document.createElement('div');
alert.className = `alert alert-${type}`;
alert.textContent = message;
alert.role = 'alert';
document.body.appendChild(alert);
setTimeout(() => alert.remove(), 5000);
}
```
---
## Testing Snippets
### Check Accessibility
```javascript
// Check for images without alt text
const imagesWithoutAlt = document.querySelectorAll('img:not([alt])');
console.log('Images missing alt text:', imagesWithoutAlt.length);
// Check for buttons without labels
const buttonsWithoutLabel = document.querySelectorAll('button:not([aria-label]):not(:has(.sr-only))');
console.log('Buttons missing labels:', buttonsWithoutLabel.length);
// Check heading hierarchy
const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6');
headings.forEach(h => console.log(h.tagName, h.textContent.substring(0, 50)));
```
### Check Contrast Ratios
```javascript
// Check text contrast (simplified)
function checkContrast(element) {
const style = getComputedStyle(element);
const color = style.color;
const bgColor = style.backgroundColor;
console.log(`Element: ${element.tagName}`, { color, bgColor });
}
// Check all text elements
document.querySelectorAll('p, h1, h2, h3, h4, h5, h6, a, button, span').forEach(checkContrast);
```
### Test Keyboard Navigation
```javascript
// Highlight focusable elements
document.querySelectorAll('a, button, input, select, textarea, [tabindex]').forEach(el => {
el.style.outline = '2px solid red';
});
// Tab order test
let tabIndex = 0;
document.addEventListener('focus', (e) => {
console.log(`Tab ${++tabIndex}:`, e.target);
}, true);
```
---
## Common Patterns
### Modal Dialog
```html
<div id="my-modal" class="modal" role="dialog" aria-labelledby="modal-title" aria-hidden="true">
<div class="modal-backdrop" data-dismiss="modal"></div>
<div class="modal-content card shadow-xl">
<div class="modal-header p-md flex justify-between items-center">
<h2 id="modal-title" class="text-xl font-semibold">Modal Title</h2>
<button class="modal-close btn btn-secondary" data-dismiss="modal" aria-label="Close">
<i class="icon-close"></i>
</button>
</div>
<div class="modal-body p-lg">
{* Modal content *}
</div>
<div class="modal-footer p-md flex justify-end gap-sm">
<button class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button class="btn btn-primary">Confirm</button>
</div>
</div>
</div>
```
### Dropdown Menu
```html
<div class="dropdown">
<button
class="btn btn-secondary dropdown-toggle touch-target"
aria-haspopup="true"
aria-expanded="false"
id="dropdown-menu-btn">
Menu <i class="icon-chevron-down"></i>
</button>
<ul
class="dropdown-menu"
role="menu"
aria-labelledby="dropdown-menu-btn"
hidden>
<li role="none">
<a href="#" role="menuitem" class="dropdown-item">Option 1</a>
</li>
<li role="none">
<a href="#" role="menuitem" class="dropdown-item">Option 2</a>
</li>
</ul>
</div>
```
### Loading Spinner
```html
<div class="loading-spinner" role="status" aria-live="polite">
<i class="icon-spinner spinner"></i>
<span class="sr-only">Loading...</span>
</div>
```
### Breadcrumbs
```html
<nav aria-label="Breadcrumb">
<ol class="breadcrumb flex gap-xs items-center">
<li><a href="/">Home</a></li>
<li aria-hidden="true">/</li>
<li><a href="/videos">Videos</a></li>
<li aria-hidden="true">/</li>
<li aria-current="page">Current Page</li>
</ol>
</nav>
```
---
## Quick Reference
### Class Names Cheat Sheet
**Spacing:**
- `m-xs`, `m-sm`, `m-md`, `m-lg` - Margins
- `p-xs`, `p-sm`, `p-md`, `p-lg` - Padding
**Typography:**
- `text-xs`, `text-sm`, `text-md`, `text-lg`, `text-xl` - Font sizes
- `font-light`, `font-normal`, `font-medium`, `font-bold` - Font weights
**Layout:**
- `flex`, `flex-col`, `flex-wrap` - Flexbox
- `grid`, `grid-cols-{n}` - Grid
- `container` - Responsive container
**Display:**
- `hidden`, `block`, `flex` - Display
- `xs:hidden`, `md:block` - Responsive display
**Colors:**
- `text-primary`, `text-secondary` - Text colors
- `bg-primary`, `bg-secondary` - Background colors
**Borders:**
- `rounded-sm`, `rounded-md`, `rounded-lg`, `rounded-full` - Border radius
**Shadows:**
- `shadow-sm`, `shadow-md`, `shadow-lg` - Box shadows
**Accessibility:**
- `sr-only` - Screen reader only
- `touch-target` - Minimum touch size
- `focus-visible` - Focus indicator
---
## Migration Checklist
- [ ] Include new CSS files in templates
- [ ] Include theme-switcher.js
- [ ] Add skip links to body
- [ ] Add main content ID
- [ ] Update navigation with theme toggle
- [ ] Replace inline styles with utility classes
- [ ] Add alt text to all images
- [ ] Add ARIA labels to buttons
- [ ] Add labels to form inputs
- [ ] Fix heading hierarchy
- [ ] Add ARIA landmarks
- [ ] Test keyboard navigation
- [ ] Test with screen reader
- [ ] Test on mobile devices
- [ ] Test all theme combinations
- [ ] Run Lighthouse audit
---
**Next Steps:** See [DESIGN_SYSTEM_GUIDE.md](DESIGN_SYSTEM_GUIDE.md) for complete documentation.
+205
View File
@@ -0,0 +1,205 @@
# EasyStream - Quick Start Guide
## 🚀 Get Started in 3 Minutes
### Option 1: Automated Deployment (Recommended)
```powershell
# Test configuration
.\deploy.ps1 -Mode test
# Deploy for development
.\deploy.ps1 -Mode dev
# Deploy for production (after configuring secrets)
.\deploy.ps1 -Mode prod
```
That's it! Access at **http://localhost:8083**
---
### Option 2: Manual Deployment
#### Step 1: Start Services
```bash
docker-compose up -d
```
#### Step 2: Wait for Database (2-3 minutes)
```bash
docker-compose logs -f db
```
Wait until you see: "ready for connections"
#### Step 3: Access Application
- Frontend: http://localhost:8083
- Admin: http://localhost:8083/admin
- Login: `admin` / `admin123` (⚠️ change immediately!)
---
## 📁 Folder Sync (Repos ↔ Docker-Progs)
### One-Time Sync
```bash
.\sync-to-docker-progs.bat
```
### Continuous Sync (Watch Mode)
```bash
.\sync-to-docker-progs.bat watch
```
This keeps `E:\repos\easystream-main` and `E:\docker-progs\easystream-main` in sync automatically.
---
## 🔑 Production Setup
### 1. Generate Secrets
```powershell
.\generate-secrets.ps1
```
### 2. Configure Environment
```bash
copy .env.production .env
# Edit .env with your domain and settings
```
### 3. Deploy
```powershell
.\deploy.ps1 -Mode prod
```
---
## 🛠️ Common Commands
### View Logs
```bash
docker-compose logs -f # All services
docker-compose logs -f php # PHP only
docker-compose logs -f db # Database only
```
### Check Status
```bash
docker-compose ps
docker-compose top
```
### Restart Service
```bash
docker-compose restart php
docker-compose restart caddy
```
### Stop Everything
```bash
docker-compose down
```
### Database Access
```bash
docker-compose exec db mysql -u easystream -peasystream easystream
```
### Backup Database
```bash
docker-compose exec db mysqldump -u easystream -peasystream easystream | gzip > backup.sql.gz
```
---
## 🎥 Streaming Setup
### RTMP URL (for OBS/Streaming Software)
```
Server: rtmp://localhost:1935/live
Stream Key: testkey
```
### View Live Stream
```
HLS: http://localhost:8083/hls/testkey/index.m3u8
```
---
## 📊 What's Included
-**270+ Database Tables** - Full schema auto-loaded
-**Default Admin Account** - Ready to use
-**10 Categories** - Pre-configured
-**Template Builder** - 7 pre-built components
-**RTMP + HLS Streaming** - Live streaming ready
-**Redis Caching** - Performance optimized
-**Queue System** - Background job processing
-**Cron Jobs** - Automated tasks
---
## 🔍 Troubleshooting
### Port Already in Use
```bash
# Change port in docker-compose.yml
ports:
- "8084:80" # Change 8083 to 8084
```
### Database Not Ready
```bash
# Check health
docker-compose ps
# View initialization progress
docker-compose logs -f db
```
### Upload Not Working
```bash
# Check permissions
docker-compose exec php ls -la /srv/easystream/f_data/uploads
# Fix if needed
docker-compose exec php chown -R www-data:www-data /srv/easystream/f_data
```
---
## 📚 Full Documentation
- **[DOCKER_DEPLOYMENT_GUIDE.md](DOCKER_DEPLOYMENT_GUIDE.md)** - Complete deployment guide
- **[TEMPLATE_BUILDER_GUIDE.md](TEMPLATE_BUILDER_GUIDE.md)** - Template builder documentation
- **[DESIGN_SYSTEM_GUIDE.md](DESIGN_SYSTEM_GUIDE.md)** - Design system usage
---
## ⚠️ Security Checklist
Before going to production:
- [ ] Change default admin password
- [ ] Generate secure secrets (`.\generate-secrets.ps1`)
- [ ] Update `.env` with production values
- [ ] Enable HTTPS/SSL
- [ ] Change database password
- [ ] Configure firewall rules
- [ ] Set up backups
- [ ] Review [DOCKER_DEPLOYMENT_GUIDE.md](DOCKER_DEPLOYMENT_GUIDE.md#security-checklist)
---
## 🆘 Need Help?
1. Check logs: `docker-compose logs -f`
2. Verify services: `docker-compose ps`
3. Review: [DOCKER_DEPLOYMENT_GUIDE.md](DOCKER_DEPLOYMENT_GUIDE.md#troubleshooting)
4. Test configuration: `.\deploy.ps1 -Mode test`
---
**Version**: 2.0 | **Last Updated**: 2025-10-25
+742
View File
@@ -0,0 +1,742 @@
# EasyStream Settings System - Complete Guide
**Configure your entire platform through the admin panel - no code changes required!**
---
## Table of Contents
1. [Quick Installation](#quick-installation)
2. [Accessing Settings](#accessing-settings)
3. [Settings Categories](#settings-categories)
4. [Usage Examples](#usage-examples)
5. [Settings Reference](#settings-reference)
6. [Advanced Features](#advanced-features)
7. [Troubleshooting](#troubleshooting)
---
## Quick Installation
### Step 1: Run the SQL Migration
**Using Docker:**
```bash
docker exec -i easystream-db mysql -u easystream -peasystream easystream < __install/install_settings_system.sql
```
**Using MySQL directly:**
```bash
mysql -u easystream -p easystream < __install/install_settings_system.sql
```
### Step 2: Access the Settings Panel
1. Log in to admin panel: `http://yoursite.com/admin_login.php`
2. Navigate to **Settings** in the sidebar
3. Or go directly to: `http://yoursite.com/admin_settings.php`
### Step 3: Start Configuring
Choose from 8 comprehensive categories and configure your platform without touching any code!
---
## Accessing Settings
### Admin Panel UI
The settings panel provides a beautiful, organized interface with:
- **8 Tabbed Categories** - General, Modules, Branding, Payments, Email, Payouts, SEO, Security
- **Live Search** - Press `Ctrl+K` (or `Cmd+K` on Mac) to instantly search settings
- **Category Filtering** - Filter by category to focus on specific configuration areas
- **Visual Feedback** - Color-coded inputs, helpful descriptions, validation messages
- **Bulk Save** - Save multiple settings at once with a single click
### Search & Filter Features
- **Keyboard Shortcuts:**
- `Ctrl+K` or `Cmd+K` - Focus search box
- `Escape` - Clear search
- **Search Capabilities:**
- Search by setting name
- Search by label text
- Search by help text
- Real-time highlighting of matches
- Result count display
---
## Settings Categories
### 1. General Settings
Configure your site's basic identity and system settings.
**Key Settings:**
- Site name and title
- Admin email address
- Main website URL
- Debug mode toggle
- Maintenance mode
**Example:**
```php
$settings = new Settings($pdo);
$settings->set('website_shortname', 'MyTube');
$settings->set('head_title', 'MyTube - Video Sharing Platform');
```
---
### 2. Modules Management
Enable or disable platform features with visual toggle switches.
**Available Modules:**
- Video uploads
- Live streaming
- Shorts (TikTok-style)
- Images
- Audio
- Documents
- Blogs
- Paid memberships
- Token economy
**Example:**
```php
$settings = new Settings($pdo);
// Disable blogs and documents
$settings->setModuleEnabled('blog', false);
$settings->setModuleEnabled('document', false);
// Check if a module is enabled
if ($settings->isModuleEnabled('video')) {
// Show video upload interface
}
```
---
### 3. Branding & Appearance
Customize your platform's look and feel.
**Customizable Elements:**
- Primary color (buttons, links, accents)
- Secondary color (highlights, hover states)
- Logo URL
- Favicon URL
- Custom footer text
**Example:**
```php
$settings = new Settings($pdo);
$settings->setMultiple([
'branding_primary_color' => '#FF0000',
'branding_secondary_color' => '#282828',
'branding_logo_url' => 'https://mysite.com/logo.png',
'branding_favicon_url' => 'https://mysite.com/favicon.ico'
]);
```
**Live Color Picker:** The admin UI includes a built-in color picker for instant visual feedback.
---
### 4. Payment Gateways
Configure PayPal and Stripe for payments.
**PayPal Settings:**
- PayPal email
- Client ID
- Secret key
- Test mode toggle
**Stripe Settings:**
- Publishable key
- Secret key
- Webhook secret
- Enable/disable toggle
**Example:**
```php
$settings = new Settings($pdo);
// Enable Stripe payments
$settings->setMultiple([
'stripe_enabled' => '1',
'stripe_publishable_key' => 'pk_live_xxxxx',
'stripe_secret_key' => 'sk_live_xxxxx',
'stripe_webhook_secret' => 'whsec_xxxxx',
'payment_methods' => 'Paypal,Stripe'
]);
// Access payment config in your code
$paymentConfig = $settings->getPaymentConfig();
if ($paymentConfig['stripe']['enabled']) {
// Initialize Stripe SDK
\Stripe\Stripe::setApiKey($paymentConfig['stripe']['secret_key']);
}
```
---
### 5. Email Configuration
Set up SMTP for transactional emails.
**SMTP Settings:**
- Host (e.g., smtp.gmail.com)
- Port (587 for TLS, 465 for SSL)
- Username
- Password
- Encryption type (TLS/SSL)
- Authentication enabled
**Example:**
```php
$settings = new Settings($pdo);
// Configure SendGrid SMTP
$settings->setMultiple([
'mail_type' => 'smtp',
'mail_smtp_host' => 'smtp.sendgrid.net',
'mail_smtp_port' => '587',
'mail_smtp_username' => 'apikey',
'mail_smtp_password' => 'your-sendgrid-api-key',
'mail_smtp_auth' => 'true',
'mail_smtp_prefix' => 'tls',
'backend_email' => 'noreply@mysite.com',
'backend_email_fromname' => 'MyTube Team'
]);
// Access email config
$emailConfig = $settings->getEmailConfig();
```
---
### 6. Creator Payouts
Configure revenue sharing with content creators.
**Payout Settings:**
- Enable/disable payout system
- Revenue share percentage (0-100%)
- Minimum payout amount
- Payout schedule (weekly, monthly, quarterly, manual)
- Default payout method (PayPal, Stripe, bank transfer)
**Example:**
```php
$settings = new Settings($pdo);
// Enable creator payouts with 80% revenue share
$settings->setMultiple([
'creator_payout_enabled' => '1',
'creator_payout_percentage' => '80',
'minimum_payout_amount' => '100.00',
'payout_schedule' => 'monthly',
'payout_method' => 'paypal'
]);
```
---
### 7. SEO & Marketing
Optimize your site for search engines.
**SEO Settings:**
- Meta description
- Meta keywords
- Site title optimization
**Example:**
```php
$settings = new Settings($pdo);
$settings->setMultiple([
'head_title' => 'MyTube - Best Video Sharing Platform',
'metaname_description' => 'Upload, share, and watch videos on MyTube. Join millions of creators.',
'metaname_keywords' => 'video sharing, streaming, upload videos, watch videos'
]);
```
---
### 8. Security Settings
Configure user registration and authentication requirements.
**Security Controls:**
- Minimum/maximum age for signup
- Username length requirements
- Password length requirements
- Username format (strict/relaxed)
- Remember me feature
**Example:**
```php
$settings = new Settings($pdo);
$settings->setMultiple([
'signup_min_age' => '13',
'signup_max_age' => '120',
'signup_min_username' => '3',
'signup_max_username' => '20',
'signup_min_password' => '8',
'signup_max_password' => '50',
'username_format' => 'relaxed'
]);
```
---
## Usage Examples
### Method 1: Using the Settings Class (Recommended)
```php
<?php
require_once 'f_core/f_classes/class.settings.php';
// Initialize
$settings = new Settings($pdo);
// Get a single setting
$siteName = $settings->get('website_shortname', 'EasyStream');
// Set a single setting
$settings->set('website_shortname', 'My Awesome Site');
// Get multiple settings at once
$emailConfig = $settings->getEmailConfig();
$paymentConfig = $settings->getPaymentConfig();
// Set multiple settings at once (bulk operation)
$settings->setMultiple([
'website_shortname' => 'My Site',
'head_title' => 'My Site - Video Platform',
'branding_primary_color' => '#FF0000'
]);
// Get all settings in a category
$brandingSettings = $settings->getByPrefix('branding_');
// Check if a module is enabled
if ($settings->isModuleEnabled('video')) {
// Show video upload interface
}
// Set module status
$settings->setModuleEnabled('blog', false);
```
### Method 2: Using Data Providers (Admin Panel)
```php
<?php
require_once 'admin/includes/data_providers.php';
// Get a single setting
$siteName = admin_get_setting($pdo, 'website_shortname');
// Save a setting
admin_save_setting($pdo, 'website_shortname', 'New Site Name');
// Save multiple settings
admin_save_multiple_settings($pdo, [
'website_shortname' => 'New Site',
'head_title' => 'New Title'
]);
// Get module status
$modules = admin_fetch_module_status($pdo);
// Toggle a module
admin_toggle_module($pdo, 'video_module', true);
```
### Method 3: Legacy Database Class
```php
<?php
global $class_database;
// Load specific settings
$class_database->getConfigurations('website_shortname,head_title,backend_email');
// Access via $cfg array
global $cfg;
echo $cfg['website_shortname']; // Site name
```
---
## Settings Reference
### Complete Settings List
| Category | Setting Name | Description | Type | Default |
|----------|--------------|-------------|------|---------|
| **General** | `website_shortname` | Short site name | text | EasyStream |
| | `head_title` | Browser tab title | text | EasyStream |
| | `backend_email` | Admin email | email | admin@example.com |
| | `main_url` | Main website URL | url | http://localhost:8083 |
| | `debug_mode` | Enable debug mode | boolean | 0 |
| **Modules** | `video_module` | Enable videos | boolean | 1 |
| | `live_module` | Enable live streaming | boolean | 1 |
| | `short_module` | Enable shorts | boolean | 1 |
| | `image_module` | Enable images | boolean | 1 |
| | `audio_module` | Enable audio | boolean | 1 |
| | `document_module` | Enable documents | boolean | 1 |
| | `blog_module` | Enable blogs | boolean | 1 |
| | `paid_memberships` | Enable memberships | boolean | 0 |
| | `token_system_enabled` | Enable tokens | boolean | 1 |
| **Branding** | `branding_primary_color` | Primary UI color | color | #1a73e8 |
| | `branding_secondary_color` | Secondary UI color | color | #34a853 |
| | `branding_logo_url` | Logo URL | url | (empty) |
| | `branding_favicon_url` | Favicon URL | url | (empty) |
| | `branding_footer_text` | Custom footer | text | (empty) |
| **Payments** | `paypal_email` | PayPal email | email | (empty) |
| | `paypal_test` | PayPal test mode | boolean | 1 |
| | `paypal_client_id` | PayPal client ID | text | (empty) |
| | `paypal_secret` | PayPal secret (encrypted) | password | (empty) |
| | `stripe_enabled` | Enable Stripe | boolean | 0 |
| | `stripe_publishable_key` | Stripe public key | text | (empty) |
| | `stripe_secret_key` | Stripe secret (encrypted) | password | (empty) |
| | `stripe_webhook_secret` | Webhook secret (encrypted) | password | (empty) |
| **Email** | `mail_type` | Mailer type | select | smtp |
| | `mail_smtp_host` | SMTP hostname | text | smtp.gmail.com |
| | `mail_smtp_port` | SMTP port | number | 587 |
| | `mail_smtp_username` | SMTP username | text | (empty) |
| | `mail_smtp_password` | SMTP password (encrypted) | password | (empty) |
| | `mail_smtp_auth` | SMTP authentication | boolean | true |
| | `mail_smtp_prefix` | Encryption type | select | tls |
| **Payouts** | `creator_payout_enabled` | Enable payouts | boolean | 0 |
| | `creator_payout_percentage` | Revenue share % | number | 70 |
| | `minimum_payout_amount` | Minimum payout | decimal | 50.00 |
| | `payout_schedule` | Payout frequency | select | monthly |
| | `payout_method` | Default method | select | paypal |
| **SEO** | `metaname_description` | Meta description | textarea | (empty) |
| | `metaname_keywords` | Meta keywords | textarea | (empty) |
| **Security** | `signup_min_age` | Minimum age | number | 18 |
| | `signup_max_age` | Maximum age | number | 70 |
| | `signup_min_username` | Min username length | number | 5 |
| | `signup_max_username` | Max username length | number | 15 |
| | `signup_min_password` | Min password length | number | 5 |
| | `signup_max_password` | Max password length | number | 15 |
| | `username_format` | Username format | select | strict |
| | `login_remember` | Enable remember me | boolean | 1 |
---
## Advanced Features
### 1. Redis Caching (10-100x Faster)
The Settings class automatically uses Redis when available:
```php
$settings = new Settings($pdo);
// First call - queries database
$siteName = $settings->get('website_shortname');
// Subsequent calls - served from Redis cache (milliseconds instead of seconds)
$siteName = $settings->get('website_shortname');
// Cache is automatically cleared when settings are updated
$settings->set('website_shortname', 'New Name'); // Invalidates cache
```
**Cache Details:**
- TTL: 1 hour (3600 seconds)
- Automatic invalidation on updates
- Uses existing `VRedis` singleton
- Falls back to database if Redis unavailable
---
### 2. Input Validation
All settings are validated before being saved:
```php
$settings = new Settings($pdo);
try {
// Valid email required
$settings->set('backend_email', 'admin@example.com'); // ✅ Valid
// Invalid email throws exception
$settings->set('backend_email', 'not-an-email'); // ❌ Throws exception
// Port must be 1-65535
$settings->set('mail_smtp_port', 587); // ✅ Valid
$settings->set('mail_smtp_port', 99999); // ❌ Throws exception
// Colors must be valid hex
$settings->set('branding_primary_color', '#FF0000'); // ✅ Valid
$settings->set('branding_primary_color', 'red'); // ❌ Throws exception
} catch (InvalidArgumentException $e) {
echo "Validation error: " . $e->getMessage();
}
```
**Validation Rules:**
- `email` - Valid email format
- `url` - Valid URL format
- `color` - Valid hex color (#RRGGBB)
- `int` - Integer with optional min/max
- `float` - Decimal number with optional min/max
- `bool` - Boolean (0/1, true/false, yes/no)
- `string` - Text with optional min/max length
---
### 3. Encryption for Sensitive Data
Sensitive settings are automatically encrypted:
```php
$settings = new Settings($pdo);
// These are automatically encrypted in the database:
$settings->set('paypal_secret', 'secret_key_here');
$settings->set('stripe_secret_key', 'sk_live_xxxxx');
$settings->set('mail_smtp_password', 'smtp_password');
$settings->set('google_client_secret', 'oauth_secret');
// When you retrieve them, they're automatically decrypted:
$secret = $settings->get('paypal_secret'); // Returns decrypted value
```
**Encrypted Settings:**
- PayPal secret
- Stripe secret key
- Stripe webhook secret
- SMTP password
- Google client secret
- Facebook app secret
- Twitter API secret
**Encryption Method:** AES-256-CBC using keys from `config.define.php` (ENC_FIRSTKEY, ENC_SECONDKEY)
---
### 4. Audit Trail & Change History
Every settings change is tracked with complete audit trail:
```php
$settings = new Settings($pdo);
// Change a setting
$settings->set('website_shortname', 'New Site Name');
// View change history (last 20 changes)
$history = $settings->getHistory('website_shortname');
foreach ($history as $change) {
echo "Changed on: " . $change['changed_at'] . "\n";
echo "Changed by: User #" . $change['changed_by'] . "\n";
echo "Old value: " . $change['old_value'] . "\n";
echo "New value: " . $change['new_value'] . "\n";
echo "IP address: " . $change['ip_address'] . "\n";
}
// Rollback to a previous value
$settings->rollback('website_shortname', $historyId);
```
**Tracked Information:**
- Setting name
- Old value
- New value
- User who made the change
- Timestamp
- IP address
- User agent
- Optional change reason
---
### 5. Bulk Operations
Efficiently update multiple settings at once:
```php
$settings = new Settings($pdo);
// Atomic transaction - all or nothing
$settings->setMultiple([
'website_shortname' => 'MyTube',
'head_title' => 'MyTube - Video Platform',
'branding_primary_color' => '#FF0000',
'branding_secondary_color' => '#282828',
'backend_email' => 'admin@mytube.com'
]);
// If any setting fails validation, the entire operation is rolled back
```
---
### 6. Export & Import
Backup and restore your configuration:
```php
$settings = new Settings($pdo);
// Export all settings to JSON
$backup = $settings->exportJSON();
file_put_contents('settings_backup.json', $backup);
// Import settings from JSON
$json = file_get_contents('settings_backup.json');
$settings->importJSON($json);
```
**Use Cases:**
- Backup before major changes
- Duplicate configuration across environments
- Version control your settings
- Disaster recovery
---
## Troubleshooting
### Settings Not Saving
**Symptoms:** Changes don't persist after clicking Save
**Solutions:**
1. Check database connection in `f_core/config.database.php`
2. Verify PDO is initialized in `admin/includes/bootstrap.php`
3. Check error logs: `f_data/data_logs/log_error/`
4. Ensure `db_settings` table exists
5. Check file permissions on log directories
---
### Settings Not Loading
**Symptoms:** Settings page shows errors or empty values
**Solutions:**
1. Clear Redis cache (if using Redis)
2. Verify `db_settings` table exists
3. Run the installation script: `__install/install_settings_system.sql`
4. Check that settings were inserted: `SELECT COUNT(*) FROM db_settings;`
5. Review PHP error logs
---
### Validation Errors
**Symptoms:** "Invalid value" errors when saving
**Solutions:**
1. Check the error message for specific validation requirements
2. Ensure email addresses are properly formatted
3. Verify URLs include protocol (http:// or https://)
4. Check number ranges (e.g., SMTP port must be 1-65535)
5. Use hex color codes for color settings (#RRGGBB)
---
### PayPal/Stripe Not Working
**Symptoms:** Payments fail or aren't processed
**Solutions:**
1. Verify API keys are correct (check for spaces/typos)
2. Ensure test mode is disabled for production
3. Check webhook URLs are configured in payment gateway dashboard
4. Review payment gateway API documentation
5. Test API keys using gateway's test tools
6. Check error logs for detailed error messages
---
### Email Not Sending
**Symptoms:** No emails received from the platform
**Solutions:**
1. Test SMTP connection manually
2. Verify SMTP credentials are correct
3. Check firewall allows outbound connections on port 587 (TLS) or 465 (SSL)
4. Try a different SMTP provider (SendGrid, Mailgun, etc.)
5. Review email logs in `f_data/data_logs/`
6. Test with a simple mail client first
7. Check spam/junk folders
---
### Search Not Working
**Symptoms:** Settings search doesn't filter results
**Solutions:**
1. Clear browser cache
2. Check JavaScript console for errors (F12)
3. Ensure `admin/includes/settings_search.php` is included
4. Verify settings have `data-setting-*` attributes
5. Try a different browser
---
## Security Best Practices
### 1. Protect Sensitive Settings
```php
// ✅ Good - Use environment variables for production secrets
$settings->set('stripe_secret_key', getenv('STRIPE_SECRET_KEY'));
// ❌ Bad - Don't hardcode secrets
$settings->set('stripe_secret_key', 'sk_live_abc123');
```
### 2. Regular Backups
```php
// Backup before major changes
$backup = $settings->exportJSON();
file_put_contents("backup_" . date('Y-m-d') . ".json", $backup);
```
### 3. Access Control
- Settings page requires admin authentication
- Regular users cannot access `/admin_settings.php`
- Use role-based access control (RBAC)
### 4. Audit Review
Regularly review change history:
```php
$history = $settings->getHistory('stripe_secret_key', 50);
// Review who changed sensitive settings and when
```
---
## File Reference
### Core Files
- [admin_settings.php](admin_settings.php) - Main settings UI
- [f_core/f_classes/class.settings.php](f_core/f_classes/class.settings.php) - Settings management class
- [admin/includes/data_providers.php](admin/includes/data_providers.php) - Settings data providers (lines 759-1041)
- [admin/includes/settings_search.php](admin/includes/settings_search.php) - Search & filter UI component
- [admin/includes/layout.php](admin/includes/layout.php) - Shared UI with sidebar navigation
- [__install/install_settings_system.sql](__install/install_settings_system.sql) - Complete installation script
---
## License
This settings system is part of EasyStream and subject to the EasyStream Proprietary License Agreement.
Copyright (c) 2025 Sami Ahmed. All rights reserved.
+569
View File
@@ -0,0 +1,569 @@
# EasyStream Template Builder Guide
## Overview
The Template Builder is a powerful drag-and-drop interface that allows users to create custom page layouts for their EasyStream installation. Users can visually design templates using pre-built components without writing any code.
## Features
**Drag and Drop Interface** - Intuitive visual builder
🎨 **Pre-built Components** - Video grids, heroes, text blocks, and more
📱 **Responsive Preview** - Test on desktop, tablet, and mobile
💾 **Auto-save** - Never lose your work
📝 **Version History** - Track changes over time
🎯 **Custom Settings** - Configure each component's appearance
🔄 **Template Management** - Create, edit, duplicate, and delete templates
👁️ **Live Preview** - See your changes in real-time
## Installation
### 1. Database Setup
Run the SQL migration to create required tables:
```bash
mysql -u your_user -p your_database < __install/add_template_builder.sql
```
This creates the following tables:
- `db_templatebuilder_templates` - Stores user templates
- `db_templatebuilder_components` - Component library
- `db_templatebuilder_assignments` - Page assignments
- `db_templatebuilder_versions` - Version history
- `db_templatebuilder_user_prefs` - User preferences
### 2. File Structure
The template builder consists of:
```
f_core/f_classes/
└── class.templatebuilder.php # Backend logic
f_templates/tpl_frontend/tpl_builder/
└── tpl_builder_main.tpl # Builder UI
f_templates/tpl_backend/
└── tpl_template_manager.tpl # Template list view
f_scripts/fe/css/builder/
└── builder.css # Builder styles
f_scripts/fe/js/builder/
├── builder-core.js # Main application
├── builder-components.js # Component logic (future)
└── builder-ui.js # UI helpers (future)
f_modules/m_frontend/
└── templatebuilder_ajax.php # AJAX handler
f_modules/m_backend/
└── template_manager.php # Management interface
```
### 3. Include in Navigation
Add a link to the template manager in your user account navigation:
```smarty
<a href="/f_modules/m_backend/template_manager.php">
<i class="icon-layout"></i> My Templates
</a>
```
## User Guide
### Creating a New Template
1. Navigate to **My Templates** in your account
2. Click **Create New Template**
3. You'll be taken to the builder interface
### Builder Interface
The builder consists of three main areas:
#### Left Sidebar - Component Library
- **Search**: Find components quickly
- **Categories**: Filter by component type
- **Component List**: Drag components to canvas
#### Center Canvas - Preview Area
- **Toolbar**: Zoom, grid, and view options
- **Device Preview**: Switch between desktop/tablet/mobile
- **Canvas**: Drag and drop components here
#### Right Sidebar - Properties Panel
- **Page Settings**: Template-wide settings
- **Component Settings**: Configure selected components
- **Section Settings**: Adjust section layout
### Adding Components
1. Find a component in the left sidebar
2. Drag it onto the canvas
3. Drop it where you want it
4. Configure its settings in the right sidebar
### Component Types
#### Video Grid (4 Columns)
Displays videos in a responsive grid layout.
**Settings:**
- Columns (1-6)
- Gap between items
- Padding
#### Hero Banner
Large banner with background image and call-to-action.
**Settings:**
- Background image
- Title and subtitle
- Button text and link
- Overlay opacity
- Height
#### Video Horizontal List
Scrollable horizontal list of videos.
**Settings:**
- Section title
- Gap between items
- Padding
#### Sidebar Widget
Customizable sidebar container.
**Settings:**
- Widget title
- Background color
- Padding and border radius
#### Text Block
Rich text content with heading.
**Settings:**
- Heading text and size
- Content
- Text alignment
- Colors and spacing
#### Image Block
Image with optional caption.
**Settings:**
- Image URL
- Alt text
- Caption
- Alignment
- Max width
#### Custom HTML
Advanced users can add custom HTML/Smarty code.
**Settings:**
- HTML content
- Padding
### Sections
Components are organized into **sections**. Each section can have:
- **Multiple columns** (1-4)
- **Custom gap** between columns
- **Background color**
- **Padding** (top, right, bottom, left)
### Editing Components
1. Click on a component in the canvas
2. The right sidebar shows its settings
3. Modify any setting
4. Changes apply immediately
### Moving Components
- **Drag and drop** within sections
- Use **section controls** to move sections up/down
- **Duplicate** components or sections
- **Delete** unwanted elements
### Responsive Design
Click the device icons in the header to preview:
- 🖥️ **Desktop** (full width)
- 📱 **Tablet** (768px)
- 📱 **Mobile** (375px)
### Saving Templates
- **Auto-save**: Automatically saves every 3 seconds
- **Manual save**: Click "Save" button
- **Versioning**: Each save creates a version history entry
### Publishing Templates
1. Click **Publish** when ready
2. Sets the template as active
3. Template becomes available for use
## Developer Guide
### Creating Custom Components
Add components to the database:
```sql
INSERT INTO `db_templatebuilder_components`
(`component_name`, `component_slug`, `component_category`, `component_html`,
`component_css`, `component_settings_schema`, `is_system`, `description`)
VALUES
('My Component', 'my_component', 'custom',
'<div class="my-component">{{content}}</div>',
'.my-component { padding: {{padding}}px; }',
'{"content": {"type": "textarea", "default": "Hello"}, "padding": {"type": "number", "default": 20}}',
1,
'Custom component description');
```
### Component Settings Schema
The `component_settings_schema` is a JSON object defining configurable settings:
```json
{
"setting_name": {
"type": "number|text|textarea|color|boolean|select|image|code",
"default": "default_value",
"min": 0,
"max": 100,
"step": 5,
"options": ["option1", "option2"]
}
}
```
**Supported Types:**
- `number` - Numeric input with optional min/max/step
- `text` - Single line text
- `textarea` - Multi-line text
- `color` - Color picker
- `boolean` - Checkbox
- `select` - Dropdown with options
- `image` - Image URL input
- `code` - Code editor
### Template Variables
Component HTML can use placeholders:
```html
<div class="hero" style="background: {{background_color}};">
<h1>{{title}}</h1>
{if {{show_button}}}
<a href="{{button_link}}">{{button_text}}</a>
{/if}
</div>
```
Placeholders are replaced with:
1. Component settings values
2. Global data passed to renderer
### Rendering Templates
#### PHP
```php
$templateBuilder = new VTemplateBuilder();
// Render by ID
$html = $templateBuilder->renderTemplate(123);
// Render by slug
$html = $templateBuilder->renderTemplate('my-template-slug');
// Render with data
$html = $templateBuilder->renderTemplate(123, [
'video_items' => $videos,
'user_name' => $userName
]);
echo $html;
```
#### Smarty Template
```smarty
{* Include template builder output *}
<div class="template-container">
{$template_html}
</div>
```
### AJAX API
All AJAX requests go to `/f_modules/m_frontend/templatebuilder_ajax.php`
**Get Components:**
```javascript
GET /templatebuilder_ajax.php?action=get_components
GET /templatebuilder_ajax.php?action=get_components&category=video_grid
```
**Create Template:**
```javascript
POST /templatebuilder_ajax.php
{
"action": "create_template",
"template_name": "My Template",
"template_type": "homepage",
"template_structure": "{...}"
}
```
**Update Template:**
```javascript
POST /templatebuilder_ajax.php
{
"action": "update_template",
"template_id": 123,
"template_structure": "{...}",
"change_note": "Updated hero section"
}
```
**Get Template:**
```javascript
GET /templatebuilder_ajax.php?action=get_template&template_id=123
```
**Preview Template:**
```javascript
GET /templatebuilder_ajax.php?action=preview&template_id=123
```
### Template Structure Format
Templates are stored as JSON:
```json
{
"sections": [
{
"id": "section-1",
"columns": 1,
"gap": 20,
"styles": {
"background_color": "#f5f5f5",
"padding": "40px 20px"
},
"blocks": [
{
"id": "block-1",
"component": "hero_banner",
"settings": {
"title": "Welcome",
"subtitle": "To my site",
"height": 400,
"overlay_opacity": 0.5
}
}
]
}
],
"layout_type": "flex",
"max_width": 1200
}
```
### Extending the Builder
#### Add New Component Category
1. Update SQL insert in `add_template_builder.sql`
2. Add category button in `tpl_builder_main.tpl`
3. Add icon mapping in `builder-core.js` `getCategoryIcon()`
#### Custom CSS for Components
Add component-specific CSS in the component definition:
```css
.component-custom {
/* Your styles */
padding: {{padding}}px;
color: {{text_color}};
}
```
Variables are replaced during rendering.
#### Custom JavaScript
Advanced components can include JavaScript:
```javascript
// In component's custom_js field
document.querySelectorAll('.my-component').forEach(el => {
el.addEventListener('click', () => {
console.log('Clicked!');
});
});
```
### Security Considerations
1. **Input Validation**: All user input is sanitized via `VDatabase::sanitizeInput()`
2. **Ownership Verification**: Users can only edit their own templates
3. **HTML Sanitization**: Custom HTML should be sanitized before rendering
4. **XSS Prevention**: Use Smarty's `|escape` modifier for user content
5. **SQL Injection**: All queries use prepared statements via VDatabase
### Performance Optimization
1. **Caching**: Rendered templates can be cached
2. **Lazy Loading**: Load components on demand
3. **Minification**: Minify CSS/JS before production
4. **Database Indexes**: Indexes already added for performance
5. **JSON Validation**: Validate structure before saving
## Keyboard Shortcuts
- **Ctrl/Cmd + S** - Save template
- **Ctrl/Cmd + Z** - Undo
- **Ctrl/Cmd + Shift + Z** - Redo
- **Delete** - Delete selected element
- **Esc** - Deselect element
## Troubleshooting
### Components Not Loading
Check:
1. Database has component records
2. AJAX endpoint is accessible
3. JavaScript console for errors
### Template Not Saving
Check:
1. User is logged in
2. Template name is provided
3. JSON structure is valid
4. Database connection is active
### Preview Not Working
Check:
1. Template is saved first
2. Template ID is correct
3. Rendering logic has no errors
### Styles Not Applying
Check:
1. CSS files are loaded
2. Builder CSS path is correct
3. Theme compatibility
## Best Practices
### For Users
1. **Name templates clearly** - Use descriptive names
2. **Save regularly** - Use auto-save but manually save major changes
3. **Test responsiveness** - Check all device sizes
4. **Use sections wisely** - Group related content
5. **Keep it simple** - Don't overcomplicate layouts
### For Developers
1. **Component reusability** - Create flexible components
2. **Settings validation** - Validate all settings in schema
3. **Documentation** - Document custom components
4. **Testing** - Test templates on different browsers
5. **Version control** - Use version history for major changes
## API Reference
### VTemplateBuilder Class
#### Methods
**`createTemplate($data)`**
- Creates new template
- Returns: `['success' => bool, 'template_id' => int, 'slug' => string]`
**`updateTemplate($template_id, $data, $change_note = null)`**
- Updates existing template
- Returns: `['success' => bool]`
**`deleteTemplate($template_id)`**
- Deletes template
- Returns: `['success' => bool]`
**`getTemplate($template_id, $check_ownership = true)`**
- Gets template by ID
- Returns: `array|null`
**`getTemplateBySlug($slug)`**
- Gets template by slug
- Returns: `array|null`
**`getUserTemplates($filters = [])`**
- Gets all user templates
- Returns: `array`
**`renderTemplate($template_identifier, $data = [])`**
- Renders template HTML
- Returns: `string`
**`getComponents($category = null)`**
- Gets available components
- Returns: `array`
**`duplicateTemplate($template_id, $new_name = null)`**
- Duplicates template
- Returns: `['success' => bool, 'template_id' => int]`
## Support
For issues or questions:
1. Check this documentation
2. Review code comments
3. Check database logs via `VLogger`
4. Inspect browser console
5. Review version history for changes
## Future Enhancements
Potential improvements:
- [ ] Template marketplace/sharing
- [ ] More component types
- [ ] Advanced grid system
- [ ] Animation options
- [ ] A/B testing support
- [ ] Template import/export
- [ ] Collaboration features
- [ ] Mobile app builder
- [ ] Component library expansion
- [ ] AI-powered suggestions
## Credits
Built for EasyStream by the EasyStream team.
## License
Same license as EasyStream platform.
---
**Last Updated:** 2025-01-22
**Version:** 1.0.0