Skip to content

Configuration Guide

This document covers configuration options for the School Clubs Management System.

Overview

The application uses Flask configuration with sensible defaults. Most settings are configured in __init__.py during application factory initialization.


Application Configuration

Secret Key

Purpose: Signs session cookies and other security-related data.

Configuration:

app.config["SECRET_KEY"] = "TDLLK"  # ⚠️ Changed in production

Production Security

Never use the default secret key in production!

Generate a secure key:

python -c "import secrets; print(secrets.token_hex(32))"

Set via environment variable:

import os
app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY") or secrets.token_hex(32)
We use github pages for it where the actual keys are random and securely stored.


Database Configuration

Database URI

Purpose: Specifies database connection.

Default: SQLite file in instance/data.db

basedir = os.path.abspath(os.path.dirname(__file__))
database_uri = "sqlite:///" + os.path.join(basedir, "instance/data.db")
app.config["SQLALCHEMY_DATABASE_URI"] = database_uri

Path: /deliverable-2/school_clubs/instance/data.db

Connection Options

Purpose: Optimize SQLite for web application use.

app.config["SQLALCHEMY_ENGINE_OPTIONS"] = {
    "connect_args": {
        "timeout": 10,              # Wait up to 10s for lock
        "check_same_thread": False, # Allow multi-threading
    },
    "pool_pre_ping": True,          # Test connections before use
    "pool_recycle": 3600,           # Recycle connections after 1 hour
}

Options Explained:

Option Value Purpose
timeout 10 Database lock timeout (seconds)
check_same_thread False Allow SQLite from multiple threads
pool_pre_ping True Verify connection health
pool_recycle 3600 Recycle connections after 1 hour

SQLite Limitations

SQLite is suitable for development and small deployments. For production at scale, consider PostgreSQL or MySQL.

Track Modifications

app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False

Disables SQLAlchemy event system to reduce overhead.


Flask-Login Configuration

Login View

Purpose: Redirect destination for unauthorized access.

login_manager.login_view = "auth.login_modal"

Users attempting to access @login_required routes are redirected here.


Environment-Specific Configuration

Development

Characteristics:

  • Debug mode enabled
  • Detailed error pages
  • Auto-reload on code changes
  • SQLite database

Activation:

export FLASK_ENV=development
export FLASK_APP=deliverable-2/school_clubs
flask run

Settings:

app.config["DEBUG"] = True
app.config["TESTING"] = False

Production

Characteristics:

  • Debug mode disabled
  • Generic error pages
  • Optimized performance
  • Secure secret key
  • Production database (PostgreSQL recommended)

Activation:

export FLASK_ENV=production
export FLASK_APP=deliverable-2/school_clubs
export SECRET_KEY="your-secure-key-here"
gunicorn "school_clubs:create_app()"

Settings:

app.config["DEBUG"] = False
app.config["TESTING"] = False
app.config["SECRET_KEY"] = os.environ["SECRET_KEY"]

Testing

Characteristics:

  • Separate test database
  • Disable CSRF
  • Fast test execution

Settings:

def create_app(test_config=None):
    if test_config:
        app.config.update(test_config)

Usage:

# In test files
test_config = {
    "TESTING": True,
    "SQLALCHEMY_DATABASE_URI": "sqlite:///:memory:",
    "WTF_CSRF_ENABLED": False,
}
app = create_app(test_config)

Extension Configuration

Flask-Admin

Purpose: Admin panel settings.

admin = Admin(
    app, 
    name="School Admin",
    index_view=MyAdminIndexView()
)

URL: /admin/

Name: "School Admin" (appears in interface)

Flask-Bootstrap

Purpose: Bootstrap 5 integration.

bootstrap = Bootstrap5()
bootstrap.init_app(app)

Provides Bootstrap templates and macros.

Turbo Flask

Purpose: Enable real-time UI updates.

turbo = Turbo()
turbo.init_app(app)

Used for dynamic login/signup error display without page reloads.


CLI Configuration

Custom Commands

Seed Database

Command: flask seed-db

Purpose: Populate database with test data.

Registration:

@app.cli.command("seed-db")
def seed_db_command():
    from .seed import seed_database
    with app.app_context():
        seed_database()

Usage:

cd deliverable-2
flask seed-db

File Upload Configuration

Not Yet Implemented

File upload settings are planned for gallery posts but not yet configured.

Recommended Configuration:

