Privacy-safe operational analytics dashboard for TapCare's NFC and QR support system.
- Next.js App Router
- TypeScript
- Tailwind CSS
- Prisma + PostgreSQL
- Upstash Redis for disposable rate limits and deduplication
- Vitest
- ESLint
- Admin household management dashboard
- Caregiver assigned-household view with sticker setup access
- Separate admin analytics area
- Explainable follow-up signals instead of opaque risk scores
ADMIN is a global TapCare administrator and can administer households, configure stickers, review follow-up signals, process access requests, and view analytics across all sites.
CAREGIVER may view and configure stickers only for households with an active assignment. Caregivers cannot perform household administration, manage follow-up signals, process access requests, or access admin analytics.
Sites are currently organizational metadata, not authorization boundaries. Site roles do not grant application permissions.
- Copy
.env.exampleto.env. - Start PostgreSQL with
docker compose up -d. - Install dependencies with
npm install. - Generate Prisma client with
npm run prisma:generate. - Apply migrations with
npm run prisma:migrate. - Seed demo data with
npm run db:seed. - Run the app with
npm run dev.
Database mode is the default and requires a non-empty DATABASE_URL. The seeded PostgreSQL setup above is the preferred development path because it exercises the production persistence layer.
PostgreSQL is TapCare's durable source of truth. Upstash Redis is disposable, short-lived coordination state only: authentication rate limits and duplicate-event suppression. It never stores users, caregiver assignments, household permissions, sticker configuration, sessions, interaction-event history, or follow-up state. A Redis flush therefore does not destroy meaningful application state.
On Vercel, create an Upstash Redis database and set UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN. Redis failures fail open: sign-in and public sticker functionality continue, with temporarily reduced abuse protection or duplicate analytics.
For read and authentication flows that explicitly need local mock data, set:
TAPCARE_DATA_MODE=mock npm run devMock mode is limited to local development and tests. It is rejected in production and on Vercel preview or production deployments. If DATABASE_URL is missing and mock mode is not explicitly enabled, TapCare reports a configuration error instead of falling back to mock users or data. Database-only setup and write operations remain unavailable in mock mode.
Run these before pushing changes:
npm test
npm run lint
npm run buildSee docs/staging-deployment.md for hosted staging setup, environment variables, Google OAuth callback configuration, database migration, and NFC sticker testing.
After creating a sticker, TapCare opens its physical setup panel. Copy the displayed canonical NFC URL (or scan its QR code), write that exact URL to the NFC tag, tap the tag to verify it, then confirm the test in TapCare. A tested tag must be reset with Replace / reprogram tag before its sticker can be deleted or moved to another household. The authenticated Preview sticker screen does not record analytics.
Hosted deployments must set PUBLIC_STICKER_BASE_URL to the permanent HTTPS public sticker base URL. TapCare refuses to generate physical-tag URLs in production without it.
Use the included seed script to populate a demo site, users, households, stickers, page configs, destination configs, and interaction events.
Commands:
npm run prisma:migrate
npm run db:seedWhat gets seeded:
SGO Bedoksite- caregiver and admin users
- three households with address-based identities
- household assignments for the caregiver
- six stickers across redirect and rendered-page modes
- page and destination configs
- interaction events to make the dashboard non-empty
Seeded login credentials:
Caregiver: maya.lim@example.org / TapCare1234!
Admin: dev.admin@tapcare.sg / TapCare1234!
Authentication notes:
- Login uses email/password with hashed passwords.
- Browser cookies store opaque session tokens, not user IDs.
- Session tokens are stored hashed in the database.
- Public signup creates caregiver accounts only.
- Google signup also creates caregiver accounts only and does not require a TapCare password.
- Newly signed-up caregivers see no household data until they are assigned households.
- Logged-in users can change passwords from
/account/password. - Google-created users can set a TapCare password from
/account/passwordif they want email/password sign-in too. - Forgotten-password reset links use one-time hashed database tokens that expire after 30 minutes.
- Local development shows the reset link after requesting a reset.
- Production reset emails use Resend when
RESEND_API_KEY,AUTH_EMAIL_FROM, andAPP_BASE_URLare configured. - Google signup/sign-in is available when
GOOGLE_CLIENT_ID,GOOGLE_CLIENT_SECRET, andAPP_BASE_URLare configured. - Google OAuth callback URL:
${APP_BASE_URL}/api/auth/google/callback.
Notes:
- the seed is rerunnable and uses fixed IDs
- setup APIs require a working
DATABASE_URL - database-backed reads and authentication also require
DATABASE_URLunless explicit local mock mode is enabled
- Prisma schema and migrations are included for the production data model.