- Created app/ package with 6 modules: - __init__.py: Application factory (create_app function) - routes.py: All route handlers (473 lines) - models.py: Data persistence layer (41 lines) - validators.py: Input validation functions (48 lines) - email_service.py: Email sending functions (85 lines) - utils.py: Utility functions (30 lines) - Implemented Flask application factory pattern - Created run.py as minimal entry point - Updated all test imports to use new module structure - Fixed template/static folder paths for package structure - All 102 tests passing - Improved maintainability with clear separation of concerns - Follows Flask best practices for scalable applications
259 lines
9.9 KiB
Markdown
259 lines
9.9 KiB
Markdown
<objective>
|
|
Refactor the monolithic app.py (664 lines) into a well-organized, modular Flask application structure using the application factory pattern. The goal is to improve code maintainability, testability, and separation of concerns while preserving all existing functionality.
|
|
|
|
This refactoring will make the codebase easier to navigate, enable better unit testing of individual components, and follow Flask best practices for scalable applications.
|
|
</objective>
|
|
|
|
<context>
|
|
Current state:
|
|
- Single app.py file contains routes, validation logic, email functions, storage helpers, and Flask app initialization
|
|
- 102 passing tests that import directly from app module
|
|
- Flask application with CSRF protection, rate limiting, file uploads, and email notifications
|
|
- Tech stack: Flask 3.0.0, Flask-Mail, Flask-WTF, PyYAML
|
|
|
|
Target state:
|
|
- Organized app/ package structure with separated concerns
|
|
- Flask application factory pattern (create_app function)
|
|
- Maintained backward compatibility for all existing functionality
|
|
- All 102 tests updated and passing
|
|
|
|
Review the current implementation:
|
|
@app.py
|
|
</context>
|
|
|
|
<requirements>
|
|
1. **Create app/ package structure**:
|
|
- `app/__init__.py` - Application factory (create_app function), Flask app initialization
|
|
- `app/routes.py` - All route handlers (@app.route decorators)
|
|
- `app/models.py` - Data models and storage functions (save/load application data)
|
|
- `app/validators.py` - All validation functions (email, phone, year, zip, file extensions)
|
|
- `app/email_service.py` - Email-related functions (send_resume_email, send_hr_notification)
|
|
- `app/utils.py` - Helper functions (path helpers, rate limiting, file handling)
|
|
|
|
2. **Implement Flask application factory pattern**:
|
|
- Create `create_app(config_class=Config)` function in `app/__init__.py`
|
|
- Initialize extensions (mail, csrf) within factory
|
|
- Register blueprints or routes within factory
|
|
- Update main entry point to use factory
|
|
|
|
3. **Maintain all existing functionality**:
|
|
- All routes must work identically
|
|
- CSRF protection, rate limiting, file uploads, email notifications unchanged
|
|
- Session handling, flash messages, redirects work as before
|
|
- Error handlers preserved
|
|
|
|
4. **Update test suite**:
|
|
- Modify test imports to use new module structure
|
|
- Update fixtures to work with application factory
|
|
- Ensure all 102 tests pass after refactoring
|
|
- No changes to test logic, only imports and app initialization
|
|
|
|
5. **Update main entry point**:
|
|
- Create `run.py` or update existing entry point to use `create_app()`
|
|
- Ensure development server still runs with `python run.py` or `flask run`
|
|
|
|
6. **Preserve imports and dependencies**:
|
|
- Keep all existing imports (Flask, yaml, werkzeug, etc.)
|
|
- Maintain proper circular import prevention
|
|
- Use relative imports within app/ package
|
|
</requirements>
|
|
|
|
<implementation>
|
|
**Module separation strategy**:
|
|
|
|
1. **app/__init__.py** should contain:
|
|
- Import statements for Flask, extensions
|
|
- Extension instances (mail, csrf) initialized but not bound
|
|
- `create_app(config_class=Config)` function that:
|
|
- Creates Flask app instance
|
|
- Loads configuration
|
|
- Initializes extensions (mail.init_app, csrf.init_app)
|
|
- Registers routes (import and register blueprint or routes)
|
|
- Registers error handlers
|
|
- Returns app instance
|
|
|
|
2. **app/routes.py** should contain:
|
|
- All @app.route decorated functions
|
|
- Import necessary validators, models, email_service, utils
|
|
- Either use Blueprint or accept app parameter for route registration
|
|
- Preserve all route logic exactly as is
|
|
|
|
3. **app/models.py** should contain:
|
|
- Path helper functions (get_application_path, get_data_file_path, get_attachments_path)
|
|
- Data persistence functions (load_application_data, save_application_data)
|
|
- Any data structure or schema-related code
|
|
|
|
4. **app/validators.py** should contain:
|
|
- validate_email, validate_phone, validate_year, validate_zip
|
|
- allowed_file function
|
|
- Each function should be independent and easily testable
|
|
|
|
5. **app/email_service.py** should contain:
|
|
- send_resume_email function
|
|
- send_hr_notification function
|
|
- Requires access to mail instance and app.config
|
|
- Use current_app for accessing config when needed
|
|
|
|
6. **app/utils.py** should contain:
|
|
- check_rate_limit function
|
|
- Any other utility functions not fitting elsewhere
|
|
|
|
**Important considerations**:
|
|
|
|
- **Circular imports**: To avoid circular imports between routes and models:
|
|
- Routes import from models, validators, email_service, utils
|
|
- Models should NOT import from routes
|
|
- Use `from flask import current_app` to access app instance in helper functions
|
|
|
|
- **Extension access**: For mail, csrf in separate modules:
|
|
- Initialize extensions in `app/__init__.py`
|
|
- Import and use them in routes/email_service: `from app import mail, csrf`
|
|
- OR pass as parameters where needed
|
|
|
|
- **Configuration access**: Use `current_app.config` in utility functions instead of `app.config`
|
|
|
|
- **Route registration**: Two approaches (choose one):
|
|
- Blueprint approach: Create Blueprint in routes.py, register in factory
|
|
- Direct approach: Import route functions and call them with app instance
|
|
|
|
- **Error handlers**: Register in `create_app()` factory function
|
|
|
|
**WHY this structure**:
|
|
- Separation of concerns makes each module independently testable
|
|
- Application factory enables multiple app instances for testing
|
|
- Smaller files are easier to navigate and maintain
|
|
- Follows Flask community best practices for production applications
|
|
- Enables future scaling (add more routes, validators, services without bloating single file)
|
|
</implementation>
|
|
|
|
<migration_steps>
|
|
Execute refactoring in this order to minimize breaking changes:
|
|
|
|
1. **Create app/ package**:
|
|
- Create `app/` directory
|
|
- Create `app/__init__.py` with imports and extension initialization
|
|
|
|
2. **Extract validators** (least dependencies):
|
|
- Move validation functions to `app/validators.py`
|
|
- Update imports in app.py
|
|
- Run tests to verify
|
|
|
|
3. **Extract models** (storage layer):
|
|
- Move path helpers and data functions to `app/models.py`
|
|
- Update imports in app.py
|
|
- Run tests to verify
|
|
|
|
4. **Extract email service**:
|
|
- Move email functions to `app/email_service.py`
|
|
- Ensure mail instance is accessible
|
|
- Update imports in app.py
|
|
- Run tests to verify
|
|
|
|
5. **Extract utilities**:
|
|
- Move rate limiting and other utils to `app/utils.py`
|
|
- Update imports in app.py
|
|
- Run tests to verify
|
|
|
|
6. **Extract routes**:
|
|
- Move all route handlers to `app/routes.py`
|
|
- Keep route registration in app.py temporarily
|
|
- Run tests to verify
|
|
|
|
7. **Implement application factory**:
|
|
- Create `create_app()` in `app/__init__.py`
|
|
- Move app initialization into factory
|
|
- Update `app.py` or create `run.py` to use factory
|
|
- Run tests to verify
|
|
|
|
8. **Update all tests**:
|
|
- Update imports in all test files
|
|
- Update app fixture in conftest.py to use factory
|
|
- Run full test suite
|
|
- Fix any remaining import issues
|
|
|
|
9. **Final cleanup**:
|
|
- Remove old app.py or convert to minimal run.py
|
|
- Verify all functionality works
|
|
- Run full test suite one final time
|
|
</migration_steps>
|
|
|
|
<test_updates>
|
|
Update test files to work with new structure:
|
|
|
|
**tests/conftest.py** changes:
|
|
```python
|
|
from app import create_app
|
|
from app import mail
|
|
|
|
@pytest.fixture
|
|
def app():
|
|
"""Create and configure a test Flask application instance."""
|
|
test_app = create_app()
|
|
# ... rest of configuration
|
|
yield test_app
|
|
```
|
|
|
|
**All test files** should update imports:
|
|
- Change `from app import validate_email` → `from app.validators import validate_email`
|
|
- Change `from app import send_resume_email` → `from app.email_service import send_resume_email`
|
|
- Change `from app import load_application_data` → `from app.models import load_application_data`
|
|
- And so on for all imports
|
|
|
|
Run tests after each major change to catch import errors early.
|
|
</test_updates>
|
|
|
|
<output>
|
|
Create the following new files:
|
|
|
|
- `./app/__init__.py` - Application factory and extension initialization
|
|
- `./app/routes.py` - All route handlers
|
|
- `./app/models.py` - Data persistence layer
|
|
- `./app/validators.py` - Validation functions
|
|
- `./app/email_service.py` - Email sending functions
|
|
- `./app/utils.py` - Utility functions (rate limiting, etc.)
|
|
|
|
Modify:
|
|
- `./app.py` → Convert to `./run.py` (or keep as minimal entry point using factory)
|
|
- `./tests/conftest.py` - Update app fixture to use create_app()
|
|
- `./tests/*.py` - Update all imports to new module structure
|
|
|
|
Delete after successful migration:
|
|
- Original `./app.py` (only if converted to run.py)
|
|
</output>
|
|
|
|
<verification>
|
|
Before declaring complete, verify:
|
|
|
|
1. **All tests pass**: Run `pytest tests/ -v` and confirm all 102 tests pass
|
|
2. **Application runs**: Start server with `python run.py` or `flask run` and verify pages load
|
|
3. **No circular imports**: Python can import app package without errors
|
|
4. **All routes work**: Test critical user flow:
|
|
- Submit email on page 1
|
|
- Fill personal info on page 2
|
|
- Fill motivation on page 3
|
|
- Upload file and submit on page 4
|
|
- View confirmation on page 5
|
|
- Access /application/<session_id>/ view
|
|
- Download uploaded file
|
|
5. **Email functionality**: HR notification sent on submission (check logs)
|
|
6. **No broken imports**: All test files import successfully
|
|
|
|
If any tests fail, carefully review:
|
|
- Import statements in test files
|
|
- Application context in helper functions (use current_app)
|
|
- Extension initialization in factory
|
|
- Route registration in factory
|
|
</verification>
|
|
|
|
<success_criteria>
|
|
- app/ package created with 6 modules (__init__, routes, models, validators, email_service, utils)
|
|
- Application factory pattern implemented (create_app function)
|
|
- Original app.py converted to minimal run.py entry point
|
|
- All 102 tests passing with updated imports
|
|
- Application runs and all features work identically
|
|
- Code is more maintainable with clear separation of concerns
|
|
- No circular import errors
|
|
- Flask development server starts successfully
|
|
</success_criteria>
|
|
Completed: Sa 27 Dez 2025 22:29:29 CET
|