- TypeScript 57.8%
- JavaScript 23.3%
- CSS 11.8%
- HTML 6.1%
- Shell 1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| pages | ||
| public | ||
| src | ||
| .copilot-ignore | ||
| .env.example | ||
| .gitignore | ||
| attendance.service.example | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| update.sh | ||
Attendance Tracker
Barcode attendance for a robotics team. The main features are the following:
- Kiosk: a public page where members scan their 7-digit student ID to check in or out during meetings. No sign-in, no OIDC client.
- Management and reports: sign-in through your OIDC provider. Admins manage members and meeting times, while viewers can see the reports area.
For more in depth features, see the Features section below.
Requirements
Node.js 24 or newer (for built-in node:sqlite and TypeScript type stripping).
Development Deployment
npm install
cp .env.example .env
Fill in .env (see the Configuration section below), then:
npm start
The web page is hosted at http://localhost:3000.
Production Deployment
Production deployments should use the attendance.service.example file to create a systemd service with auto-start and other automatic features. This service file assumes that you have used nvm to install node v24.8.0. (This is my preferred method of working with node).
Copy the service file to your systemd service directory, and edit the naming to fit your system.
You can also use the update.sh file to automatically pull an update from git and restart the service. Make sure to edit the $SERVICE_NAME variable to match the name of your systemd service.
This service requires a reverse proxy in front of it to provide SSL termination. Without this you will not be able to have secure authentication. Point the proxy at http://[LOCAL IP]:3000.
Configuration
| Setting | Meaning |
|---|---|
PORT |
Port to listen on (default 3000) |
BASE_URL |
Public URL of the site. The sign-in redirect URI is BASE_URL/auth/callback; cookies become Secure when this is https |
DATABASE_PATH |
SQLite file (default data/attendance.db, created on first start) |
OIDC_ISSUER |
Your provider's issuer URL |
OIDC_CLIENT_ID |
The client id |
OIDC_CLIENT_SECRET |
That client's secret |
ROLE_MAP |
group:role pairs mapping the groups claim to roles (default admin:admin,viewer:viewer) |
MEMBERS_API_KEY |
Enables POST /api/v1/members; at least 32 characters (alphanumeric) |
Setting up sign-in
Register one confidential client for the site:
- Redirect URI:
https://attendance.example.org/auth/callback - Post-logout redirect URI:
https://attendance.example.org/ - It must put a
groupsclaim in the ID token or the userinfo response.
The app also sends PKCE (S256), which providers accept for confidential
clients too.
Roles
| Role | Abilities |
|---|---|
admin |
Everything below, plus add/edit/delete members and set meeting times |
viewer |
Reports: calendar, day detail, leaderboard, CSV downloads |
ROLE_MAP="oidc-admin:admin,oidc-viewer:viewer" means members of a group named oidc-admin
get the admin role and members of oidc-viewer get viewer. To allow the use of certain OIDC
provider group formatting, enclose the entire role map in quotation marks.
Features
Kiosk
- Allows users to type in their 7-digit numeric ID. This is intended for use with a USB or Bluetooth barcode scanner which imports text by typing it extremely quickly. The site will not auto enter, as most barcode scanners support automatically appending a CRLF line end to the scan.
- Shows currently logged in members, as well as if a meeting is currently running, or when the next meeting would be.
Reports
- Calendar: Shows the number of unique attendees for each date. Click on the date to pull up a detail list.
- Time in meetings: A ranking of how much time members have spent in meetings.
- ASB report (CSV): Currently uses a format specific to ChainLynx 8248. You will have to fork and edit it. It's a little odd.
- Internal report (CSV): Arbitrary internal report format. Fork to change.
All times are Pacific Time.
Management
- Allows setting up to 3 meeting times per day of the week. Schedules are recurring.
- Allows adding or manually editing members. See the Members API section for the automatic method.
Members API
Supports adding members to the database through a POST API. This was created to work with a Google AppScript workflow to add members as soon as they fill out the team's roster form.
curl -X POST https://attendance.example.org/api/v1/members \
-H "Authorization: Bearer $MEMBERS_API_KEY" \
-H "Content-Type: application/json" \
-d '[{"studentId": "8116598", "firstName": "Ada", "lastName": "Lovelace", "isOfficer": false}]'
Send one member object or an array of up to 1000. Each entry is handled on its
own: the response lists the IDs created and any skipped with the reason
(already registered, invalid ID, missing name). isOfficer is optional.
Data Structure
| Table | Holds |
|---|---|
members |
student_id (7 digits, unique), first_name, last_name, is_officer |
meeting_times |
Up to 3 per weekday: name, start and end as Pacific HH:MM |
attendance |
One row per visit: student_id, meeting name, check-in and check-out time, whether the check-out was automatic |
login_sessions |
Signed-in staff sessions |
Changing a member's student ID carries their records with it; deleting a member deletes their attendance. The database can be viewed manually using the sqlite3 database tools package.