Skip to content

Repository files navigation

TamTap Logo

TamTap

TamTap NFC-Based Attendance System with Camera Verification

Grade 12 ICT B Group 5 Capstone | FEU Roosevelt Marikina | S.Y. 2025–2026

Version License Node Python Platform

A locally hosted, TamTap NFC-Based Attendance System running on Raspberry Pi with camera verification and a real-time LAN dashboard.


πŸ“‘ Table of Contents


πŸ”­ Overview

TamTap is a locally hosted attendance system designed for FEU Roosevelt Marikina. Students tap their NFC cards on an RC522 reader connected to a Raspberry Pi 4B. The system captures a photo via Pi Camera v2 for face detection verification (Haar Cascade β€” detection only, no recognition), records the attendance in MongoDB, and broadcasts the event to a real-time LAN dashboard via Socket.IO.

All processing happens on-premise β€” no cloud, no internet dependency.


✨ Features

Category Feature
Attendance NFC tap β†’ Camera capture β†’ Face detection β†’ Record
Dashboard Real-time attendance feed via Socket.IO
Roles Admin, Adviser, Teacher β€” role-based access
Schedules Per-section weekly schedules with grace period/absent thresholds
Calendar Academic calendar with suspensions and no-class declarations
Notifications Pending absence tracking, excused marking
Export XLSX and PDF attendance reports
Offline Mode JSON fallback when MongoDB is unreachable
Logs Live systemd log streaming in admin panel
Buttons Physical GPIO buttons to start/restart/stop services
Photo Storage External SD card with internal fallback

