Features implemented: - Application factory pattern with environment-based config - 7 modular blueprints (main, auth, admin, players, groups, content, api) - Flask-Caching with Redis support for production - Flask-Login authentication with bcrypt password hashing - API endpoints with rate limiting and Bearer token auth - Comprehensive error handling and logging - CLI commands (init-db, create-admin, seed-db) Blueprint Structure: - main: Dashboard with caching, health check endpoint - auth: Login, register, logout, password change - admin: User management, system settings, theme, logo upload - players: Full CRUD, fullscreen view, bulk operations, playlist management - groups: Group management, player assignments, content management - content: Upload with progress tracking, file management, preview/download - api: RESTful endpoints with authentication, rate limiting, player feedback Performance Optimizations: - Dashboard caching (60s timeout) - Playlist caching (5min timeout) - Redis caching for production - Memoized functions for expensive operations - Cache clearing on data changes Security Features: - Bcrypt password hashing - Flask-Login session management - admin_required decorator for authorization - Player authentication via auth codes - API Bearer token authentication - Rate limiting on API endpoints (60 req/min default) - Input validation and sanitization Documentation: - README.md: Full project documentation with quick start - PROGRESS.md: Detailed progress tracking and roadmap - BLUEPRINT_GUIDE.md: Quick reference for blueprint architecture Pending work: - Models migration from v1 with database indexes - Utils migration from v1 with type hints - Templates migration with updated route references - Docker multi-stage build configuration - Unit tests for all blueprints Ready for models and utils migration from digiserver v1
9.3 KiB
9.3 KiB
Blueprint Architecture - Quick Reference
📦 Blueprint Structure
app/
├── blueprints/
│ ├── __init__.py # Package initialization
│ ├── main.py # Dashboard, health check
│ ├── auth.py # Login, register, logout
│ ├── admin.py # Admin panel, user management
│ ├── players.py # Player CRUD, fullscreen view
│ ├── groups.py # Group management, assignments
│ ├── content.py # Media upload, file management
│ └── api.py # REST API endpoints
🔗 URL Mapping
Main Blueprint (/)
GET /- Dashboard with statisticsGET /health- Health check (database, disk)
Auth Blueprint (/auth)
GET /auth/login- Login pagePOST /auth/login- Process loginGET /auth/logout- LogoutGET /auth/register- Register pagePOST /auth/register- Process registrationGET /auth/change-password- Change password pagePOST /auth/change-password- Update password
Admin Blueprint (/admin)
GET /admin/- Admin panelPOST /admin/user/create- Create userPOST /admin/user/<id>/role- Change user rolePOST /admin/user/<id>/delete- Delete userPOST /admin/theme- Change themePOST /admin/logo/upload- Upload logoPOST /admin/logs/clear- Clear logsGET /admin/system/info- System info (JSON)
Players Blueprint (/players)
GET /players/- List all playersGET /players/add- Add player pagePOST /players/add- Create playerGET /players/<id>/edit- Edit player pagePOST /players/<id>/edit- Update playerPOST /players/<id>/delete- Delete playerPOST /players/<id>/regenerate-auth- Regenerate auth codeGET /players/<id>- Player pageGET /players/<id>/fullscreen- Player fullscreen viewPOST /players/<id>/reorder- Reorder contentPOST /players/bulk/delete- Bulk delete playersPOST /players/bulk/assign-group- Bulk assign to group
Groups Blueprint (/groups)
GET /groups/- List all groupsGET /groups/create- Create group pagePOST /groups/create- Create groupGET /groups/<id>/edit- Edit group pagePOST /groups/<id>/edit- Update groupPOST /groups/<id>/delete- Delete groupGET /groups/<id>/manage- Manage group pageGET /groups/<id>/fullscreen- Group fullscreen viewPOST /groups/<id>/add-player- Add player to groupPOST /groups/<id>/remove-player/<player_id>- Remove playerPOST /groups/<id>/add-content- Add content to groupPOST /groups/<id>/remove-content/<content_id>- Remove contentPOST /groups/<id>/reorder-content- Reorder contentGET /groups/<id>/stats- Group statistics (JSON)
Content Blueprint (/content)
GET /content/- List all contentGET /content/upload- Upload pagePOST /content/upload- Upload fileGET /content/<id>/edit- Edit content pagePOST /content/<id>/edit- Update contentPOST /content/<id>/delete- Delete contentPOST /content/bulk/delete- Bulk delete contentGET /content/upload-progress/<upload_id>- Upload progress (JSON)GET /content/preview/<id>- Preview contentGET /content/<id>/download- Download contentGET /content/statistics- Content statistics (JSON)GET /content/check-duplicates- Check duplicates (JSON)GET /content/<id>/groups- Content groups info (JSON)
API Blueprint (/api)
GET /api/health- API health checkGET /api/playlists/<player_id>- Get player playlist (auth required)POST /api/player-feedback- Submit player feedback (auth required)GET /api/player-status/<player_id>- Get player statusGET /api/upload-progress/<upload_id>- Get upload progressGET /api/system-info- System statisticsGET /api/groups- List all groupsGET /api/content- List all contentGET /api/logs- Get server logs (query params: limit, level, since)
🔒 Authentication & Authorization
Login Required
Most routes require authentication via @login_required decorator:
from flask_login import login_required
@players_bp.route('/')
@login_required
def players_list():
# Route logic
Admin Required
Admin routes use custom @admin_required decorator:
from app.blueprints.admin import admin_required
@admin_bp.route('/')
@login_required
@admin_required
def admin_panel():
# Route logic
API Authentication
API routes use @verify_player_auth for player authentication:
from app.blueprints.api import verify_player_auth
@api_bp.route('/playlists/<int:player_id>')
@verify_player_auth
def get_player_playlist(player_id):
# Access authenticated player via request.player
🚀 Performance Features
Caching
Routes with caching enabled:
- Dashboard: 60 seconds
- Player playlist: 5 minutes (memoized function)
Clear cache on data changes:
from app.extensions import cache
# Clear specific memoized function
cache.delete_memoized(get_player_playlist, player_id)
# Clear all cache
cache.clear()
Rate Limiting
API endpoints have rate limiting:
@api_bp.route('/playlists/<int:player_id>')
@rate_limit(max_requests=30, window=60) # 30 requests per minute
def get_player_playlist(player_id):
# Route logic
🎨 Template Usage
URL Generation
Always use blueprint-qualified names in templates:
Old (v1):
<a href="{{ url_for('login') }}">Login</a>
<a href="{{ url_for('dashboard') }}">Dashboard</a>
<a href="{{ url_for('add_player') }}">Add Player</a>
New (v2):
<a href="{{ url_for('auth.login') }}">Login</a>
<a href="{{ url_for('main.dashboard') }}">Dashboard</a>
<a href="{{ url_for('players.add_player') }}">Add Player</a>
Context Processors
Available in all templates:
server_version- Server version stringbuild_date- Build date stringlogo_exists- Boolean, whether custom logo existstheme- Current theme ('light' or 'dark')
📝 Common Patterns
Creating a New Route
- Choose the appropriate blueprint based on functionality
- Add the route with proper decorators:
@blueprint_name.route('/path', methods=['GET', 'POST'])
@login_required # If authentication needed
def route_name():
try:
# Route logic
log_action('info', 'Success message')
flash('Success message', 'success')
return redirect(url_for('blueprint.route'))
except Exception as e:
db.session.rollback()
log_action('error', f'Error: {str(e)}')
flash('Error message', 'danger')
return redirect(url_for('blueprint.route'))
Adding Caching
For view caching:
@cache.cached(timeout=60, key_prefix='my_key')
def my_route():
# Route logic
For function memoization:
@cache.memoize(timeout=300)
def my_function(param):
# Function logic
API Response Format
Consistent JSON responses:
# Success
return jsonify({
'success': True,
'data': {...}
})
# Error
return jsonify({
'error': 'Error message'
}), 400
🔧 Extension Access
Import extensions from centralized location:
from app.extensions import db, bcrypt, cache, login_manager
Never initialize extensions directly in blueprints - they're initialized in extensions.py and registered in app.py.
🧪 Testing Routes
Manual Testing
# Start development server
flask run
# Test specific blueprint
curl http://localhost:5000/api/health
curl http://localhost:5000/health
# Test authenticated route
curl -H "Authorization: Bearer <auth_code>" http://localhost:5000/api/playlists/1
Unit Testing
def test_dashboard(client, auth):
auth.login()
response = client.get('/')
assert response.status_code == 200
📊 Blueprint Registration
Blueprints are registered in app/app.py:
def register_blueprints(app: Flask) -> None:
"""Register all blueprints."""
from app.blueprints.main import main_bp
from app.blueprints.auth import auth_bp
from app.blueprints.admin import admin_bp
from app.blueprints.players import players_bp
from app.blueprints.groups import groups_bp
from app.blueprints.content import content_bp
from app.blueprints.api import api_bp
app.register_blueprint(main_bp)
app.register_blueprint(auth_bp)
app.register_blueprint(admin_bp)
app.register_blueprint(players_bp)
app.register_blueprint(groups_bp)
app.register_blueprint(content_bp)
app.register_blueprint(api_bp)
✅ Checklist for Adding New Features
- Choose appropriate blueprint
- Add route with proper decorators
- Implement error handling (try/except)
- Add logging with
log_action() - Add flash messages for user feedback
- Clear cache if data changes
- Add type hints to parameters
- Update this documentation
- Add unit tests
- Test manually in browser/API client
This architecture provides:
- ✅ Separation of concerns - Each blueprint handles specific functionality
- ✅ Scalability - Easy to add new blueprints
- ✅ Maintainability - Clear organization and naming
- ✅ Performance - Built-in caching and optimization
- ✅ Security - Proper authentication and authorization
- ✅ API-first - RESTful API alongside web interface