9.3 KiB
Development Guide
This guide covers the architecture, code organization, and contribution guidelines for the Romanoff Fire Alarm Management System.
Architecture Overview
Application Structure
romanoff/
├── run.py # Entry point - starts Flask dev server
├── import_data.py # Data import utility
├── requirements.txt # Dependencies
├── app/
│ ├── __init__.py # Flask app factory
│ ├── models.py # SQLAlchemy models
│ ├── routes.py # Web routes & API endpoints
│ ├── templates/ # Jinja2 templates
│ └── static/ # CSS, JavaScript assets
└── instance/ # SQLite database (auto-created)
Design Patterns
Flask App Factory
The application uses the factory pattern in app/__init__.py:
def create_app():
app = Flask(__name__)
# Configure app
db.init_app(app)
# Register blueprints
app.register_blueprint(main_bp)
app.register_blueprint(api_bp, url_prefix='/api')
return app
Blueprint Organization
Routes are organized into two blueprints:
main_bp- Web routes serving HTML pagesapi_bp- REST API endpoints (prefixed with/api)
Model-View Separation
- Models (
models.py) handle data persistence - Routes (
routes.py) handle request/response logic - Templates (
templates/) handle presentation
Data Flow
User Browser
↓
Flask Routes (routes.py)
↓
SQLAlchemy Models (models.py)
↓
SQLite Database (instance/romanoff.db)
Database Schema
Entity Relationship
┌─────────────┐
│ Job │
├─────────────┤
│ id (PK) │
│ job_number │───────┐
│ job_name │ │
│ ... │ │
└─────────────┘ │
│ │
│ 1:N │ 1:N
↓ ↓
┌─────────────┐ ┌─────────────┐
│ Phase │ │ Material │
├─────────────┤ ├─────────────┤
│ id (PK) │ │ id (PK) │
│ job_id (FK) │ │ job_id (FK) │
│ phase_type │ │ part_number │
│ ... │ │ ... │
└─────────────┘ └─────────────┘
Models
Job - Core project entity
- Contains budget, team assignments, milestones, dates
- Has many phases and materials (cascade delete)
Phase - Project schedule phases
- Types: rough_in, trim, commissioning, final, turnover
- Tracks dates, completion status, man hours
Material - Inventory tracking
- Tracks ordering, receipt, and delivery
Frontend Architecture
Template Hierarchy
base.html
├── dashboard.html - Charts and statistics
├── jobs.html - Job list with filters
├── job_detail.html - Single job view
├── job_form.html - Create/edit job
├── schedule.html - Phase management
└── materials.html - Material tracking
JavaScript Strategy
Shared Utilities (static/js/app.js)
// API helpers
async function apiGet(url) { ... }
async function apiPost(url, data) { ... }
async function apiPut(url, data) { ... }
async function apiDelete(url) { ... }
// Formatting
function formatCurrency(value) { ... }
function formatDate(dateString) { ... }
// UI helpers
function showToast(message, type) { ... }
function getProgressClass(percent) { ... }
function debounce(func, wait) { ... }
function confirmAction(message) { ... }
Page-Specific Scripts
Each template contains embedded <script> blocks for page-specific functionality:
- Data fetching and rendering
- Event handlers
- Filter/search logic
CSS Organization
Bootstrap 5 provides the base styling. Custom styles in static/css/style.css add:
- Card shadows and hover effects
- Progress bar color states
- Responsive table adjustments
- Form styling enhancements
Development Setup
Prerequisites
- Python 3.8+
- pip
Local Development
-
Create virtual environment:
python -m venv .venv source .venv/bin/activate -
Install dependencies:
pip install -r requirements.txt -
Run development server:
python run.py -
Access at
http://localhost:5000
Database
The SQLite database is automatically created on first run in instance/romanoff.db. Tables are created via db.create_all() in the app factory.
To reset the database:
rm instance/romanoff.db
python run.py
Importing Test Data
python import_data.py
Imports from Excel files (if present):
Raleigh jobs FIRE ALARM INFORMATION.xlsxschedule_updated.xlsm
Code Guidelines
Python Style
- Follow PEP 8 style guidelines
- Use type hints where helpful
- Keep functions focused and small
- Document complex logic with comments
Database Operations
# Reading data
jobs = Job.query.all()
job = Job.query.get_or_404(job_id)
# Creating records
job = Job(job_number='JOB-001', job_name='New Job')
db.session.add(job)
db.session.commit()
# Updating records
job.percent_complete = 0.5
db.session.commit()
# Deleting records
db.session.delete(job)
db.session.commit()
API Response Patterns
# Success with data
return jsonify(job.to_dict())
# Success with created resource
return jsonify(job.to_dict()), 201
# Success with no content
return '', 204
# Error
return jsonify({'error': 'Not found'}), 404
Frontend JavaScript
// Fetch pattern
try {
const data = await apiGet('/api/jobs');
renderJobs(data);
} catch (error) {
showToast('Error loading jobs', 'danger');
}
// Event handling
document.getElementById('searchInput')
.addEventListener('input', debounce(filterJobs, 300));
Adding New Features
Adding a New Model
-
Define model in
models.py:class NewModel(db.Model): __tablename__ = 'new_models' id = db.Column(db.Integer, primary_key=True) # ... fields def to_dict(self): return { ... } -
Add API routes in
routes.py -
Create template if needed
-
Restart server (tables auto-create)
Adding a New Page
- Create template in
templates/ - Add web route in
routes.py:@main_bp.route('/newpage') def new_page(): return render_template('newpage.html') - Add navigation link in
base.html
Adding API Endpoints
-
Add route function in
routes.py:@api_bp.route('/newresource', methods=['GET']) def get_new_resource(): # ... logic return jsonify(data) -
Document in
API.md
Testing
Currently no automated tests are implemented. Recommended testing approach:
Manual Testing
- Test all CRUD operations through UI
- Verify API responses with curl or Postman
- Test edge cases (empty data, invalid input)
Future Testing Setup
pip install pytest pytest-flask
# tests/test_api.py
def test_get_jobs(client):
response = client.get('/api/jobs')
assert response.status_code == 200
Deployment Considerations
Production Checklist
- Set
SECRET_KEYenvironment variable - Configure production database (PostgreSQL recommended)
- Use production WSGI server (Gunicorn, uWSGI)
- Enable HTTPS
- Add authentication/authorization
- Configure logging
- Set up database backups
Environment Variables
| Variable | Description | Required |
|---|---|---|
SECRET_KEY |
Flask secret key | Yes |
DATABASE_URL |
Database connection string | No (defaults to SQLite) |
Example Production Config
# config.py
import os
class ProductionConfig:
SECRET_KEY = os.environ['SECRET_KEY']
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
SQLALCHEMY_TRACK_MODIFICATIONS = False
Contributing
Workflow
- Create a feature branch from
main - Make changes following code guidelines
- Test thoroughly
- Submit pull request with description
Commit Messages
Use clear, descriptive commit messages:
Add material delivery tracking featureFix job completion percentage calculationUpdate dashboard chart colors
Code Review
Before merging:
- Code follows style guidelines
- No obvious bugs or security issues
- Documentation updated if needed
- Changes tested manually
Troubleshooting
Common Issues
Database locked error
- Stop any other processes accessing the database
- Delete
.dbfile and restart if corrupted
Import errors
- Ensure virtual environment is activated
- Run
pip install -r requirements.txt
Template not found
- Check file name matches route
- Verify file is in
templates/directory
API returns 404
- Check URL matches route definition
- Verify blueprint prefix (
/api)
Debug Mode
Debug mode is enabled by default in development. Check Flask output for:
- Request/response logging
- SQL queries (if enabled)
- Stack traces on errors