This guide covers all configuration options for Checawaa, including email setup, user management, scheduler settings, security configuration, and customization options.
Most configuration is done through editing the main application file (app.py) and JSON data files. Changes typically require restarting the application to take effect.
If using MFA, you may need to create an app-specific password in your Microsoft account settings.
app.config['MAIL_SERVER'] = 'smtp.yourcompany.com'app.config['MAIL_PORT'] = 587 # or 465 for SSLapp.config['MAIL_USE_TLS'] = True # False if using SSLapp.config['MAIL_USE_SSL'] = False # True if using port 465app.config['MAIL_USERNAME'] = '[email protected]'app.config['MAIL_PASSWORD'] = 'secure-password'
Contact your IT department for the correct SMTP settings.
scheduler.add_job( enviar_recordatorio_automatizado, 'cron', hour=7, # Changed from 8 minute=30 # Changed from 0)
Send reminders at multiple times:
# First reminder at 7:30 AMscheduler.add_job( enviar_recordatorio_automatizado, 'cron', hour=7, minute=30)# Second reminder at 8:15 AMscheduler.add_job( enviar_recordatorio_automatizado, 'cron', hour=8, minute=15)
Skip weekends:
scheduler.add_job( enviar_recordatorio_automatizado, 'cron', day_of_week='mon-fri', # Monday to Friday only hour=8, minute=0)
Different times for different days:
# 8 AM on Monday-Thursdayscheduler.add_job( enviar_recordatorio_automatizado, 'cron', day_of_week='mon-thu', hour=8, minute=0)# 9 AM on Friday (casual Fridays start later)scheduler.add_job( enviar_recordatorio_automatizado, 'cron', day_of_week='fri', hour=9, minute=0)
How often employees send their location:Current setting: Every 50 minutes
// In templates/index.html:27setInterval(enviarUbicacion, 50 * 60 * 1000);
Changing the frequency:
More Frequent (30 min)
setInterval(enviarUbicacion, 30 * 60 * 1000);
Pros: Better accuracy, more data points
Cons: More battery usage, higher server load
Less Frequent (90 min)
setInterval(enviarUbicacion, 90 * 60 * 1000);
Pros: Better battery life, lower server load
Cons: Less frequent verification
Consider your organization’s needs. If employees are highly mobile, more frequent updates provide better verification. For stationary office workers, less frequent updates may suffice.
For larger deployments, consider migrating to a database:
SQLite implementation example
import sqlite3# Initialize databaseconn = sqlite3.connect('data/checawaa.db')cursor = conn.cursor()# Create tablescursor.execute('''CREATE TABLE IF NOT EXISTS usuarios ( id INTEGER PRIMARY KEY, username TEXT UNIQUE NOT NULL, password_hash TEXT NOT NULL, email TEXT NOT NULL)''')cursor.execute('''CREATE TABLE IF NOT EXISTS registros ( id INTEGER PRIMARY KEY, usuario TEXT NOT NULL, lat REAL NOT NULL, lon REAL NOT NULL, fecha DATE NOT NULL, hora TIME NOT NULL)''')conn.commit()
msg = Message("⚠️ Recordatorio Automático: Inicia tu Turno", sender=app.config['MAIL_USERNAME'], recipients=destinatarios)msg.body = "Buenos días. Son las 8:00 AM y el sistema aún no detecta tu registro de hoy. Por favor inicia tu monitoreo."
Customize to your needs:
Bilingual email example
msg.body = """Good morning / Buenos días,It's 8:00 AM and the system has not detected your attendance record yet.Please start your shift tracking.Son las 8:00 AM y el sistema aún no detecta tu registro de hoy.Por favor inicia tu monitoreo.Thank you / Gracias,Company Attendance System"""
HTML email with formatting
from flask_mail import Messagemsg = Message("⚠️ Attendance Reminder", sender=app.config['MAIL_USERNAME'], recipients=destinatarios)msg.html = """<html><body style="font-family: Arial, sans-serif;"> <h2 style="color: #dc3545;">Attendance Reminder</h2> <p>Good morning,</p> <p>It's 8:00 AM and we haven't received your attendance check-in yet.</p> <p><strong>Please log in and start your shift tracking.</strong></p> <hr> <p style="font-size: 12px; color: #666;"> This is an automated message from the Company Attendance System. </p></body></html>"""
# Add indexes for faster queriescursor.execute('CREATE INDEX idx_fecha ON registros(fecha)')cursor.execute('CREATE INDEX idx_usuario ON registros(usuario)')cursor.execute('CREATE INDEX idx_usuario_fecha ON registros(usuario, fecha)')
Caching attendance data
from functools import lru_cachefrom datetime import datetime, timedelta@lru_cache(maxsize=128)def get_attendance_for_date(date_string): registros = leer_json(REGISTROS_FILE) return [r for r in registros if r['fecha'] == date_string]# Clear cache after new recordsdef update_location(): # ... save new record ... get_attendance_for_date.cache_clear()
Pagination for large datasets
# In monitor route, show only recent recordsfrom datetime import datetime, timedeltathirty_days_ago = (datetime.now() - timedelta(days=30)).strftime("%Y-%m-%d")asistencia = [ reg for reg in todos_registros if reg.get('fecha', '') >= thirty_days_ago]
import jsonfrom datetime import datetime, timedelta# Archive records older than 90 dayscutoff = (datetime.now() - timedelta(days=90)).strftime("%Y-%m-%d")registros = leer_json(REGISTROS_FILE)current = [r for r in registros if r['fecha'] >= cutoff]archive = [r for r in registros if r['fecha'] < cutoff]# Save current recordsguardar_json(REGISTROS_FILE, current)# Save archivearchive_file = f"data/archive_{cutoff}.json"guardar_json(archive_file, archive)print(f"Archived {len(archive)} records, kept {len(current)}")
Remove duplicate entries:
import jsonregistros = leer_json(REGISTROS_FILE)# Remove duplicates (same user, date, time)seen = set()unique = []for r in registros: key = (r['usuario'], r['fecha'], r['hora']) if key not in seen: seen.add(key) unique.append(r)print(f"Removed {len(registros) - len(unique)} duplicates")guardar_json(REGISTROS_FILE, unique)