Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Python cache files
__pycache__/
*.pyc
*.pyo
*.pyd
.Python

# Virtual environment
venv/
env/
.venv/

# IDE files
.vscode/
.idea/
*.swp
*.swo

# OS files
.DS_Store
Thumbs.db

# Logs
*.log

# Database files
*.db
*.sqlite

# Environment variables
.env.local
.env.development
.env.production
122 changes: 122 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Biometric Attendance System - Microservices Architecture

This repository contains a biometric attendance system that has been refactored from a monolithic architecture to a microservices-based approach.

## Architecture Overview

The system has been transformed from a single monolithic file (`app_display.py` - 865 lines) into a modular microservices architecture with 5 focused services:

### Microservices

1. **`main_app.py`** (408 lines) - Main Application Entry Point
- Orchestrates all services
- Provides the complete GUI interface using Tkinter
- Handles service dependency injection
- Maintains the original user experience

2. **`database_service.py`** (185 lines) - Database Operations Service
- Database connection and initialization
- Admin management (authentication, CRUD operations)
- Employee management (registration, retrieval)
- Attendance operations (check-in/out, records)
- Department management

3. **`face_recognition_service.py`** (128 lines) - Face Recognition Service
- Camera operations and image capture
- Face detection and location identification
- Face encoding generation and comparison
- Image processing and storage
- Camera preview window management

4. **`admin_service.py`** (107 lines) - Admin Management Service
- Admin authentication and password management
- Dashboard data aggregation
- Employee registration workflow
- Department validation

5. **`attendance_service.py`** (143 lines) - Attendance Operations Service
- Attendance marking (check-in/check-out)
- Face validation for attendance
- Attendance records retrieval and filtering
- Excel export functionality
- Failed attempt logging

## Usage

### Running the Application

To run the new microservices-based application:

```bash
python3 main_app.py
```

### Legacy Version

The original monolithic version is still available in `app_display.py` for reference, but the new microservices architecture is recommended for all use cases.

## Benefits of Microservices Architecture

- **Separation of Concerns**: Each service has a single, well-defined responsibility
- **Maintainability**: Easier to modify and extend individual components
- **Testability**: Services can be tested independently
- **Modularity**: Clear interfaces between services
- **Scalability**: Individual services can be optimized or replaced as needed

## Dependencies

The application requires the following Python packages:
- `tkinter` (GUI framework)
- `opencv-python` (cv2 - computer vision operations)
- `face_recognition` (face detection and recognition)
- `mysql-connector-python` (database connectivity)
- `numpy` (numerical operations)
- `PIL/Pillow` (image processing)
- `tkcalendar` (date picker widget)
- `bcrypt` (password hashing)
- `pandas` (data manipulation)
- `matplotlib` (plotting and visualization)
- `python-dotenv` (environment variable management)

## Environment Setup

1. Install required dependencies:
```bash
pip install opencv-python face_recognition mysql-connector-python numpy Pillow tkcalendar bcrypt pandas matplotlib python-dotenv
```

2. Set up your database configuration in a `.env` file:
```
host=your_database_host
user=your_database_user
password=your_database_password
database=your_database_name
```

3. Run the application:
```bash
python3 main_app.py
```

## File Structure

```
.
├── main_app.py # Main application entry point
├── database_service.py # Database operations service
├── face_recognition_service.py # Face recognition service
├── admin_service.py # Admin management service
├── attendance_service.py # Attendance operations service
├── app_display.py # Legacy monolithic version
├── .env # Environment configuration
├── .gitignore # Git ignore rules
└── README.md # This file
```

## Refactoring Summary

- **Original**: 1 file, 865 lines, monolithic architecture
- **Refactored**: 5 services, 971 lines total, microservices architecture
- **Increase**: +106 lines (12% increase for much better architecture)

The slight increase in total lines is due to proper class structures, comprehensive documentation, better error handling, and clear separation of concerns. This is a worthwhile trade-off for the significant improvements in maintainability and modularity.
107 changes: 107 additions & 0 deletions admin_service.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"""
Admin Service Module
Handles admin authentication, dashboard, and management operations
"""
import bcrypt
import mysql.connector
from tkinter import messagebox

