Documentation Index
Fetch the complete documentation index at: https://docs.enferno.io/llms.txt
Use this file to discover all available pages before exploring further.
Project Structure
enferno/
├── enferno/ # Main application package
│ ├── app.py # Application factory
│ ├── settings.py # Configuration
│ ├── extensions.py # Flask extensions
│ ├── commands.py # CLI commands
│ ├── portal/ # Blueprint: Protected routes
│ ├── public/ # Blueprint: Public routes
│ ├── user/ # Blueprint: User management
│ ├── tasks/ # Background tasks (optional Celery)
│ ├── utils/ # Utility functions
│ ├── static/ # Static assets (Vue, Vuetify, CSS)
│ └── templates/ # Jinja2 templates
├── docs/ # Documentation
├── instance/ # SQLite database
├── pyproject.toml # Dependencies and project config
├── setup.sh # Setup script
├── run.py # Entry point
├── AGENTS.md # AI coding instructions
└── docker-compose.yml # Docker configuration
Blueprints
Enferno uses a three-blueprint architecture for better organization and security:
1. Portal Blueprint (portal/)
Usually contains protected routes that require authentication. Enferno uses a pattern of protecting all routes in this blueprint automatically using before_request:
from flask import Blueprint
from flask_security import auth_required
portal = Blueprint('portal', __name__)
# Protect all routes in this blueprint automatically
@portal.before_request
@auth_required()
def before_request():
pass
@portal.route('/dashboard')
def dashboard():
return render_template('portal/dashboard.html')
@portal.route('/settings')
def settings():
return render_template('portal/settings.html')
This pattern ensures that all routes within the portal blueprint require authentication without needing to decorate each route individually.
2. User Blueprint (user/)
Handles user management, authentication, and profile-related routes:
from flask import Blueprint
from flask_security import auth_required
user = Blueprint('user', __name__)
@user.route('/profile')
@auth_required()
def profile():
return render_template('user/profile.html')
3. Public Blueprint (public/)
Contains routes that are publicly accessible without authentication:
from flask import Blueprint
public = Blueprint('public', __name__)
@public.route('/')
def index():
return render_template('public/index.html')
Database Operations
Enferno uses SQLAlchemy 2.x with the Flask-SQLAlchemy extension. The db instance is available from enferno.extensions.
Model Definition
from enferno.extensions import db
from datetime import datetime
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(80), nullable=False)
content = db.Column(db.Text)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
user = db.relationship('User', back_populates='posts')
Database Operations
from enferno.extensions import db
from enferno.models import Post
from sqlalchemy import select
# Create
post = Post(title='New Post', content='Content here')
db.session.add(post)
db.session.commit()
# Simple queries
stmt = db.session.select(Post) # Select all posts
posts = db.session.scalars(stmt).all()
post = db.session.get(Post, 1) # Get by ID
# Filtered query
stmt = db.session.select(Post).where(Post.title.like('%python%'))
python_posts = db.session.scalars(stmt).all()
# Ordered query with join
stmt = (
db.session.select(Post)
.join(Post.user)
.order_by(Post.created_at.desc())
)
recent_posts = db.session.scalars(stmt).all()
# Update
post = db.session.get(Post, 1)
post.title = 'Updated Title'
db.session.commit()
# Delete
db.session.delete(post)
db.session.commit()
Background Tasks (Optional)
Celery is available when you need async job processing. First, install the full extras:
uv sync --extra full # Adds Redis + Celery
Define tasks in enferno/tasks/__init__.py:
from enferno.tasks import celery
@celery.task
def send_email(user_id, subject, message):
from enferno.extensions import db
from enferno.user.models import User
user = db.session.get(User, user_id)
# Send email...
return True
Call tasks asynchronously:
from enferno.tasks import send_email
send_email.delay(user.id, 'Welcome', 'Welcome to Enferno!')
Run Celery worker:
uv run celery -A enferno.tasks worker --loglevel=info
API Development
Add API endpoints to your blueprints:
from flask import Blueprint, jsonify
from enferno.extensions import db
api = Blueprint('api', __name__)
@api.route('/posts')
def get_posts():
query = db.select(Post).order_by(Post.created_at.desc())
posts = db.session.scalars(query).all()
return jsonify([post.to_dict() for post in posts])
Development Server
uv run flask run # Start server
uv run ruff check --fix . # Lint and auto-fix
uv run ruff format . # Format code
Security Best Practices
-
Input Validation
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired, Length
class PostForm(FlaskForm):
title = StringField('Title', validators=[
DataRequired(),
Length(max=80)
])
-
CSRF Protection
from flask_wtf.csrf import CSRFProtect
csrf = CSRFProtect(app)
-
Authentication
from flask_security import auth_required
@app.route('/protected')
@auth_required()
def protected_route():
return 'Protected content'
Debugging
Enferno includes several debugging tools:
-
Flask Debug Toolbar
from flask_debugtoolbar import DebugToolbarExtension
toolbar = DebugToolbarExtension(app)
-
Logging
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
-
Database Debugging
# Enable SQLAlchemy query logging
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)