app.config["MAX_CONTENT_LENGTH"] = 16 * 1024 * 1024  # 16 MB max
app.config["UPLOAD_FOLDER"] = os.path.join(basedir, "static/uploads")
app.config["ALLOWED_EXTENSIONS"] = {"png", "jpg", "jpeg", "gif"}

Helper Function:

def allowed_file(filename):
    return "." in filename and \
           filename.rsplit(".", 1)[1].lower() in app.config["ALLOWED_EXTENSIONS"]

Configuration Best Practices

Use Environment Variables

import os

class Config:
    SECRET_KEY = os.environ.get("SECRET_KEY") or "dev-key-only"
    SQLALCHEMY_DATABASE_URI = os.environ.get("DATABASE_URL") or \
        "sqlite:///" + os.path.join(basedir, "instance/data.db")
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class DevelopmentConfig(Config):
    DEBUG = True

class ProductionConfig(Config):
    DEBUG = False
    # Production-specific settings

config = {
    "development": DevelopmentConfig,
    "production": ProductionConfig,
    "default": DevelopmentConfig
}

Usage:

config_name = os.environ.get("FLASK_ENV") or "default"
app.config.from_object(config[config_name])

External Configuration File

.env file:

SECRET_KEY=your-secret-key
DATABASE_URL=sqlite:///instance/data.db
FLASK_ENV=development

Load with python-dotenv:

from dotenv import load_dotenv
load_dotenv()

app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY")

Configuration Hierarchy

  1. Defaults: Hard-coded in application
  2. Config File: config.py or similar
  3. Environment Variables: Override config file
  4. Instance Folder: instance/config.py (not in version control)

Database Initialization

Automatic Initialization

The application automatically creates tables on first run:

with app.app_context():
    db.create_all()
    init_admin(app)

Note: This doesn't handle migrations. For production, use Flask-Migrate.

Manual Initialization

from school_clubs import create_app, db

app = create_app()
with app.app_context():
    db.create_all()
    print("Database tables created!")

Database Seeding

Populate with test data:

flask seed-db

Defined in seed.py:

def seed_database():
    # Create admin user
    admin = User(
        first_name="Admin",
        last_name="User",
        email="admin@example.com",
        password_hash=generate_password_hash("admin123"),
        user_type="admin"
    )
    db.session.add(admin)

    # Create clubs, posts, etc.
    # ...

    db.session.commit()

For production environments, use Flask-Migrate for database migrations.

Installation

pip install Flask-Migrate

Configuration

from flask_migrate import Migrate

app = create_app()
migrate = Migrate(app, db)

Usage

# Initialize migrations
flask db init

# Create migration
flask db migrate -m "Initial migration"

# Apply migration
flask db upgrade

# Rollback
flask db downgrade

Logging Configuration

Development

Flask's default logger is sufficient:

app.logger.info("Application started")
app.logger.error("Error occurred: %s", error)

Production

Configure structured logging:

import logging
from logging.handlers import RotatingFileHandler

if not app.debug:
    file_handler = RotatingFileHandler(
        "logs/school_clubs.log",
        maxBytes=10240,
        backupCount=10
    )
    file_handler.setFormatter(logging.Formatter(
        "%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]"
    ))
    file_handler.setLevel(logging.INFO)
    app.logger.addHandler(file_handler)

    app.logger.setLevel(logging.INFO)
    app.logger.info("School Clubs startup")

Performance Tuning

Query Optimization

Enable query logging:

app.config["SQLALCHEMY_ECHO"] = True  # Log all SQL queries

Caching

Consider Flask-Caching for frequently accessed data:

from flask_caching import Cache

cache = Cache(app, config={
    "CACHE_TYPE": "simple",
    "CACHE_DEFAULT_TIMEOUT": 300
})

@cache.cached(timeout=60)
def get_all_clubs():
    return Club.query.all()

Security Headers

@app.after_request
def set_security_headers(response):
    response.headers["X-Content-Type-Options"] = "nosniff"
    response.headers["X-Frame-Options"] = "SAMEORIGIN"
    response.headers["X-XSS-Protection"] = "1; mode=block"
    response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
    return response

Configuration Checklist

Development

  • Use development secret key
  • Enable debug mode
  • Use SQLite database
  • Seed database with test data

Production

  • Set secure SECRET_KEY from environment
  • Disable debug mode
  • Use production database (PostgreSQL)
  • Enable HTTPS
  • Configure logging to file
  • Set security headers
  • Use environment variables for all secrets
  • Enable Flask-Migrate for migrations
  • Configure rate limiting
  • Set up monitoring and alerts

Next Steps