batman (working version kinda)

This commit is contained in:
pika 2025-03-30 19:20:13 +02:00
commit 6dd38036e7
65 changed files with 3950 additions and 0 deletions

25
config/Dockerfile Normal file
View file

@ -0,0 +1,25 @@
FROM python:3.11-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
libpq-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install gunicorn psycopg2-binary redis
# Copy application code
COPY . .
# Set environment variables
ENV PYTHONUNBUFFERED=1
ENV PYTHONDONTWRITEBYTECODE=1
# Run the application
CMD ["gunicorn", "-w", "4", "-b", ":8000", "app:create_app()"]

Binary file not shown.

53
config/docker-compose.yml Normal file
View file

@ -0,0 +1,53 @@
version: '3'
services:
app:
build:
context: ..
dockerfile: config/Dockerfile
command: gunicorn -w 4 -b :8000 "app:create_app()" --access-logfile - --error-logfile -
volumes:
- ../app:/app/app
environment:
- FLASK_APP=app
- FLASK_ENV=production
- DATABASE_URL=postgresql://user:password@db:5432/app_db
- REDIS_URL=redis://redis:6379/0
- SECRET_KEY=${SECRET_KEY:-default_secret_key_change_in_production}
depends_on:
- db
- redis
restart: unless-stopped
nginx:
image: nginx:1.25
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/ssl:/etc/nginx/ssl
depends_on:
- app
restart: unless-stopped
db:
image: postgres:15
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: password
POSTGRES_DB: app_db
volumes:
- pg_data:/var/lib/postgresql/data
restart: unless-stopped
redis:
image: redis:7
volumes:
- redis_data:/data
restart: unless-stopped
volumes:
pg_data:
redis_data:

64
config/settings.py Normal file
View file

@ -0,0 +1,64 @@
import os
from datetime import timedelta
basedir = os.path.abspath(os.path.dirname(__file__))
class Config:
"""Base config."""
SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-key-placeholder')
SQLALCHEMY_TRACK_MODIFICATIONS = False
SESSION_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
REMEMBER_COOKIE_DURATION = timedelta(days=14)
PERMANENT_SESSION_LIFETIME = timedelta(days=1)
@staticmethod
def init_app(app):
pass
class DevelopmentConfig(Config):
DEBUG = True
SESSION_COOKIE_SECURE = False
SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, '..', 'instance', 'development.db')
class TestingConfig(Config):
TESTING = True
SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, '..', 'instance', 'testing.db')
WTF_CSRF_ENABLED = False
class ProductionConfig(Config):
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
'sqlite:///' + os.path.join(basedir, '..', 'instance', 'production.db')
@classmethod
def init_app(cls, app):
Config.init_app(app)
# Production-specific logging
import logging
from logging.handlers import RotatingFileHandler
log_dir = os.path.join(basedir, '..', 'logs')
os.makedirs(log_dir, exist_ok=True)
file_handler = RotatingFileHandler(
os.path.join(log_dir, 'app.log'),
maxBytes=10485760, # 10MB
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('App startup')
config = {
'development': DevelopmentConfig,
'testing': TestingConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}