πŸ— System Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        RASPBERRY PI 4B                          β”‚
β”‚                                                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚  β”‚  RC522 NFC   β”‚    β”‚  Pi Camera   β”‚    β”‚  I2C LCD     β”‚      β”‚
β”‚  β”‚  Reader      β”‚    β”‚  v2 (5MP)    β”‚    β”‚  16x2        β”‚      β”‚
β”‚  β”‚  (SPI)       β”‚    β”‚  (CSI)       β”‚    β”‚  (0x27)      β”‚      β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β”‚         β”‚                   β”‚                   β”‚               β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚              tamtap.py (Python 3.11)                     β”‚   β”‚
β”‚  β”‚         State Machine + Face Detection (Haar)            β”‚   β”‚
β”‚  β”‚         GPIO: Green LED (17) | Red LED (27) | Buzzer(18) β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                         β”‚ HTTP POST /api/hardware/*             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚              server.js (Node.js 20 / Express)            β”‚   β”‚
β”‚  β”‚         REST API + Socket.IO + Session Auth              β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                         β”‚                                       β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚              MongoDB (Local Instance)                    β”‚   β”‚
β”‚  β”‚         Collections: students, teachers, attendance,     β”‚   β”‚
β”‚  β”‚         admins, calendar, schedules, settings            β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                β”‚ LAN (port 3000)
                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                    β”‚   Browser Dashboard   β”‚
                    β”‚   (HTML/CSS/Vanilla JS)β”‚
                    β”‚   Tailwind + Chart.js  β”‚
                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Data Flow

Student taps NFC card
        β”‚
        β–Ό
  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
  β”‚ RC522 reads  │───▢│ Lookup student   │───▢│ Validate        β”‚
  β”‚ NFC UID      β”‚    β”‚ in DB (Mongo/JSON)β”‚   β”‚ schedule/time   β”‚
  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                       β”‚
                                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
                                              β”‚ Capture photo   β”‚
                                              β”‚ (rpicam-still)  β”‚
                                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                       β”‚
                                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
                                              β”‚ Haar cascade    β”‚
                                              β”‚ face detection  β”‚
                                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                                       β”‚
                                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                    β”‚                                     β”‚
                              Face detected?                        No face
                                    β”‚                                     β”‚
                              β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”                      β”Œβ”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”
                              β”‚ Save to DB β”‚                      β”‚ Red LED +     β”‚
                              β”‚ Green LED  β”‚                      β”‚ Buzzer fail   β”‚
                              β”‚ Buzzer OK  β”‚                      β”‚ LCD: FAIL     β”‚
                              β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜                      β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                    β”‚
                              β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                              β”‚ POST /api/hardware/ β”‚
                              β”‚ attendance          β”‚
                              β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                    β”‚
                              β”Œβ”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                              β”‚ Socket.IO broadcast β”‚
                              β”‚ attendance:new      β”‚
                              β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”§ Hardware Specifications

Component Model Interface Details
SBC Raspberry Pi 4B β€” 4GB RAM, Bookworm OS
NFC Reader RC522 SPI GPIO 8, 9, 10, 11, 25
LCD I2C 16x2 I2C Address 0x27
Camera Pi Camera v2 CSI 5MP, snapshot only
Green LED β€” GPIO 17 Success indicator
Red LED β€” GPIO 27 Failure indicator
Buzzer β€” GPIO 18 Via relay module
Start Button β€” GPIO 5 Active LOW, pull-up
Restart Button β€” GPIO 6 Active LOW, pull-up
Stop Button β€” GPIO 13 Hold 2.5s, Active LOW

GPIO Pin Map (BCM)

GPIO 5  ─── START button  (to GND)
GPIO 6  ─── RESTART button (to GND)
GPIO 8  ─── RC522 SDA/CS
GPIO 9  ─── RC522 MISO
GPIO 10 ─── RC522 MOSI
GPIO 11 ─── RC522 SCK
GPIO 13 ─── STOP button  (to GND, hold 2.5s)
GPIO 17 ─── Green LED (success)
GPIO 18 ─── Buzzer (via relay)
GPIO 25 ─── RC522 RST
GPIO 27 ─── Red LED (fail)
I2C SDA ─── LCD SDA
I2C SCL ─── LCD SCL

Wiring Diagram


πŸ›  Software Stack

Hardware Layer (Python 3.11)

Library Purpose
RPi.GPIO GPIO pin control (LEDs, buzzer)
mfrc522 RC522 NFC reader driver (SPI)
smbus I2C communication (LCD 16x2)
opencv-python-headless Face detection (Haar Cascade)
pymongo MongoDB driver (with JSON fallback)
python-dotenv Environment variable loading
pyserial Arduino serial communication

Backend (Node.js 20)

Library Purpose
express HTTP server & REST API
mongodb MongoDB native driver
socket.io Real-time WebSocket events
express-session Session-based authentication
connect-mongo MongoDB-backed session store
express-rate-limit Rate limiting (login, API)
bcryptjs Password hashing
cors Cross-origin requests (LAN)
multer File upload handling (XLSX import)
exceljs XLSX report generation
pdfkit PDF report generation
xlsx XLSX parsing (schedule import)
signale Structured console logging
dotenv Environment variable loading

Frontend (Multi-Page HTML)

Technology Purpose
HTML5 Page structure
CSS3 Styling
Vanilla JavaScript (ES6+) Client logic β€” no frameworks
Tailwind CSS Utility-first styling (CDN)
Chart.js Attendance analytics charts
SweetAlert2 Modal dialogs and alerts
Socket.IO Client Real-time attendance feed
Fetch API HTTP requests β€” no Axios

πŸ“ Project Structure

TamTap/
β”œβ”€β”€ .env                          # Environment variables (gitignored)
β”œβ”€β”€ .gitignore
β”œβ”€β”€ LICENSE                       # MIT License
β”œβ”€β”€ README.md                     # This file
β”œβ”€β”€ startup.sh                    # Systemd startup script for tamtap.py
β”œβ”€β”€ update.sh                     # Git pull + dependency update + restart
β”‚
β”œβ”€β”€ assets/
β”‚   β”œβ”€β”€ attendance_photos/        # Captured attendance photos (by date)
β”‚   β”œβ”€β”€ backgrounds/              # UI background images
β”‚   β”œβ”€β”€ icons/                    # Favicon and UI icons
β”‚   β”œβ”€β”€ logos/                    # FEU x TamTap branding logos
β”‚   β”œβ”€β”€ templates/                # Schedule import templates
β”‚   └── formats/                  # Export format assets
β”‚
β”œβ”€β”€ buttons/
β”‚   β”œβ”€β”€ button_listener.py        # GPIO button controller (start/restart/stop)
β”‚   β”œβ”€β”€ tamtap-buttons.service    # Systemd unit: button listener
β”‚   β”œβ”€β”€ tamtap-server.service     # Systemd unit: Node.js server
β”‚   └── README.md                 # Button wiring & setup guide
β”‚
β”œβ”€β”€ database/
β”‚   └── tamtap_users.json         # JSON fallback database
β”‚
β”œβ”€β”€ hardware/
β”‚   β”œβ”€β”€ tamtap.py                 # Main NFC attendance loop (state machine)
β”‚   β”œβ”€β”€ database.py               # Unified DB module (MongoDB + JSON sync)
β”‚   β”œβ”€β”€ register.py               # Student registration CLI
β”‚   β”œβ”€β”€ tamtap_admin.py           # Admin CLI (archive, manage, export)
β”‚   β”œβ”€β”€ archive_attendance.py     # Attendance archival utility
β”‚   β”œβ”€β”€ requirements.txt          # Python dependencies
β”‚   └── arduino/
β”‚       β”œβ”€β”€ rfid_reader.ino       # Arduino RFID reader firmware
β”‚       └── register_arduino.py   # Arduino-based NFC registration
β”‚
β”œβ”€β”€ software/
β”‚   β”œβ”€β”€ server.js                 # Express.js API server (main entry)
β”‚   β”œβ”€β”€ config.js                 # Server configuration
β”‚   β”œβ”€β”€ package.json              # Node.js dependencies
β”‚   β”œβ”€β”€ middleware/
β”‚   β”‚   β”œβ”€β”€ auth.js               # Session auth middleware (requireAuth, requireAdmin)
β”‚   β”‚   └── hardwareAuth.js       # Hardware API key auth (Pi β†’ Server)
β”‚   β”œβ”€β”€ routes/
β”‚   β”‚   β”œβ”€β”€ admin.js              # Teacher/student CRUD (admin only)
β”‚   β”‚   β”œβ”€β”€ archive.js            # Attendance archival management
β”‚   β”‚   β”œβ”€β”€ attendance.js         # Attendance queries (today, by date, range)
β”‚   β”‚   β”œβ”€β”€ auth.js               # Login/logout/session
β”‚   β”‚   β”œβ”€β”€ calendar.js           # Academic calendar management
β”‚   β”‚   β”œβ”€β”€ export.js             # XLSX/PDF report generation
β”‚   β”‚   β”œβ”€β”€ logs.js               # Live systemd log streaming
β”‚   β”‚   β”œβ”€β”€ notifications.js      # Pending absences & excused marking
β”‚   β”‚   β”œβ”€β”€ schedules.js          # Section schedule management
β”‚   β”‚   β”œβ”€β”€ stats.js              # Dashboard statistics & analytics
β”‚   β”‚   └── students.js           # Student/teacher data queries
β”‚   β”œβ”€β”€ scripts/
β”‚   β”‚   └── bootstrap-admin.js    # Initial admin account creation
β”‚   β”œβ”€β”€ utils/
β”‚   β”‚   β”œβ”€β”€ Logger.js             # Signale-based structured logging
β”‚   β”‚   β”œβ”€β”€ dateUtils.js          # Philippine timezone date utilities
β”‚   β”‚   β”œβ”€β”€ filenameSanitizer.js  # Photo filename sanitization
β”‚   β”‚   └── sanitize.js           # Input sanitization (NoSQL injection guard)
β”‚   └── public/
β”‚       β”œβ”€β”€ index.html            # Landing page
β”‚       β”œβ”€β”€ login.html            # Login page
β”‚       β”œβ”€β”€ dashboard.html        # Main dashboard
β”‚       β”œβ”€β”€ admin.html            # Admin panel
β”‚       β”œβ”€β”€ 404.html              # Custom 404 error page
β”‚       β”œβ”€β”€ privacy.html          # Privacy policy page
β”‚       β”œβ”€β”€ terms.html            # Terms of use page
β”‚       β”œβ”€β”€ researchers.html      # Research team page
β”‚       β”œβ”€β”€ css/
β”‚       β”‚   β”œβ”€β”€ fonts.css         # Shared @font-face definitions
β”‚       β”‚   β”œβ”€β”€ preloader.css     # Loading animation styles
β”‚       β”‚   β”œβ”€β”€ dashboard.css     # Dashboard page styles
β”‚       β”‚   β”œβ”€β”€ admin.css         # Admin panel styles
β”‚       β”‚   β”œβ”€β”€ login.css         # Login page styles
β”‚       β”‚   β”œβ”€β”€ researchers.css   # Researchers page styles
β”‚       β”‚   └── 404.css           # 404 page styles
β”‚       └── js/
β”‚           β”œβ”€β”€ preloader.js      # Loading animation logic
β”‚           β”œβ”€β”€ tailwind-config.js # Shared Tailwind CSS configuration
β”‚           β”œβ”€β”€ utils.js          # Shared utilities (XSS escape, etc.)
β”‚           β”œβ”€β”€ dashboard.js      # Dashboard page logic
β”‚           β”œβ”€β”€ admin.js          # Admin panel logic
β”‚           └── login.js          # Login page logic
β”‚
└── test/
    β”œβ”€β”€ test_rfid.py              # RFID reader test
    β”œβ”€β”€ test_lcd.py               # LCD display test
    β”œβ”€β”€ test_lcd_debug.py         # LCD debug utility
    β”œβ”€β”€ test_leds.py              # LED test
    β”œβ”€β”€ test_buzzer.py            # Buzzer test
    β”œβ”€β”€ test_dry_run.py           # Full system dry run (no hardware)
    └── excel_id.py               # Excel ID utility

πŸ“‹ Prerequisites

Hardware

  • Raspberry Pi 4B (4GB RAM) with Raspberry Pi OS Bookworm
  • RC522 NFC Reader module
  • I2C LCD 16x2 display
  • Pi Camera v2
  • 2x LEDs (green, red), 1x buzzer with relay
  • 3x push buttons (start, restart, stop)
  • NFC cards/tags (MIFARE)

Software

  • Python 3.11+
  • Node.js 20+
  • MongoDB 7+ (local instance)
  • Git

Enable Interfaces (on Raspberry Pi)

sudo raspi-config
# Enable: SPI, I2C, Camera (Legacy Camera if needed)

πŸš€ Installation & Setup

1. Clone the Repository

cd /home/charles
git clone https://github.com/CharlesNaig/TamTap.git
cd TamTap

2. Create Environment File

cp .env.example .env
# Edit .env with your MongoDB URI and settings

Required .env variables:

# MongoDB
MONGODB_URI=mongodb://localhost:27017/
MONGODB_NAME=tamtap

# Server
API_SERVER_PORT=3000
API_SERVER_HOST=0.0.0.0

# Session
SESSION_SECRET=your-random-secret-here

# Hardware β†’ Server communication
TAMTAP_API_URL=http://localhost:3000

# Hardware API Key (shared secret between Pi and server, prevents forged attendance)
HARDWARE_SECRET=your-hardware-secret-here

3. Setup Python Virtual Environment

python3 -m venv .venv
source .venv/bin/activate
pip install -r hardware/requirements.txt

4. Install Node.js Dependencies

cd software
npm install

5. Start MongoDB

sudo systemctl start mongod
sudo systemctl enable mongod

6. Bootstrap Admin Account

cd software
npm run bootstrap
# Default: admin / tamtap2026 (change immediately)

7. Install Systemd Services

# Copy service files
sudo cp buttons/tamtap-buttons.service /etc/systemd/system/
sudo cp buttons/tamtap-server.service /etc/systemd/system/

# Create tamtap.service for the hardware script
sudo systemctl daemon-reload
sudo systemctl enable tamtap-buttons.service
sudo systemctl enable tamtap-server.service
sudo systemctl enable tamtap.service

βš™οΈ Configuration

Server Config (software/config.js)

Setting Default Description
server.port 3000 HTTP server port
server.host 0.0.0.0 Bind address (all interfaces)
mongodb.maxPoolSize 10 Max MongoDB connections
session.maxAge 8 hours Session cookie lifetime
photos.baseDir ../assets/attendance_photos Internal photo storage
photos.externalDir /mnt/tamtap_photos External SD card (preferred)
socketio.pingTimeout 60000 Socket.IO ping timeout (ms)

Timing Constants (hardware/tamtap.py)

Constant Value Description
CAMERA_CAPTURE_TIME 1200 ms Camera shutter time
CAMERA_TIMEOUT 2.5 s subprocess timeout
NFC_POLL_INTERVAL 0.1 s NFC read poll interval
FACE_DETECTION_TIMEOUT 1.0 s Haar cascade timeout
MIN_FACE_SIZE (80, 80) Minimum face pixel size

πŸƒ Running the System

Development Mode

# Terminal 1: Start MongoDB
sudo systemctl start mongod

# Terminal 2: Start Node.js server (with auto-reload)
cd software
npm run dev

# Terminal 3: Start hardware script (on Raspberry Pi only)
source .venv/bin/activate
cd hardware
python tamtap.py

Production Mode (Systemd)

# Start all services
sudo systemctl start tamtap.service
sudo systemctl start tamtap-server.service
sudo systemctl start tamtap-buttons.service

# Or use physical START button (GPIO 5)

Access the Dashboard

Open a browser on any device on the same LAN:

http://<raspberry-pi-ip>:3000

πŸ“‘ API Reference

Base URL: http://<host>:3000/api

Authentication

Method Endpoint Auth Description
POST /api/auth/login Public Login (returns session cookie)
POST /api/auth/logout Session Destroy session
GET /api/auth/me Session Get current user info

Students & Teachers

Method Endpoint Auth Description
GET /api/students Session List all students
GET /api/students/:nfc_id Session Get student by NFC ID
GET /api/teachers Session List all teachers
GET /api/teachers/:nfc_id Session Get teacher by NFC ID

Admin (Admin Only)

Method Endpoint Auth Description
Teachers
GET /api/admin/teachers Admin List teachers with sections
GET /api/admin/teachers/:id Admin Get teacher by ID
POST /api/admin/teachers Admin Register new teacher
PUT /api/admin/teachers/:id Admin Update teacher
DELETE /api/admin/teachers/:id Admin Delete teacher
POST /api/admin/teachers/:id/reset-password Admin Reset teacher password
Students
GET /api/admin/students Admin List students (paginated, filterable)
POST /api/admin/students Admin Register new student
POST /api/admin/students/bulk Admin Bulk register (CSV)
PUT /api/admin/students/:nfc_id Admin Update student
DELETE /api/admin/students/:nfc_id Admin Delete student
POST /api/admin/students/archive-batch Admin Archive multiple students
GET /api/admin/students/archived Admin List archived students
POST /api/admin/students/restore Admin Restore archived student
DELETE /api/admin/students/archived/:nfc_id Admin Permanently delete archived
POST /api/admin/students/delete-batch Admin Permanently delete batch
Sections & Settings
GET /api/admin/sections Admin List all sections
GET /api/admin/settings Admin Get all settings
GET /api/admin/settings/:key Admin Get setting by key
PUT /api/admin/settings/:key Admin Update setting value
POST /api/admin/settings/saturday-toggle Admin Toggle Saturday classes

Attendance

Method Endpoint Auth Description
GET /api/attendance Session Today's records (?section=11-A)
GET /api/attendance/:date Session Records by date (YYYY-MM-DD)
GET /api/attendance/range Session Records by date range (?from=&to=)

Statistics

Method Endpoint Auth Description
GET /api/stats Session Dashboard statistics
GET /api/stats/summary Session Present/late/absent counts
GET /api/stats/daily Session Daily summary
GET /api/stats/weekly Session Weekly summary

Schedules

Method Endpoint Auth Description
GET /api/schedules Session All section schedules
GET /api/schedules/:section Session Specific section schedule
POST /api/schedules Admin Create schedule
PUT /api/schedules/:section Admin/Adviser Update schedule
DELETE /api/schedules/:section Admin Delete schedule
POST /api/schedules/import Admin Import from XLSX
GET /api/schedules/template Session Download XLSX template

Calendar

Method Endpoint Auth Description
GET /api/calendar Session Calendar events
POST /api/calendar Admin Add suspension/no-class
DELETE /api/calendar/:id Admin Remove event

Export

Method Endpoint Auth Description
GET /api/export/xlsx Session Download XLSX report
GET /api/export/pdf Session Download PDF report

Notifications

Method Endpoint Auth Description
GET /api/notifications/pending Session Students who haven't tapped
GET /api/notifications/count Session Pending absence count
POST /api/notifications/mark-excused Session Mark student excused
POST /api/notifications/mark-absent Session Confirm absent
POST /api/notifications/bulk-absent Session Mark all pending as absent

System Logs (Admin Only)

Method Endpoint Auth Description
GET /api/logs Admin All service logs
GET /api/logs/:service Admin Logs by service (buttons, server, hardware)

Hardware Bridge (API Key Protected)

Method Endpoint Auth Description
POST /api/hardware/attendance Hardware Key Record from tamtap.py
POST /api/hardware/fail Hardware Key Failure from tamtap.py
POST /api/hardware/status Hardware Key Status update from tamtap.py

Health Check

Method Endpoint Auth Description
GET /api/health Public Server health + uptime

πŸ—„ Database Schema

MongoDB Collections

students

{
  nfc_id: String,       // Unique NFC card UID (required, indexed)
  tamtap_id: String,    // Human-readable TamTap ID
  name: String,         // Full name
  first_name: String,
  last_name: String,
  email: String,
  grade: String,        // e.g., "12"
  section: String,      // e.g., "12-ICT-A"
  registered: String    // ISO date string
}

teachers

{
  username: String,           // Unique login username (indexed)
  password: String,           // bcrypt hash
  name: String,
  email: String,
  nfc_id: String,             // Optional (sparse unique index)
  tamtap_id: String,
  role_type: String,          // "admin" | "adviser" | "teacher"
  advised_section: String,    // For advisers only
  sections_handled: [String], // Sections this teacher manages
  forcePasswordChange: Boolean,
  created: String
}

admins

{
  username: String,     // Unique
  password: String,     // bcrypt hash
  name: String
}

attendance

{
  nfc_id: String,       // Student/teacher NFC UID
  tamtap_id: String,
  name: String,
  role: String,         // "student" | "teacher"
  date: String,         // "YYYY-MM-DD HH:MM:SS"
  time: String,         // "HH:MM:SS"
  session: String,      // "AM" | "PM"
  status: String,       // "present" | "late" | "absent" | "excused"
  photo: String,        // Filename of captured photo
  grade: String,
  section: String
}

schedules

{
  section: String,              // Unique (e.g., "12-ICT-A")
  adviser_id: String,           // Teacher _id (indexed)
  weekly_schedule: {
    monday:    { start: "07:00", end: "17:00" },
    tuesday:   { start: "07:00", end: "17:00" },
    wednesday: { start: "07:00", end: "17:00" },
    thursday:  { start: "07:00", end: "17:00" },
    friday:    { start: "07:00", end: "17:00" },
    saturday:  { start: null, end: null }
  },
  grace_period_minutes: Number,     // Default: 20
  absent_threshold_minutes: Number  // Default: 60
}

calendar

{
  type: String,         // "suspension" | "no-class" | "saturday-makeup"
  date: String,         // Single date (YYYY-MM-DD)
  startDate: String,    // Range start (for multi-day suspensions)
  endDate: String,      // Range end
  section: String,      // For section-specific no-class
  reason: String
}

settings

{
  key: String,          // Unique setting key
  value: Mixed          // Setting value
}

Calendar Priority Order

1. School-wide suspension (Admin)      ← Highest
2. Section no-class declaration (Teacher)
3. Weekend rules (Sat disabled, Sun always off)
4. Normal instructional day (Mon-Fri)  ← Lowest

Indexes

// Students
students.createIndex({ nfc_id: 1 }, { unique: true });
students.createIndex({ tamtap_id: 1 });

// Teachers
teachers.createIndex({ nfc_id: 1 }, { unique: true, sparse: true });
teachers.createIndex({ tamtap_id: 1 });
teachers.createIndex({ username: 1 }, { unique: true });

// Attendance
attendance.createIndex({ nfc_id: 1, date: 1 });
attendance.createIndex({ date: -1 });

// Calendar
calendar.createIndex({ type: 1, date: 1 });
calendar.createIndex({ type: 1, startDate: 1, endDate: 1 });
calendar.createIndex({ type: 1, section: 1, date: 1 });

// Settings
settings.createIndex({ key: 1 }, { unique: true });

// Schedules
schedules.createIndex({ section: 1 }, { unique: true });
schedules.createIndex({ adviser_id: 1 });

πŸ“‘ Socket.IO Events

Only these events are emitted (contract-enforced):

Attendance Events (hardware β†’ dashboard)

Event Direction Payload Description
attendance:new Server β†’ Client { nfc_id, name, role, date, time, session, photo, section } New attendance recorded
attendance:fail Server β†’ Client { nfc_id, name, reason, decline_code } Attendance failed
camera:snapshot Server β†’ Client { photo_url } Camera snapshot taken
system:status Server β†’ Client { status, mongodb, clients, hardware } System health update

Log Streaming Events (admin panel ↔ server)

Event Direction Payload Description
logs:subscribe Client β†’ Server { service } Client requests real-time log stream
logs:entry Server β†’ Client { timestamp, message, service } Server pushes a log entry
logs:error Server β†’ Client { error } Server reports log stream error
logs:unsubscribe Client β†’ Server { service } Client stops log stream

⚠️ No custom events may be added without updating the contract.


πŸ” State Machine

All hardware modules must follow this state flow:

          β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
          β”‚                                         β”‚
          β–Ό                                         β”‚
       β”Œβ”€β”€β”€β”€β”€β”€β”    Card read     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
       β”‚ IDLE β”‚ ────────────────▢│ CARD_DETECTED β”‚  β”‚
       β””β”€β”€β”€β”€β”€β”€β”˜                  β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                                         β”‚          β”‚
                                         β–Ό          β”‚
                                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
                                β”‚ CAMERA_ACTIVE  β”‚  β”‚
                                β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
                                        β”‚           β”‚
                              β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
                              β”‚                   β”‚ β”‚
                              β–Ό                   β–Ό β”‚
                        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”β”‚
                        β”‚ SUCCESS β”‚         β”‚ FAIL β”‚β”‚
                        β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜         β””β”€β”€β”¬β”€β”€β”€β”˜β”‚
                             β”‚                 β”‚    β”‚
                             β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β”€β”€β”€β”€β”˜

Rules:

  • No state skipping β€” every transition is sequential
  • No parallel state transitions
  • Every cycle must return to IDLE
  • SHUTDOWN state only on SIGINT/SIGTERM

Flow Chart


⏱ Timing Constraints

Each attendance cycle must complete within ≀ 3.5 seconds:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    TOTAL BUDGET: ≀ 3.5s                      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ NFC Read β”‚ Schedule β”‚ Camera Wake  β”‚ Face     β”‚ LCD + LED   β”‚
β”‚ ≀ 100ms  β”‚ Validate β”‚ + Capture    β”‚ Detect   β”‚ Update      β”‚
β”‚          β”‚ ~50ms    β”‚ ≀ 1500ms     β”‚ ≀ 1200ms β”‚ ≀ 100ms     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

All code must be non-blocking. No sleep() calls that violate this budget.


πŸ–₯ Frontend Pages

Page Path Description
Landing /index.html Public landing page with hero slideshow
Login /login.html Username/password login (session)
Dashboard /dashboard.html Real-time attendance feed + charts
Admin /admin.html Student/teacher management, schedules, calendar, logs
Privacy /privacy.html Privacy policy (Data Privacy Act compliance)
Terms /terms.html Terms of use
Researchers /researchers.html Research team profiles
404 /404.html Custom error page

Frontend Architecture

  • Multi-page HTML β€” no SPA frameworks
  • One JS file per page β€” extracted to public/js/ (no inline <script> blocks)
  • Shared utilities β€” utils.js (XSS escape), tailwind-config.js, fonts.css
  • Fetch API only β€” no Axios
  • WebSocket only for live updates β€” not for data fetching
  • Tailwind CSS via CDN with shared config (tailwind-config.js)
  • Role-based UI via JS logic: admin / adviser / teacher

βš™οΈ Systemd Services

Service File Description User
tamtap.service (created during setup) Hardware NFC/camera loop charles
tamtap-server.service buttons/tamtap-server.service Node.js backend charles
tamtap-buttons.service buttons/tamtap-buttons.service GPIO button controller root

Service Commands

# Check status
sudo systemctl status tamtap.service
sudo systemctl status tamtap-server.service
sudo systemctl status tamtap-buttons.service

# View logs
sudo journalctl -u tamtap -f
sudo journalctl -u tamtap-server -f
sudo journalctl -u tamtap-buttons -f

# Restart
sudo systemctl restart tamtap.service
sudo systemctl restart tamtap-server.service

🧰 Scripts & Utilities

Script Location Description
startup.sh Root Activates venv + starts tamtap.py (used by systemd)
update.sh Root Git pull + update deps + restart services
bootstrap-admin.js software/scripts/ Create initial admin account
register.py hardware/ CLI student registration via NFC
tamtap_admin.py hardware/ Admin CLI: archive, manage, export
archive_attendance.py hardware/ Archive/clear attendance records

CLI Registration (register.py)

source .venv/bin/activate
cd hardware
python register.py
# Menu: 1. Register Student (NFC) | 2. List | 3. Delete | 4. Exit

Update System (update.sh)

./update.sh
# Pulls from GitHub, updates pip deps if changed, restarts services
# Aborts if local uncommitted changes exist

⚠️ Error Handling & Logging

Python (Hardware)

  • All functions use try/except with specific exception types
  • Timeouts on NFC reads, camera subprocess, and face detection
  • No print() debugging β€” use logging module only
  • Levels: INFO (normal), WARNING (recoverable), ERROR (hardware/data failure)

Node.js (Backend)

  • All routes use try/catch
  • Structured logging via signale (Logger.js)
  • Custom log types: info, success, warn, error, debug, database, socket, api, hardware, server
  • Live log streaming to admin panel via Socket.IO

Logging Levels

Level Use Case Example
INFO Normal operations "Student tapped: John Doe"
WARN Recoverable issues "MongoDB reconnecting..."
ERROR Hardware or data failure "NFC reader init failed"

🀝 Contributing

Rules

  1. No cloud services β€” Firebase, AWS, Supabase, etc. are forbidden
  2. No frontend frameworks β€” React, Angular, Vue are not allowed
  3. No GUI apps on Pi β€” No Tkinter, PyQT
  4. No facial recognition β€” Face detection (Haar) only, no face matching
  5. No hardcoded credentials β€” Use .env for all secrets
  6. No blocking infinite loops β€” All code must be non-blocking
  7. No features outside research scope β€” Only implement what's in the capstone spec

Workflow

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/your-feature
  3. Commit changes: git commit -m "feat: description"
  4. Push: git push origin feature/your-feature
  5. Open a Pull Request

Commit Convention

feat:     New feature
fix:      Bug fix
docs:     Documentation only
style:    Formatting (no logic change)
refactor: Code restructuring
test:     Adding tests
chore:    Build/tooling changes

Pull Request Checklist

  • Code follows the Code Style Guide
  • No cloud dependencies introduced
  • Hardware timing constraints respected (≀ 3.5s cycle)
  • State machine flow preserved
  • Only approved Socket.IO events used
  • Error handling with try/except or try/catch
  • Tested on Raspberry Pi 4B

πŸ“ Code Style Guide

Python

  • Python 3.11+ syntax
  • logging module β€” never print()
  • Type hints encouraged but not required
  • snake_case for functions and variables
  • PascalCase for classes
  • UPPER_SNAKE_CASE for constants
  • Defensive programming: validate all inputs
  • Prefer clarity over cleverness
  • All code must be explainable to panelists

JavaScript (Node.js)

  • ES6+ syntax (const, let, arrow functions, async/await)
  • camelCase for functions and variables
  • PascalCase for classes
  • UPPER_SNAKE_CASE for constants
  • Always use try/catch in async routes
  • Return early on errors
  • Use structured logger, not console.log

JavaScript (Frontend)

  • Vanilla ES6+ β€” no frameworks, no transpilers
  • One JS file per HTML page
  • Fetch API for HTTP requests β€” no Axios
  • Socket.IO client for real-time only
  • Use const by default, let when mutation needed
  • Never use var

General

  • 4-space indentation (Python), 4-space or 2-space (JS β€” match existing)
  • Modular, testable functions
  • Meaningful variable/function names
  • Comments for non-obvious logic
  • TODO comments are mandatory edge cases β€” never ignore them

πŸ—£ Languages

Layer Language
Hardware control Python 3.11
Backend API JavaScript (Node.js 20)
Frontend UI HTML5, CSS3, JavaScript (ES6+)
Arduino firmware C++ (Arduino IDE)
Shell scripts Bash
Database MongoDB query language

πŸ‘¨β€πŸ’» Authors

  • Charles Giann Marcelo β€” Lead Developer
  • et al. β€” FEU Roosevelt Marikina, Grade 12 ICT

πŸ“„ License

This project is licensed under the MIT License β€” see the LICENSE file for details.

MIT License
Copyright (c) 2025 Charles Giann Marcelo

Built with πŸ’š at FEU Roosevelt Marikina

TamTap β€” Tap. Verify. Present.

About

TamTap - This is a product of our capstone called tamtap. And it's a attendance product that has a user friendly website dashboard.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages