# NFC Attendance Hub A multi-tenant admin web app that acts as middleware between on-premise NFC student attendance apps and the [Semaphore](https://semaphore.co) SMS API. ## Features - **Multi-tenant Client Management** — Register schools/orgs, each gets a unique API key - **Semaphore SMS Integration** — Per-client Semaphore API key + sender name, credit balance display - **DB-based SMS Queue** — Retry up to 3 attempts with exponential backoff, tracks failure reasons - **Failed SMS Dashboard** — View failed messages with error details, manual retry button - **Reports** — SMS stats per client, date filter, CSV export - **Admin Auth** — Email/password login with NextAuth ## Tech Stack - Next.js 14 (App Router) + TypeScript - Tailwind CSS + shadcn/ui-compatible components - Prisma ORM (v5) + PostgreSQL - NextAuth.js (credentials provider) ## Quick Start (Docker) ```bash cp .env.example .env # Edit .env with your values docker compose up -d ``` App available at: http://localhost:3000 Default admin: `admin@nfchub.local` / `admin123` ## Development ```bash npm install cp .env.example .env # Edit .env to point to a local PostgreSQL npx prisma generate npx prisma db push npm run db:seed npm run dev ``` ## SMS API Reference On-premise NFC apps submit attendance events to: ``` POST /api/v1/sms/send Header: X-API-Key: Content-Type: application/json { "student_name": "Juan Dela Cruz", "student_id": "2024-001", "parent_phone": "09171234567", "event": "time_in", // "time_in" or "time_out" "timestamp": "2024-01-15T08:30:00+08:00", "message": "Optional custom message" // optional } ``` ### Response ```json { "success": true, "queueId": "...", "message": "SMS queued for delivery" } ``` ### SMS Queue Behavior 1. Submission is accepted immediately (202 Accepted) 2. Processing is triggered asynchronously 3. Failed sends are retried up to 3 times with exponential backoff (2min, 4min, 8min) 4. After 3 failures, SMS is marked FAILED and visible in the Failed SMS dashboard ## Environment Variables | Variable | Description | Required | |----------|-------------|----------| | `DATABASE_URL` | PostgreSQL connection string | Yes | | `NEXTAUTH_URL` | Public app URL | Yes | | `NEXTAUTH_SECRET` | Random secret for JWT | Yes | | `INTERNAL_API_KEY` | Internal queue trigger key | Yes | ## Docker Services | Service | Port | Description | |---------|------|-------------| | `app` | 3000 | Next.js application | | `postgres` | 5433 (host) | PostgreSQL 16 |