A modern, web-based dormitory management system built with Flask and SQLite. Designed for universities and dormitory administrators to efficiently manage buildings, rooms, tenants, and payments.
- Features
- System Objectives
- Scope & Limitations
- Technology Stack
- Database Schema
- Installation
- Usage
- Project Structure
- User Roles
- Development Guide
- Troubleshooting
- Contributing
- License
- User Management: Create and manage admin, landlord, and student accounts
- Building Management: Track multiple dormitory buildings with floor details
- Room Management: Monitor room availability, types, and pricing
- Assignment Tracking: Manage tenant-to-room assignments with contract periods
- Payment Processing: Record and track rent payments with multiple payment methods
- Report Generation: Generate occupancy and payment reports
- Role-Based Access Control: Different permissions for admins, landlords, and students
- Modern, responsive design using Bootstrap 5
- Clean, intuitive navigation
- Mobile-friendly layout
- Real-time form validation
- Flash message notifications
- Streamline Dormitory Operations: Automate manual processes for room assignments and payment tracking
- Centralized Data Management: Maintain a single source of truth for all dormitory information
- Improve Transparency: Provide clear visibility of room availability and payment status
- Reduce Administrative Overhead: Minimize paperwork through digital record-keeping
- Support Multiple Stakeholders: Serve administrators, landlords, and students with role-specific features
- Facilitate data-driven decision making through reports
- Ensure data integrity with relational database constraints
- Provide audit trails for all transactions
- Enable scalability for multiple buildings and properties
✅ User authentication and authorization
✅ Building and room inventory management
✅ Room type categorization with pricing
✅ Tenant assignment and contract tracking
✅ Payment recording and history
✅ Basic reporting (occupancy, payments)
✅ Role-based access control (Admin, Landlord, Student)
✅ CSV export functionality
✅ SQLite database for data persistence
❌ Mobile application
❌ Online payment processing/gateway integration
❌ Real-time chat or messaging system
❌ Maintenance request tracking
❌ Room inquiry/application system
❌ Email notifications (SMTP configured but optional)
❌ Advanced analytics and dashboards
❌ Document management (contracts, IDs)
❌ Multi-tenancy support
❌ Automated rent reminders
- Single Database: Uses SQLite (not recommended for high-concurrency production)
- Local File Storage: No cloud storage integration
- Basic Reporting: Limited to predefined report types
- Manual Payment Entry: No automatic payment reconciliation
- No API: Currently web-interface only
- Limited Search: Basic filtering, no full-text search
- Python 3.8+: Core programming language
- Flask 3.0.0: Web framework
- SQLite3: Database engine
- Werkzeug 3.0.1: Password hashing and security
- HTML5/CSS3: Markup and styling
- Bootstrap 5.3.2: UI framework
- Vanilla JavaScript: Client-side interactivity
- python-dotenv: Environment variable management
- Git: Version control
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ USERS │◄────────│ BUILDINGS │────────►│ ROOMS │
│ │ owns │ │ has │ │
│ - user_id │ │ - building_id│ │ - room_id │
│ - username │ │ - owner_id │ │ - building_id│
│ - role │ │ │ │ - type_id │
└─────────────┘ └──────────────┘ └─────────────┘
│ │
│ has has │
│ │
▼ ▼
┌──────────────────┐ ┌─────────────┐
│ ROOM_ASSIGNMENTS │◄─────────────────────────│ ROOM_TYPES │
│ │ │ │
│ - assignment_id │ │ - type_id │
│ - user_id │ │ - type_name │
│ - room_id │ │ - base_rate │
└──────────────────┘ └─────────────┘
│
│ has
│
▼
┌─────────────┐
│ PAYMENTS │
│ │
│ - payment_id│
│ - user_id │
│ - assign_id │
└─────────────┘
┌─────────────┐
│ REPORTS │
│ │
│ - report_id │
│ - generated │
└─────────────┘
Stores all system users (admins, landlords, students)
user_id INTEGER PRIMARY KEY
username VARCHAR(100) UNIQUE
password_hash VARCHAR(255)
role VARCHAR(20) -- 'admin', 'landlord', 'student'
first_name VARCHAR(100)
last_name VARCHAR(100)
email VARCHAR(150) UNIQUE
phone VARCHAR(30)
birth_date DATE
is_active BOOLEAN DEFAULT 1
created_at DATETIME
updated_at DATETIMEDormitory buildings and properties
building_id INTEGER PRIMARY KEY
building_name VARCHAR(100)
address VARCHAR(255)
total_floors INTEGER
owner_id INTEGER FK -> users(user_id)
is_active BOOLEAN DEFAULT 1
created_at DATETIME
updated_at DATETIMERoom categories with pricing
type_id INTEGER PRIMARY KEY
type_name VARCHAR(50)
base_rate DECIMAL(10,2)
capacity INTEGER
description TEXT
features TEXT
is_active BOOLEAN DEFAULT 1
created_at DATETIME
updated_at DATETIMEIndividual room units
room_id INTEGER PRIMARY KEY
building_id INTEGER FK -> buildings(building_id)
type_id INTEGER FK -> room_types(type_id)
room_number VARCHAR(50)
floor_number INTEGER
is_available BOOLEAN DEFAULT 1
notes TEXT
created_at DATETIME
updated_at DATETIMETenant-to-room assignments
assignment_id INTEGER PRIMARY KEY
user_id INTEGER FK -> users(user_id)
room_id INTEGER FK -> rooms(room_id)
start_date DATE
end_date DATE
monthly_rate DECIMAL(10,2)
status VARCHAR(20) -- 'active', 'completed', 'cancelled', 'pending'
assigned_by INTEGER FK -> users(user_id)
notes TEXT
created_at DATETIME
updated_at DATETIMERent payment records
payment_id INTEGER PRIMARY KEY
user_id INTEGER FK -> users(user_id)
assignment_id INTEGER FK -> room_assignments(assignment_id)
amount DECIMAL(10,2)
payment_method VARCHAR(30)
payment_date DATE
payment_period_start DATE
payment_period_end DATE
receipt_number VARCHAR(100) UNIQUE
recorded_by INTEGER FK -> users(user_id)
notes TEXT
created_at DATETIME
updated_at DATETIMEGenerated system reports
report_id INTEGER PRIMARY KEY
generated_by INTEGER FK -> users(user_id)
report_type VARCHAR(50)
report_title VARCHAR(200)
file_path VARCHAR(500)
generated_on DATETIMEPython 3.8 or higher
pip (Python package manager)
Git (optional)git clone https://github.com/yourusername/accommo.git
cd accommo# Windows
python -m venv venv
venv\Scripts\activate
# macOS/Linux
python3 -m venv venv
source venv/bin/activatepip install -r requirements.txt# Copy .env.example to .env (or create new .env file)
cp .env.example .env
# Edit .env with your settings
# Minimum required: FLASK_SECRET_KEY# Create database schema
python -c "from db import init_db; init_db()"
# Seed with sample data
python seed_data.pypython app.pyVisit: http://localhost:5000
| Role | Username | Password |
|---|---|---|
| Admin | admin | admin123 |
| Landlord | landlord1 | landlord123 |
| Student | student1 | student123 |
- Log in with admin credentials
- Add landlords via Users → Add User
- Create buildings via Buildings → Add Building
- View all system data and manage users
- Log in with landlord credentials
- View your assigned buildings
- Monitor room occupancy
- Track tenant payments
- Register for an account
- View available rooms
- Check your room assignment
- View payment history
accommo/
├── app.py # Main Flask application
├── db.py # Database connection and schema
├── seed_data.py # Sample data seeder
├── requirements.txt # Python dependencies
├── .env # Environment variables (not in git)
├── .gitignore # Git ignore rules
│
├── database/
│ ├── manager.db # SQLite database file
│ ├── ERD.md # Entity Relationship Diagram (DELETE)
│ └── data_dictionary.md # Data dictionary (DELETE)
│
├── templates/ # HTML templates
│ ├── _base.html # Base layout
│ ├── index.html # Dashboard
│ ├── logIn.html # Login page
│ ├── register.html # Registration page
│ ├── 02_users.html # Users list
│ ├── 02_add_user.html # Add user form
│ ├── 02_edit_user.html # Edit user form
│ ├── 03_buildings.html # Buildings list
│ ├── 03_add_building.html # Add building form
│ ├── 03_edit_building.html # Edit building form
│ ├── 04_room_types.html # Room types view
│ ├── 05_rooms.html # Rooms list
│ ├── 06_assignments.html # Assignments list
│ ├── 07_payment.html # Payment form
│ ├── 07_payments.html # Payments list (duplicate - consolidate)
│ └── 08_reports.html # Reports list
│
├── static/ # Static assets (optional)
│ ├── css/
│ └── js/
│
└── docs/ # Documentation (optional)
└── README.md # This file
These files are now consolidated into this README:
database/ERD.md✂️database/data_dictionary.md✂️SYSTEM_STRUCTURE.md✂️SETUP_SQLITE.md✂️QUICK_REFERENCE.md(if exists) ✂️CHANGES.md(if exists) ✂️
Permissions:
- Full system access
- User management (create, edit, delete)
- Building management (all buildings)
- Room management (all rooms)
- Assignment management (all assignments)
- Payment management (all payments)
- Report generation
- System configuration
Typical Tasks:
- Onboard new landlords
- Oversee all properties
- Generate system-wide reports
- Manage user accounts
Permissions:
- View own buildings
- View rooms in own buildings
- View tenant assignments in own buildings
- View payments for own properties
- Export data for own properties
Typical Tasks:
- Monitor property occupancy
- Track rental income
- Review tenant information
- Export payment reports
Permissions:
- View available rooms
- View own assignment
- View own payment history
- Update own profile
Typical Tasks:
- Browse available rooms
- Check room details
- View payment receipts
- Update contact information
# In app.py
@app.route('/your_route', methods=['GET', 'POST'])
@role_required('admin', 'landlord') # Optional: restrict by role
def your_function():
if request.method == 'POST':
# Handle form submission
data = request.form.get('field_name')
conn = get_db_connection()
cursor = conn.cursor()
try:
cursor.execute("INSERT INTO table_name (field) VALUES (?)", (data,))
conn.commit()
flash('Success message', 'success')
return redirect(url_for('your_route'))
except Exception as e:
flash(f'Error: {e}', 'danger')
finally:
cursor.close()
conn.close()
# GET request - show form or data
return render_template('your_template.html')# In db.py, add to init_db() function
cursor.execute("""
CREATE TABLE IF NOT EXISTS your_table (
id INTEGER PRIMARY KEY AUTOINCREMENT,
field_name VARCHAR(100),
foreign_key INTEGER,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (foreign_key) REFERENCES other_table(id)
)
""")<!-- templates/your_template.html -->
{% extends '_base.html' %}
{% block title %}Your Page Title{% endblock %}
{% block content %}
<div class="container-modern">
<div class="page-header">
<h1 class="page-title">Your Title</h1>
<p class="page-subtitle">Your subtitle</p>
</div>
<!-- Your content here -->
</div>
{% endblock %}# In route handler
from functools import wraps
def validate_form(*required_fields):
"""Decorator to validate required form fields"""
def decorator(f):
@wraps(f)
def wrapped(*args, **kwargs):
if request.method == 'POST':
missing = [field for field in required_fields
if not request.form.get(field)]
if missing:
flash(f'Missing required fields: {", ".join(missing)}', 'danger')
return redirect(request.url)
return f(*args, **kwargs)
return wrapped
return decorator
@app.route('/example', methods=['GET', 'POST'])
@validate_form('username', 'email', 'password')
def example():
# Form is already validated
passcursor.execute("""
SELECT r.room_id, r.room_number, b.building_name, rt.type_name
FROM rooms r
LEFT JOIN buildings b ON r.building_id = b.building_id
LEFT JOIN room_types rt ON r.type_id = rt.type_id
WHERE r.is_available = ?
ORDER BY r.room_number
""", (1,))
rows = [dict(row) for row in cursor.fetchall()]try:
cursor.execute("""
INSERT INTO table_name (field1, field2)
VALUES (?, ?)
""", (value1, value2))
conn.commit()
flash('Record added successfully', 'success')
except sqlite3.IntegrityError:
flash('Duplicate entry or constraint violation', 'danger')
except Exception as e:
flash(f'Database error: {e}', 'danger')cursor.execute("""
UPDATE table_name
SET field1 = ?, field2 = ?
WHERE id = ?
""", (value1, value2, record_id))
conn.commit()# Check for dependent records first
cursor.execute("SELECT COUNT(*) FROM child_table WHERE parent_id = ?", (record_id,))
if cursor.fetchone()[0] > 0:
# Soft delete
cursor.execute("UPDATE parent_table SET is_active = 0 WHERE id = ?", (record_id,))
flash('Record deactivated (has dependent records)', 'warning')
else:
# Hard delete
cursor.execute("DELETE FROM parent_table WHERE id = ?", (record_id,))
flash('Record deleted successfully', 'success')from functools import wraps
def role_required(*allowed_roles):
"""Decorator to restrict routes by user role"""
def decorator(f):
@wraps(f)
def wrapped(*args, **kwargs):
if not session.get('user_id'):
flash('Please log in to access this page', 'warning')
return redirect(url_for('login'))
role = session.get('role')
if role not in allowed_roles:
flash('Permission denied', 'danger')
return redirect(url_for('home'))
return f(*args, **kwargs)
return wrapped
return decorator
# Usage
@app.route('/admin_only')
@role_required('admin')
def admin_function():
pass
@app.route('/landlord_admin')
@role_required('admin', 'landlord')
def landlord_admin_function():
pass<form method="POST">
<div class="form-group mb-3">
<label class="form-label-modern">Field Label</label>
<input type="text" name="field_name" class="form-control-modern"
placeholder="Enter value" required>
<small style="color: var(--gray-600); font-size: 0.8125rem;">
Help text here
</small>
</div>
<div class="d-flex gap-2 justify-content-end">
<a href="{{ url_for('cancel_route') }}" class="btn-secondary-modern">Cancel</a>
<button type="submit" class="btn-primary-modern">Submit</button>
</div>
</form><div class="card-modern">
<table class="table-modern w-100">
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th style="text-align: right;">Actions</th>
</tr>
</thead>
<tbody>
{% for item in items %}
<tr>
<td>{{ item.field }}</td>
<td>{{ item.field2 }}</td>
<td style="text-align: right;">
<div class="d-flex gap-2 justify-content-end">
<a href="{{ url_for('edit', id=item.id) }}"
class="btn-secondary-modern"
style="padding: 0.375rem 0.75rem; font-size: 0.875rem;">
Edit
</a>
</div>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>Error: no such table: users
Solution:
python -c "from db import init_db; init_db()"
python seed_data.pyIssue: Correct credentials not working
Solutions:
1. Check database has users: sqlite3 database/manager.db "SELECT * FROM users;"
2. Reseed database:
rm database/manager.db
python -c "from db import init_db; init_db()"
python seed_data.py
3. Check password hashing in login routeError: ModuleNotFoundError: No module named 'flask'
Solution:
1. Activate virtual environment
2. pip install -r requirements.txtError: Address already in use
Solution:
# Change port in app.py
app.run(debug=True, host="0.0.0.0", port=5001) # Use different portIssue: Cannot access admin-only pages
Solution:
1. Check session: visit /debug_session
2. Verify role in database
3. Log out and log back inEnable detailed error messages:
# In .env
DEBUG=TrueCheck session data:
Visit: http://localhost:5000/debug_session# Open SQLite database
sqlite3 database/manager.db
# Common commands
.tables # List all tables
.schema users # Show table schema
SELECT * FROM users LIMIT 5; # View sample data
.quit # Exit- Fork the Repository
- Create Feature Branch
git checkout -b feature/your-feature-name
- Make Changes
- Follow existing code style
- Add comments for complex logic
- Update documentation if needed
- Test Thoroughly
- Test all CRUD operations
- Check role-based permissions
- Verify responsive design
- Commit Changes
git commit -m "Add: description of your changes" - Push to Branch
git push origin feature/your-feature-name
- Create Pull Request
- Python: Follow PEP 8
- HTML: 4-space indentation
- CSS: Use existing CSS variables
- JavaScript: ES6+ syntax
Type: Brief description
Types:
- Add: New feature
- Fix: Bug fix
- Update: Modify existing feature
- Remove: Delete code/feature
- Docs: Documentation only
- Style: Formatting changes
- Refactor: Code restructuring
Example:
Add: CSV export for room assignments
Fix: Login validation for empty passwords
Update: Building form to include owner selection
- Change default passwords
- Set strong
FLASK_SECRET_KEY - Disable
DEBUGmode - Use HTTPS
- Implement rate limiting
- Add CSRF protection
- Sanitize all user inputs
- Use environment variables for sensitive data
- Regular database backups
- Update dependencies regularly
- Implement logging and monitoring
# Already implemented in app.py
from werkzeug.security import generate_password_hash, check_password_hash
# Hash password before storing
password_hash = generate_password_hash(password)
# Verify password
check_password_hash(stored_hash, input_password)This project is licensed under the MIT License - see the LICENSE file for details.
- Flask framework and community
- Bootstrap for UI components
- SQLite for database engine
- Contributors and testers
For issues, questions, or contributions:
- Issues: GitHub Issues
- Email: your.email@example.com
- Documentation: Wiki
- Advanced search and filtering
- Email notification system
- PDF report generation
- Maintenance request module
- Contract document management
- Payment gateway integration
- Mobile-responsive improvements
- RESTful API
- Mobile app (iOS/Android)
- Multi-language support
- Advanced analytics dashboard
- Calendar integration
- Automated rent reminders
Last Updated: December 2, 2025
Version: 1.0.0
Status: Production Ready ✅