From 63a2aeebbc661cce5a6c2309044058cc2249f34c Mon Sep 17 00:00:00 2001 From: Meghdad Date: Sat, 2 May 2026 00:44:52 +0330 Subject: [PATCH] add welcome page and README.md --- README.md | 105 +++++++++++++---- app/main/routes.py | 2 +- app/static/css/app.css | 156 +++++++++++++++++++++++++- app/static/img/welcome-hero.png | Bin 0 -> 69564 bytes app/static/js/kiosk.js | 2 +- app/templates/admin/account_form.html | 2 +- app/templates/admin/accounts.html | 2 +- app/templates/attendance/index.html | 2 +- app/templates/attendance/kiosk.html | 2 +- app/templates/auth/login.html | 2 +- app/templates/base.html | 2 +- app/templates/dashboard.html | 2 +- app/templates/errors/403.html | 2 +- app/templates/errors/404.html | 2 +- app/templates/errors/500.html | 2 +- app/templates/people/detail.html | 4 +- app/templates/people/form.html | 2 +- app/templates/people/index.html | 2 +- app/templates/welcome.html | 68 +++++++++++ 19 files changed, 319 insertions(+), 42 deletions(-) create mode 100644 app/static/img/welcome-hero.png create mode 100644 app/templates/welcome.html diff --git a/README.md b/README.md index f664082..6e7b4bf 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,58 @@ # Face Attendance -A modern Flask attendance application with staff authentication, role-based access control, face enrollment, camera-based recognition, and attendance reporting. +Face Attendance is a modern Flask application for managing attendance with face recognition. It includes staff authentication, role-based authorization, person enrollment, a webcam kiosk, attendance reporting, database migrations, and a responsive English UI. + +## Features + +- Application factory pattern with modular Blueprints. +- Admin-created staff accounts with `admin`, `operator`, and `viewer` roles. +- Secure login/logout with Flask-Login and Werkzeug password hashing. +- CSRF-protected forms and secure session/cookie defaults. +- Person enrollment with one to four face reference images. +- Webcam-based recognition kiosk for check-in and check-out events. +- Attendance reports with person, timestamp, source, confidence, and staff user. +- SQLAlchemy models with Flask-Migrate/Alembic migrations. +- Pytest coverage for authentication, roles, and attendance behavior. +- Modern Bootstrap-based UI with an English welcome page. ## Roles -- `admin`: manages staff accounts, enrolls people, records attendance, and views reports. -- `operator`: enrolls people, uses the attendance kiosk, and views reports. -- `viewer`: read-only access to people and attendance reports. +| Role | Permissions | +| --- | --- | +| `admin` | Manage staff accounts, enroll people, use the kiosk, and view reports. | +| `operator` | Enroll people, use the kiosk, and view reports. | +| `viewer` | View people and attendance reports only. | Only admins can create staff accounts. ## Requirements - Python 3.11 or 3.12 is recommended for production. -- Native build prerequisites for `face-recognition`/`dlib` may be required by your OS. +- Native build prerequisites for `face-recognition` and `dlib`. +- SQLite for local development, or PostgreSQL/MySQL for production. - A production WSGI server such as Gunicorn on Linux or Waitress on Windows. +## Project Structure + +```text +app/ + __init__.py Application factory + config.py Environment-based configuration + extensions.py Flask extensions + auth/ Login/logout + admin/ Staff account management + attendance/ Kiosk and attendance reports + people/ Person enrollment and profiles + recognition/ Recognition API routes + models/ SQLAlchemy models + services/ Business logic + templates/ Jinja templates + static/ CSS, JS, and images +migrations/ Alembic migrations +tests/ Pytest suite +wsgi.py WSGI entrypoint +``` + ## Setup ```powershell @@ -25,15 +62,28 @@ pip install -r requirements.txt Copy-Item .env.example .env ``` -Edit `.env` and set a strong `SECRET_KEY`. For production, set `APP_ENV=production` and use a durable database URL. +Edit `.env` before running the app. + +```env +APP_ENV=development +SECRET_KEY=replace-with-a-long-random-secret +DATABASE_URL=sqlite:///instance/face_attendance.sqlite3 +FACE_MATCH_TOLERANCE=0.55 +MAX_CONTENT_LENGTH=8388608 +``` ## Database -Initialize the database with migrations: +Apply migrations: ```powershell $env:FLASK_APP = "wsgi:app" flask db upgrade +``` + +Create the first admin account: + +```powershell flask create-admin ``` @@ -44,7 +94,7 @@ $env:FLASK_APP = "wsgi:app" flask run ``` -Open `http://127.0.0.1:5000` and sign in with the admin account created above. +Open `http://127.0.0.1:5000`. ## Tests @@ -52,23 +102,30 @@ Open `http://127.0.0.1:5000` and sign in with the admin account created above. pytest ``` -The tests use an isolated SQLite database and disable CSRF only for test requests. +The test suite uses an in-memory SQLite database and disables CSRF only for test requests. -## Production Notes +## Production Deployment -- Use HTTPS. Production config enables secure cookies. -- Set `SECRET_KEY`, `DATABASE_URL`, and `APP_ENV=production`. -- Run `flask db upgrade` during deployment. -- Run behind a reverse proxy that forwards HTTPS headers correctly. -- Treat face encodings as biometric data. Restrict database access, define a retention policy, and back up securely. +1. Set `APP_ENV=production`. +2. Set a strong `SECRET_KEY`. +3. Set `DATABASE_URL` to your production database. +4. Install native dependencies for `face-recognition`/`dlib`. +5. Run `flask db upgrade`. +6. Serve through a production WSGI server behind HTTPS. +7. Configure your reverse proxy to forward HTTPS headers correctly. -## What Changed +Production config enables secure cookies. Do not run the Flask development server in production. -- Replaced the legacy single-file Flask script with an application factory and Blueprints. -- Added SQLAlchemy models and Alembic migrations. -- Added Flask-Login authentication, admin-created accounts, password hashing, and role checks. -- Replaced raw SQL with ORM queries. -- Removed global enrollment state. -- Rebuilt the UI in English with reusable templates and responsive Bootstrap-based layouts. -- Added CSRF protection, secure cookie settings, security headers, validation, and error pages. -- Added pytest coverage for authentication, roles, models, and attendance recording. +## Security Notes + +- Face encodings are biometric data. Restrict database access and define a retention policy. +- Keep `.env` out of version control. +- Use HTTPS in production. +- Rotate staff accounts when operators leave the organization. +- Review database backups and access logs regularly. + +## Troubleshooting + +- If recognition endpoints return a dependency error, install `face-recognition` on Python 3.11 or 3.12 with the required `dlib` build tools. +- If the default Flask port is blocked on Windows, run `flask run --port 8000`. +- If database tables are missing, run `flask db upgrade`. diff --git a/app/main/routes.py b/app/main/routes.py index 1e652c7..6420a74 100644 --- a/app/main/routes.py +++ b/app/main/routes.py @@ -12,7 +12,7 @@ bp = Blueprint("main", __name__) def index(): if current_user.is_authenticated: return redirect(url_for("main.dashboard")) - return redirect(url_for("auth.login")) + return render_template("welcome.html") @bp.get("/dashboard") diff --git a/app/static/css/app.css b/app/static/css/app.css index 4ce9159..0ae3fd5 100644 --- a/app/static/css/app.css +++ b/app/static/css/app.css @@ -257,11 +257,152 @@ a { text-align: center; } +.welcome-page { + margin: -2rem -1.5rem -3rem; + background: #f3f6f7; +} + +.welcome-hero { + min-height: 78vh; + position: relative; + display: flex; + align-items: center; + isolation: isolate; + overflow: hidden; + padding: 7rem clamp(1.5rem, 6vw, 7rem) 5rem; + background: url("../img/welcome-hero.png") center / cover no-repeat; + color: #ffffff; +} + +.welcome-hero::before { + content: ""; + position: absolute; + inset: 0; + z-index: -1; + background: rgba(6, 15, 28, 0.58); +} + +.welcome-nav { + position: absolute; + top: 1.5rem; + left: clamp(1.5rem, 6vw, 7rem); + right: clamp(1.5rem, 6vw, 7rem); + display: flex; + align-items: center; + justify-content: space-between; + gap: 1rem; +} + +.welcome-brand { + color: #ffffff; + font-size: 1.05rem; + font-weight: 700; + text-decoration: none; +} + +.welcome-copy { + max-width: 760px; +} + +.welcome-copy h1 { + margin: 0; + font-size: clamp(3rem, 7vw, 7rem); + font-weight: 800; + line-height: 0.95; +} + +.welcome-copy p { + max-width: 660px; + margin: 1.4rem 0 0; + color: rgba(255, 255, 255, 0.86); + font-size: clamp(1.05rem, 1.5vw, 1.35rem); +} + +.welcome-eyebrow { + color: rgba(255, 255, 255, 0.72); +} + +.welcome-actions { + display: flex; + flex-wrap: wrap; + gap: 0.85rem; + margin-top: 2rem; +} + +.welcome-section, +.workflow-band { + padding: clamp(3rem, 6vw, 5rem) clamp(1.5rem, 6vw, 7rem); +} + +.welcome-section-header { + max-width: 760px; + margin-bottom: 1.5rem; +} + +.welcome-section-header h2, +.workflow-band h2 { + margin: 0; + font-size: clamp(2rem, 3vw, 3rem); +} + +.feature-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 1rem; +} + +.feature-card { + min-height: 250px; + padding: 1.25rem; + border: 1px solid var(--border); + border-radius: 8px; + background: #ffffff; +} + +.feature-card span { + color: var(--accent); + font-weight: 800; +} + +.feature-card h3 { + margin: 2.5rem 0 0.75rem; + font-size: 1.15rem; +} + +.feature-card p { + color: var(--muted); + margin: 0; +} + +.workflow-band { + display: grid; + grid-template-columns: minmax(0, 0.75fr) minmax(320px, 1fr); + gap: 2rem; + align-items: start; + background: #172033; + color: #ffffff; +} + +.workflow-band .eyebrow, +.workflow-list { + color: rgba(255, 255, 255, 0.72); +} + +.workflow-list { + display: grid; + gap: 1rem; + margin: 0; + padding-left: 1.25rem; + font-size: 1.05rem; +} + @media (max-width: 992px) { .stats-grid, .upload-grid, .detail-grid, - .kiosk-grid { + .kiosk-grid, + .feature-grid, + .workflow-band { grid-template-columns: 1fr 1fr; } } @@ -276,11 +417,22 @@ a { .stats-grid, .upload-grid, .detail-grid, - .kiosk-grid { + .kiosk-grid, + .feature-grid, + .workflow-band { grid-template-columns: 1fr; } .detail-list { grid-template-columns: 1fr; } + + .welcome-hero { + min-height: 82vh; + padding-top: 6rem; + } + + .welcome-actions .btn { + width: 100%; + } } diff --git a/app/static/img/welcome-hero.png b/app/static/img/welcome-hero.png new file mode 100644 index 0000000000000000000000000000000000000000..a1df4e571a3c2762b2d9795bd740b85253611c99 GIT binary patch literal 69564 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 literal 0 HcmV?d00001 diff --git a/app/static/js/kiosk.js b/app/static/js/kiosk.js index 7aced6f..907cf07 100644 --- a/app/static/js/kiosk.js +++ b/app/static/js/kiosk.js @@ -82,7 +82,7 @@ function renderFaces(faces) { const confidence = face.confidence === null ? "n/a" : `${Math.round(face.confidence * 100)}%`; card.innerHTML = `

${escapeHtml(face.full_name)}

-

${escapeHtml(face.employee_id)} · Confidence ${confidence}
${escapeHtml(face.last_presence)}

+

${escapeHtml(face.employee_id)} - Confidence ${confidence}
${escapeHtml(face.last_presence)}

diff --git a/app/templates/admin/account_form.html b/app/templates/admin/account_form.html index 7e6a6e8..b9ff2d0 100644 --- a/app/templates/admin/account_form.html +++ b/app/templates/admin/account_form.html @@ -1,7 +1,7 @@ {% extends "base.html" %} {% from "macros/forms.html" import render_field, render_select %} -{% block title %}Create account · Face Attendance{% endblock %} +{% block title %}Create account - Face Attendance{% endblock %} {% block content %}