Overview
Soft-Bee API follows a feature-based structure where each business feature is organized as a self-contained module with its own domain, application, and infrastructure layers.
Root Structure
soft-bee-api/
├── app.py # Application factory
├── config.py # Configuration management
├── requirements.txt # Python dependencies
├── .env # Environment variables
├── src/ # Source code
│ ├── api/ # API routing
│ ├── core/ # Shared core functionality
│ ├── features/ # Business features
│ └── shared/ # Shared utilities
├── tests/ # Test suite
└── docs/ # Documentation
Application Entry Point
app.py
The application factory that creates and configures the Flask app:
from flask import Flask
from flask_cors import CORS
from src.core.database.db import init_app
from src.api.router import register_features
from config import get_config
def create_app ( config_name : str = None , testing : bool = False ):
app = Flask( __name__ )
# Load configuration
config_class = get_config()
app.config.from_object(config_class)
# Enable CORS
CORS(app, resources = { r "/api/ * " : { "origins" : "*" }})
# Initialize database
init_app(app)
# Register features
features_to_register = [ 'auth' ] # Add more features here
registered_features = register_features(app, features_to_register)
return app
The factory pattern makes it easy to create different app instances for testing, development, and production.
config.py
Environment-based configuration:
import os
from dotenv import load_dotenv
load_dotenv()
class Config :
"""Base configuration"""
SECRET_KEY = os.getenv( 'SECRET_KEY' , 'dev-secret-key' )
JWT_SECRET_KEY = os.getenv( "JWT_KEY" , "secret-key-default" )
JWT_ALGORITHM = os.getenv( "ALGORITHM" , "HS256" )
FRONTEND_URL = os.getenv( "FRONTEND_URL" , "http://localhost:3000" )
class LocalConfig ( Config ):
DEBUG = True
DATABASE_URL = os.getenv( "DATABASE_URL" ,
"postgresql://postgres:postgres@localhost:5432/softbee_local" )
class ProductionConfig ( Config ):
DEBUG = False
DATABASE_URL = os.getenv( "DATABASE_URL" )
if not DATABASE_URL :
raise ValueError ( "DATABASE_URL is required in production" )
config = {
'local' : LocalConfig,
'production' : ProductionConfig,
'testing' : TestingConfig,
'default' : LocalConfig
}
Source Directory Structure
src/api/ - API Routing
Handles feature registration and routing:
src/api/
├── __init__.py
└── router.py # Feature router
router.py - Dynamic feature registration:
from flask import Flask
from typing import List
class FeatureRouter :
"""Router que registra todas las features"""
def __init__ ( self , app : Flask):
self .app = app
self .registered_features: List[ str ] = []
def register ( self , feature_name : str , enabled : bool = True ) -> bool :
"""Registrar una feature individual"""
if not enabled:
return False
try :
# Import the feature module
module = __import__ (
f "src.features. { feature_name } " ,
fromlist = [ '' ]
)
# Find and register blueprint
blueprint = getattr (module, f ' { feature_name } _bp' , None )
if blueprint:
self .app.register_blueprint(blueprint)
self .registered_features.append(feature_name)
print ( f "✅ Feature ' { feature_name } ' registrada" )
return True
except ImportError as e:
print ( f "❌ Feature ' { feature_name } ' no encontrada: { e } " )
return False
Features are registered dynamically, making it easy to enable/disable features without changing code.
src/core/ - Core Functionality
Shared infrastructure that all features use:
src/core/
├── database/
│ └── db.py # Database connection and session management
└── dependencies/
└── containers.py # Dependency injection containers
Database Module:
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, scoped_session
from flask import Flask, g
def init_app ( app : Flask):
"""Initialize database with Flask app"""
engine = create_engine(app.config[ 'DATABASE_URL' ])
session_factory = sessionmaker( bind = engine)
app.db_session = scoped_session(session_factory)
def get_db ():
"""Get database session for current request"""
if 'db' not in g:
g.db = current_app.db_session()
return g.db
Dependency Container:
src/core/dependencies/containers.py
from dependency_injector import containers, providers
class AuthContainer ( containers . DeclarativeContainer ):
"""Dependency container for auth feature"""
config = providers.Configuration()
db_session = providers.Dependency()
# Repositories
user_repository = providers.Factory(
UserRepositoryImpl,
db_session = db_session
)
# Services
jwt_service = providers.Singleton(
JWTService,
secret_key = config.auth.jwt_secret_key
)
# Use cases
login_use_case = providers.Factory(
LoginUserUseCase,
user_repository = user_repository,
token_service = jwt_service
)
class MainContainer ( containers . DeclarativeContainer ):
"""Main application container"""
config = providers.Configuration()
db_session = providers.Dependency()
# Feature containers
auth = providers.Container(
AuthContainer,
db_session = db_session,
config = config.auth
)
src/features/ - Business Features
Each feature follows the same structure:
src/features/
└── auth/ # Authentication feature
├── __init__.py # Exports auth_bp blueprint
├── domain/ # Business logic
│ ├── entities/
│ │ └── user.py
│ ├── value_objects/
│ │ ├── email.py
│ │ └── password.py
│ ├── events/
│ │ └── auth_events.py
│ ├── exceptions/
│ │ └── auth_exceptions.py
│ └── services/
├── application/ # Use cases and DTOs
│ ├── use_cases/
│ │ ├── login_user.py
│ │ └── register_user.py
│ ├── dto/
│ │ ├── auth_dto.py
│ │ └── user_dto.py
│ ├── interfaces/
│ │ ├── repositories/
│ │ │ └── user_repository.py
│ │ └── services/
│ │ └── token_service.py
│ └── mappers/
│ └── user_mapper.py
├── infrastructure/ # Technical implementation
│ ├── repositories/
│ │ └── user_repository_impl.py
│ ├── models/
│ │ └── user_model.py
│ └── services/
│ └── security/
│ ├── jwt_handler.py
│ └── password_hasher.py
└── presentation/ # API layer
└── api/v1/
├── endpoints/
│ └── auth.py
└── schemas/
└── auth_schemas.py
Pure business logic with no framework dependencies:
entities/ : Business objects with behavior (User, Apiary, Hive)
value_objects/ : Immutable objects defined by attributes (Email, Password)
events/ : Domain events (UserRegistered, HiveInspected)
exceptions/ : Business rule violations
services/ : Domain services for operations involving multiple entities
Application workflows that orchestrate domain logic:
use_cases/ : Business workflows (LoginUser, RegisterUser)
dto/ : Data Transfer Objects for crossing boundaries
interfaces/ : Contracts that infrastructure must implement
mappers/ : Convert between entities, DTOs, and models
infrastructure/ - Technical Details
Concrete implementations of technical concerns:
repositories/ : Database implementations
models/ : SQLAlchemy or other ORM models
services/ : External services (email, SMS, payments)
presentation/ - API Layer
HTTP interface for the feature:
endpoints/ : Flask blueprints with routes
schemas/ : Request/response validation (Marshmallow)
dependencies/ : Route-level dependency injection
Feature init .py
Each feature exports its blueprint:
src/features/auth/__init__.py
"""Authentication Feature"""
from .presentation.api.v1.endpoints import auth_bp
__all__ = [ 'auth_bp' ]
This makes it easy for the router to discover and register features automatically.
src/shared/ - Shared Utilities
Utilities used across multiple features:
src/shared/
└── utils/
├── file_handler.py # File upload/download
├── validators.py # Common validation logic
└── formatters.py # Data formatting
Adding a New Feature
To add a new feature (e.g., “hives”):
Create feature directory
mkdir -p src/features/hives/{domain,application,infrastructure,presentation}
Implement the layers
Create entities, use cases, repositories, and endpoints following the structure above
Export the blueprint
src/features/hives/__init__.py
from .presentation.api.v1.endpoints import hives_bp
__all__ = [ 'hives_bp' ]
Register in app.py
features_to_register = [ 'auth' , 'hives' ] # Add 'hives'
The modular structure makes it easy to add, remove, or modify features without affecting others.
Key Files Reference
app.py Application factory and initialization
config.py Environment-based configuration
router.py Dynamic feature registration
containers.py Dependency injection setup
Related Pages
Clean Architecture Understand the three layers in detail
Dependency Injection Learn how dependencies are wired