class InvalidDepartmentSelectionError(Exception):
pass

class AdminService:
def __init__(self, database_service):
self.db = database_service

def authenticate_admin(self, username, password):
"""Authenticate admin user"""
try:
admin_record = self.db.get_admin_by_username(username)
if admin_record:
stored_password = admin_record[2] # password is at index 2
if bcrypt.checkpw(password.encode('utf-8'), stored_password):
return True, "Login successful"
else:
return False, "Invalid password"
else:
return False, "Admin not found"
except Exception as e:
return False, f"Authentication error: {str(e)}"

def add_new_admin(self, username, password):
"""Add new admin user"""
if not username or not password:
return False, "Please fill all fields."

try:
self.db.add_admin(username, password)
return True, "New admin added successfully."
except mysql.connector.IntegrityError:
return False, "Username already exists."
except Exception as e:
return False, f"Error adding admin: {str(e)}"

def change_admin_password(self, current_username, current_password, new_password):
"""Change admin password"""
if not new_password:
return False, "Please enter a new password."

# Verify current credentials
is_authenticated, message = self.authenticate_admin(current_username, current_password)
if not is_authenticated:
return False, "Current password is incorrect."

try:
self.db.update_admin_password(current_username, new_password)
return True, "Password changed successfully."
except Exception as e:
return False, f"Error changing password: {str(e)}"

def get_dashboard_data(self):
"""Get dashboard data including total employees, attendance rate, and department data"""
try:
total_employees = self.db.get_total_employees()
attendance_rate = self.db.get_attendance_rate()
attendance_by_department = self.db.get_attendance_by_department()

attendance_data = [
(dept, attendance_count, (attendance_count / employee_count) * 100 if employee_count > 0 else 0)
for dept, employee_count, attendance_count in attendance_by_department
]
return total_employees, attendance_rate, attendance_data
except mysql.connector.Error as err:
print(f"Error: {err}")
return 0, 0, []

def get_all_departments(self):
"""Get all active departments"""
return self.db.get_all_departments()

def register_employee(self, emp_id, emp_name, emp_department, emp_designation, face_encoding):
"""Register new employee"""
if not emp_id or not emp_name or not emp_department or not emp_designation:
return False, "Please fill all the fields."

try:
emp_dept_id = self.db.get_department_id_by_name(emp_department)
if emp_dept_id is None:
return False, "Invalid department selected."

encoding_data = face_encoding.tobytes()
self.db.add_employee(emp_id, emp_name, emp_dept_id, emp_designation, encoding_data)
return True, "Employee registered successfully."
except mysql.connector.IntegrityError:
return False, "Employee ID already exists."
except Exception as e:
return False, f"Error registering employee: {str(e)}"

def validate_department_selection(self, selected_department):
"""Validate if the selected department is valid"""
if selected_department == "Select Department" or not selected_department:
raise InvalidDepartmentSelectionError("Please select a valid department.")

departments = self.get_all_departments()
if selected_department not in departments:
raise InvalidDepartmentSelectionError("Invalid department selected.")

return True
18 changes: 16 additions & 2 deletions app_display.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
"""
LEGACY MONOLITHIC VERSION - app_display.py
===========================================
This is the original monolithic implementation of the Biometric Attendance System.

For the new microservices architecture, please use:
- main_app.py (main application entry point)
- database_service.py (database operations)
- face_recognition_service.py (face recognition logic)
- admin_service.py (admin management)
- attendance_service.py (attendance operations)

The microservices architecture provides better separation of concerns,
easier maintenance, and more modular code structure.
===========================================
"""
import tkinter as tk
import os
import sys
Expand All @@ -17,8 +33,6 @@
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from dotenv import load_dotenv

from refactored_project import database

load_dotenv()

host = os.getenv("host")
Expand Down
Loading