A practical utility built to make time tracking faster and simpler. Replaces slow paper logs with a quick QR scan interface, instant automated DTR reports, and printable QR passes for the department's interns.
- Overview
- Key Features
- Tech Stack
- System Architecture
- Database Schema
- Screenshots & User Flow
- Getting Started
- Environment Variables
- Project Structure
- API Reference
- Deployment
- Suggested Repository Name
- Author
OJT Track is a production-ready web application designed to digitize and streamline the On-the-Job Training (OJT) attendance process for university departments. Built for the ISUFST Dingle Campus β CICT Department, the system replaces manual paper-based Daily Time Records (DTR) with a fast, accurate, and tamper-resistant QR code scanning workflow.
The platform provides two distinct role-based portals:
| Role | Access | Capabilities |
|---|---|---|
| π Administrator | /admin |
Dashboard analytics, QR scanning, intern management, DTR report generation, ID printing, leave request review |
| π€ Intern | /intern |
Personal QR code display, OJT progress tracking, attendance logbook, leave request submission |
| Feature | Description |
|---|---|
| π Real-Time Dashboard | Live analytics showing morning & afternoon check-in/out counts, pending leave requests, and total intern stats β all in one view |
| π· QR Code Scanner | Camera-based HTML5 QR scanner with support for Morning/Afternoon sessions, overtime override, and manual time entry for late arrivals |
| π΄ Offline Mode | Scans are queued locally when internet is unavailable and automatically synced to Supabase when connectivity is restored |
| π Intern Management | Add, search, edit required hours, delete interns, and manage individual attendance logs with a paginated table |
| π Attendance Logbook | Full system-wide attendance log with Daily / Monthly / All-Time filtering, AM/PM session columns, and stale check-in detection |
| π Monthly DTR Reports | Generate pixel-perfect PDF Daily Time Records per intern with ISUFST official letterhead, signature blocks, Late/Undertime flags, and bulk ZIP export for all interns |
| π€ CSV Export | Export filtered attendance data as spreadsheet-ready .csv files per month |
| πͺͺ Printable ID Generator | Auto-generate standard CR80 ID cards with embedded QR codes for all registered interns, optimized for print layout |
| β Leave Request Review | Approve or reject intern leave requests with optional admin notes from the dashboard |
| Feature | Description |
|---|---|
| π² Personal QR Pass | Holographic-styled card with unique UUID-encoded QR code for scanning at the admin terminal |
| π OJT Progress Tracker | Animated SVG donut chart showing rendered hours vs. required hours (default: 600h) with percentage completion |
| π Attendance Logbook | Filterable personal attendance log with AM/PM session columns, paginated and grouped by date |
| π Leave Request System | Submit excused absence requests with date and reason; track status (Pending / Approved / Rejected) with admin notes |
| βοΈ Profile Self-Management | Update full name, username, and password directly from the dashboard |
| π Monthly Summary | Quick glance at current month's hours rendered and days present |
| Layer | Technology | Version |
|---|---|---|
| Framework | Next.js (App Router) | 16.1.6 |
| UI Library | React | 19.2.3 |
| Database & BaaS | Supabase (PostgreSQL) | 2.99.1 |
| Animations | Framer Motion | 12.35.2 |
| QR Scanning | html5-qrcode | 2.3.8 |
| QR Generation | react-qr-code | 2.0.18 |
| PDF Generation | jsPDF | 4.2.0 |
| Canvas Rendering | html2canvas | 1.4.1 |
| File Downloads | file-saver | 2.0.5 |
| ZIP Packaging | JSZip | 3.10.1 |
| Alert Dialogs | SweetAlert2 | 11.26.22 |
| Styling | Vanilla CSS (Custom Properties / CSS Variables) | β |
| Linting | ESLint + eslint-config-next | 9.x |
ojt-attendance/
βββ src/
β βββ app/
β β βββ admin/
β β β βββ dashboard/ # Live analytics & system logbook
β β β βββ scanner/ # QR camera scanner (offline-capable)
β β β βββ interns/ # Intern CRUD management
β β β βββ reports/ # DTR PDF & CSV export engine
β β β βββ ids/ # Printable QR ID card generator
β β β βββ login/ # Admin authentication
β β βββ intern/
β β β βββ dashboard/ # Personal QR pass, progress, logbook
β β β βββ login/ # Intern authentication
β β β βββ register/ # Intern self-registration
β β βββ api/
β β β βββ scan/ # Server-side scan processing endpoint
β β βββ globals.css # Design system (CSS custom properties)
β β βββ layout.js # Root layout
β βββ components/
β β βββ CustomDatePicker.js # Calendar date picker component
β β βββ CustomMonthPicker.js # Month selector component
β β βββ ManageAttendanceModal.js # Per-intern attendance CRUD modal
β βββ lib/
β β βββ supabase-browser.js # Supabase client singleton
β βββ utils/
β βββ time.js # Manila timezone helpers & hour calculations
β βββ swal-configs.js # SweetAlert2 themed alert presets
β βββ debounce.js # QR scan debouncer & UUID validator
β βββ logo-isufst.js # ISUFST logo (Base64) for PDF headers
β βββ logo-bagong.js # Bagong Pilipinas logo (Base64) for DTR
βββ database/
β βββ supabase_schema.sql # Full database schema (safe to re-run)
βββ public/
β βββ success.mp3 # Audio feedback on successful scan
β βββ error.mp3 # Audio feedback on scan error
βββ next.config.mjs
The system uses 3 core tables in Supabase (PostgreSQL):
-- Registered OJT interns
interns (
id BIGINT PRIMARY KEY,
uuid UUID UNIQUE, -- encoded in QR code
full_name TEXT,
username TEXT UNIQUE,
password TEXT,
required_hours NUMERIC DEFAULT 600,
created_at, updated_at
)
-- Time-in / time-out records
attendance (
id BIGINT PRIMARY KEY,
intern_id BIGINT β interns(id),
time_in TIMESTAMPTZ,
time_out TIMESTAMPTZ, -- NULL while still checked in
created_at
)
-- Excused absence requests
leave_requests (
id UUID PRIMARY KEY,
intern_id BIGINT β interns(id),
date_of_leave DATE,
reason TEXT,
status TEXT CHECK (pending | approved | rejected),
admin_notes TEXT,
created_at, updated_at
)All tables include Row Level Security (RLS) policies and relevant indexes for performance. Auto-update triggers maintain
updated_atfields automatically.
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β ADMIN FLOW β
β Login β Dashboard (stats + logbook) β Scanner (QR cam) β
β β Interns (CRUD) β Reports (DTR PDF/CSV) β
β β Printable IDs β Leave Request Review β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β INTERN FLOW β
β Register β Login β Dashboard (QR pass + progress chart) β
β β Attendance Logbook β Leave Request Submission β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β SCAN FLOW (QR Terminal) β
β Select Session (AM/PM) + Mode (In/Out) β
β β Start Camera β Intern presents QR β UUID validated β
β β POST /api/scan β Supabase upsert β Audio + Alert β
β [Offline] β Queue to localStorage β Sync on reconnect β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- Node.js β₯ 18.x
- npm β₯ 9.x (or
yarn/pnpm) - A Supabase project (free tier works)
git clone https://github.com/your-username/ojt-track.git
cd ojt-tracknpm installCreate a .env.local file in the project root:
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key-hereCopy the contents of database/supabase_schema.sql and run it in your Supabase SQL Editor. It is idempotent and safe to re-run.
npm run devOpen http://localhost:3000 in your browser.
Default Admin Access: Navigate to
/admin/loginand use the credentials configured in your database or Supabase dashboard.
| Variable | Required | Description |
|---|---|---|
NEXT_PUBLIC_SUPABASE_URL |
β Yes | Your Supabase project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
β Yes | Supabase anonymous/public API key |
β οΈ Never commit your.env.localfile. It is already included in.gitignore.
src/
βββ app/ # Next.js App Router pages
β βββ admin/ # Protected admin-only routes
β βββ intern/ # Intern self-service routes
β βββ api/scan/ # REST API for QR scan processing
βββ components/ # Reusable UI components
βββ lib/ # Third-party client configurations
βββ utils/ # Pure helper functions & shared configs
Processes a QR code scan event (check-in or check-out).
Request Body:
{
"uuid": "string", // Intern's unique UUID from QR code
"mode": "time-in | time-out",
"sessionType": "morning | afternoon",
"overtime": false, // Override time restrictions
"explicitTime": "ISO string | null" // Manual time entry
}Response (per result):
{
"results": [
{
"status": "ok | duplicate | already_checked_out | not_checked_in | missing | invalid_time",
"name": "Intern Full Name",
"session": "morning | afternoon"
}
]
}Status Codes:
| Status | Meaning |
|---|---|
ok |
Scan successfully recorded |
duplicate |
Intern already scanned for this session today |
already_checked_out |
Time-out already recorded |
not_checked_in |
Time-out attempted without a prior time-in |
missing |
UUID not found in database |
invalid_time |
Scan attempted outside allowed session window |
This project is optimized for deployment on Vercel (recommended for Next.js).
# Install Vercel CLI
npm i -g vercel
# Deploy
vercel --prodAdd your environment variables in the Vercel Dashboard β Project Settings β Environment Variables.
npm run build
npm startEnsure your hosting environment supports Node.js β₯ 18.x and has the required environment variables set.
This project was developed as a helpful utility for ISUFST Dingle Campus. Contributions, issue reports, and suggestions are welcome to make it even more useful for the department.
- Fork the repository
- Create your feature branch:
git checkout -b feature/your-feature - Commit your changes:
git commit -m 'feat: add your feature' - Push to the branch:
git push origin feature/your-feature - Open a Pull Request
This project is licensed under the MIT License β see the LICENSE file for details.
Lou Vincent Baroro
BS Information Technology Β· ISUFST Dingle Campus
Developed as a practical workflow tool to help the College of Information and Communications Technology (CICT) department streamline trainee attendance, hours tracking, and printable QR pass generation.
Built with β€οΈ using Next.js, React, and Supabase