The API and data hub of Happify β a Node.js/Express backend that authenticates users, stores every wellbeing signal, orchestrates AI journal and voice analysis, powers an anonymous community and heatmap, routes professional care, and streams it all to web, mobile, and companion-device clients in real time.
π Frontend Β· βοΈ Backend Β· π§ AI Β· π± Mobile Β· π IoT
Happify-Backend is the single source of truth of the Happify ecosystem. Every client β the web dashboard, the mobile app, and the companion IoT device β reads and writes through this API. It owns the PostgreSQL schema, verifies Firebase identities, enforces role-based access, delegates AI reasoning to Happify-AI, stores media in S3-compatible object storage, and fans out live updates over WebSockets.
Happify-Backend's role in the ecosystem: "The nervous system β every signal a user, a device, or an AI model produces passes through here to be verified, persisted, and routed to whoever needs to see it next."
The backend does not run AI models itself. Voice processing and journal analysis are delegated to Happify-AI through a single shared service base URL and bearer token β the backend's job is orchestration, safety policy, and persistence, not inference.
| Runtime | Node.js (ESM) + tsx |
| Framework | Express 5 + TypeScript |
| Database | PostgreSQL via Prisma 7 (@prisma/adapter-pg) |
| Auth | Firebase Admin SDK (ID-token verification) + RBAC |
| Validation | Zod schemas on every route |
| Realtime | Raw ws WebSocket server, channel-based pub/sub |
| Storage | S3-compatible object storage (@aws-sdk/client-s3) |
| AI Integration | HTTP calls to Happify-AI (journal + voice) |
| API Docs | OpenAPI JSON + Swagger UI at /docs |
Happify-Backend sits at the center of the platform β the frontend, mobile app, and IoT companion device all depend on it, and it in turn depends on Happify-AI for reasoning and Firebase/PostgreSQL/S3 for identity, data, and media.
| Repository | Role | Link |
|---|---|---|
| π Happify-FE | Web dashboard β mood, journal, community, care | Happiffy/Happify-FE |
| βοΈ Happify-BE | Node.js API, PostgreSQL, Firebase, WebSocket hub (this repo) | Happiffy/Happify-BE |
| π§ Happify-AI | FastAPI service β journal reflection, risk detection, voice processing | Happiffy/Happify-AI |
| π± Happify-Mobile | Flutter app for mood tracking, journaling, and care access on the go | Happiffy/Happify-Mobile |
| π Happify-IOT | ESP32-class voice-companion device paired to a user account | Happiffy/Happify-IOT |
System architecture:
graph TD
FE["π Happify-Frontend"] -->|REST + WebSocket| BE["βοΈ Happify-Backend (this repo)"]
MB["π± Happify-Mobile"] -->|REST + WebSocket| BE
IOT["π Happify-IOT device"] -->|Device-token REST + audio| BE
BE --> PG[("ποΈ PostgreSQL via Prisma")]
BE --> FB["π₯ Firebase Admin (auth)"]
BE --> S3[("π¦ S3-compatible storage")]
BE -->|"journal / voice analysis"| AI["π§ Happify-AI"]
AI -->|"risk level + reflection / audio"| BE
BE -->|WebSocket broadcast| FE
BE -->|WebSocket broadcast| MB
style BE fill:#1CB0F6,color:#fff,stroke:#168CC7
style AI fill:#CE82FF,color:#fff,stroke:#A760D2
style FE fill:#58CC02,color:#fff,stroke:#46A302
style MB fill:#58CC02,color:#fff,stroke:#46A302
style IOT fill:#FF9600,color:#fff,stroke:#D97A00
Principles this backend is built around:
- Privacy by design β Public community responses strip internal user IDs, emails, and profile data; heatmap results only ever return coarse, k-anonymous regions.
- Safety first β AI output is supportive, not diagnostic. High-risk signals become explicit
Referralrecords reviewed by a human, not automated actions. - Human support matters β Accepted referrals open a
CareChatSessionconnecting a user directly to a verified psychologist. - Least privilege β Every route is gated by Firebase-verified identity plus role (
USER/PSYCHOLOGIST/MODERATOR/ADMIN), and device endpoints use a separate, scoped device-credential system. - Secure operations β Service-account JSON, database URLs, AI tokens, S3 keys, and device pepper secrets are all environment-only and never committed.
- π Authentication & RBAC β Firebase ID-token verification on every request, with
USER,PSYCHOLOGIST,MODERATOR, andADMINroles enforced viarequireAuth/requireRolemiddleware. - π Mood Tracking β Timestamped mood check-ins (state, intensity, triggers, notes) feeding the analytics dashboard.
- π Daily Journaling β Journal entries enriched by Happify-AI with a detected mood, a
LOW/MEDIUM/HIGH/CRISISrisk level, and a short supportive reflection. - ποΈ Voice Companion β Uploads raw audio to Happify-AI, stores the transcript/response/mood/risk per turn, and streams the generated speech back for playback.
- π Analytics β Aggregated dashboard totals, mood-intensity trends, and journal risk-level summaries per user.
- π Consent Management β Versioned consent documents and per-user acceptance for AI processing, voice processing, device emotion observation, and heatmap contribution.
- π« Anonymous Community β Alias-based posts and comments, support reactions, reporting, and a moderator audit trail (hide/restore/resolve/dismiss).
- πΊοΈ Anonymous Heatmap β Daily mood contributions bucketed into coarse geo-regions, only surfaced once a region reaches the configured k-anonymity threshold (
max(3, HEATMAP_K_ANONYMITY), default 5). - π€ Professional Care β Psychologist verification applications, referral requests with a captured background snapshot, referral review, and 1:1 care-chat sessions.
- π§ Mindfulness & Motivation β Published breathing/meditation/grounding exercises with per-user progress, plus locale-aware daily motivation messages.
- π Companion Devices β Claim-secret pairing, scoped runtime credentials, telemetry ingestion, remote commands, and OTA firmware metadata for the IoT companion.
- π Media Upload β Validated image uploads proxied to S3-compatible object storage.
- π Push Notifications β FCM token registration and per-user notification preference toggles.
- β‘ Realtime Broadcasts β A single WebSocket hub fans out community, referral, care-chat, and device events to authorized subscribers only.
- π Self-Documenting API β Full OpenAPI spec served at
/openapi.json, with an interactive Swagger UI at/docs.
| Layer | Technology | Purpose |
|---|---|---|
| Runtime | Node.js (ESM) + tsx |
Fast TypeScript execution without a separate build step in dev |
| Framework | Express 5 | HTTP routing and middleware pipeline |
| Language | TypeScript ~6.0 | End-to-end type safety across modules |
| ORM | Prisma 7 + @prisma/adapter-pg |
Type-safe PostgreSQL access, migrations, and seeding |
| Database | PostgreSQL | Primary relational data store |
| Authentication | firebase-admin |
Verifies client Firebase ID tokens server-side |
| Validation | Zod | Request/response schema validation across every module |
| Security | Helmet, CORS (origin allow-list) | HTTP security headers and cross-origin control |
| Logging | Morgan | Request logging (dev locally, combined in production) |
| Realtime | ws |
Raw WebSocket server with an authenticated pub/sub channel model |
| Object Storage | @aws-sdk/client-s3 |
S3-compatible media upload/retrieval |
| Sanitization | sanitize-html |
Strips unsafe markup from rich-text journal/community content |
| API Docs | swagger-ui-express |
Interactive docs generated from src/config/openapi.ts |
| Testing | Node's built-in test runner via tsx --test |
Unit tests for utils, voice validation, analytics, device firmware logic |
Happify-BE/
βββ prisma/
β βββ schema.prisma # Full data model (30+ models, see Data Model below)
β βββ migrations/ # Timestamped SQL migrations
β βββ seed.ts # Idempotent reference + demo data seeding
β
βββ src/
β βββ server.ts # Express app entry point, route mounting, WS attach
β β
β βββ config/
β β βββ prisma.ts # Prisma client singleton
β β βββ firebase.ts # Firebase Admin initialization
β β βββ openapi.ts # OpenAPI document served at /openapi.json and /docs
β β
β βββ generated/prisma/ # Generated Prisma Client (do not edit)
β β
β βββ modules/ # One folder per domain, each with the same shape:
β β β # *.routes.ts β *.controller.ts β *.service.ts β *.repository.ts
β β β # plus *.validation.ts (Zod schemas)
β β βββ auth/ # Firebase verification, RBAC middleware
β β βββ profile/ # User profile read/update
β β βββ preference/ # Onboarding + accessibility + notification preferences
β β βββ mood/ # Mood check-ins
β β βββ journal/ # Journals + journal.client.ts (Happify-AI adapter)
β β βββ voice/ # Voice turns + voice.client.ts (Happify-AI adapter)
β β βββ analytics/ # Dashboard aggregation
β β βββ consent/ # Consent documents and user consent state
β β βββ community/ # Posts, comments, support, reports, moderation
β β βββ heatmap/ # K-anonymous mood aggregation
β β βββ referral/ # Referrals + care-chat sessions/messages
β β βββ provider/ # Professional provider directory
β β βββ emergency-contact/ # Emergency contact CRUD
β β βββ mindfulness/ # Mindfulness content + progress
β β βββ motivation/ # Daily motivation messages
β β βββ notification/ # FCM tokens + notification preferences
β β βββ media/ # S3 upload/retrieval
β β βββ device/ # Pairing, telemetry, commands, OTA, runtime auth
β β βββ realtime/realtime.ts # WebSocket server, channels, broadcast()
β β
β βββ utils/ # ai.util.ts, html.util.ts (sanitization), request.util.ts
β
βββ VOICE_IOT_CONTRACT.md # Firmware-facing contract for the IoT voice companion
βββ prisma.config.ts
βββ tsconfig.json
βββ .env.example
βββ package.json
Every module follows the same layered convention: routes (Express Router, wires middleware) β controller (parses req, calls service, shapes res) β service (business logic, calls the AI client where relevant) β repository (Prisma queries), with validation as shared Zod schemas.
Authentication on every request:
sequenceDiagram
participant C as Client (FE / Mobile)
participant BE as Happify-BE
participant FB as Firebase Admin
participant DB as PostgreSQL
C->>BE: Request with "Authorization: Bearer <Firebase ID token>"
BE->>FB: verifyIdToken(token)
FB-->>BE: decoded { uid }
BE->>DB: findUnique MsUser by firebaseUid
DB-->>BE: { id, role }
alt user found & role valid
BE-->>C: 200 β proceeds to controller
else missing / invalid
BE-->>C: 401 UNAUTHENTICATED
end
Journal creation with AI-assisted risk detection:
sequenceDiagram
participant U as User (via Frontend)
participant BE as Happify-BE
participant AI as Happify-AI
participant DB as PostgreSQL
U->>BE: POST /journal { title, content }
BE->>AI: POST /api/analyze-journal { content, language }
AI-->>BE: { reflection, emotion.state, risk_policy.severity }
Note over BE: On AI timeout/failure, journal is still saved (riskLevel defaults to LOW)
BE->>DB: Insert TrJournalEntry (detectedMood, riskLevel, aiReflection)
DB-->>BE: Saved journal
BE-->>U: 201 { journal }
Realtime channel model (src/modules/realtime/realtime.ts):
flowchart LR
S[WebSocket connects] -->|"{ type: 'auth', token }"| V[verify Firebase token]
V --> J["{ type: 'subscribe', channel }"]
J --> A{authorizeChannel}
A -->|"community"| OK1[Anyone authenticated]
A -->|"care"| OK2["PSYCHOLOGIST / ADMIN only"]
A -->|"user:<id>:care"| OK3[Only that user]
A -->|"care-chat:<sessionId>"| OK4[Only session participants]
OK1 & OK2 & OK3 & OK4 --> B[broadcast on domain events]
Community posts/comments, referral status changes, care-chat messages/typing/read-receipts, and device command acknowledgements are all pushed through broadcast(channel, payload) to every authorized socket in that channel β no polling required on the client side.
The schema (prisma/schema.prisma) uses a Ms/Tr naming convention β Ms (master) tables for reference/identity data, Tr (transaction) tables for user-generated activity β spanning 30+ models. Core relationships:
erDiagram
MsUser ||--o{ TrMoodEntry : logs
MsUser ||--o{ TrJournalEntry : writes
MsUser ||--o{ TrCommunityPost : posts
MsUser ||--o{ TrReferral : requests
MsUser ||--o| MsUserPreference : has
MsUser ||--o| TrPsychologistApplication : "applies as"
MsUser ||--o{ MsDevice : owns
TrReferral ||--o| TrCareChatSession : opens
TrCareChatSession ||--o{ TrCareChatMessage : contains
TrCommunityPost ||--o{ TrCommunityComment : has
TrCommunityPost ||--o{ TrCommunitySupport : receives
TrCommunityPost ||--o{ TrCommunityReport : "can be"
MsDevice ||--o{ TrDeviceTelemetry : reports
MsDevice ||--o{ TrDeviceCommand : receives
MsDevice ||--o{ TrDeviceEmotionObservation : produces
MsDevice ||--o{ TrDevicePairingSession : "paired via"
MsDevice ||--o{ TrDeviceOtaDeployment : updates
MsUser ||--o{ TrUserConsent : grants
MsConsentDocument ||--o{ TrUserConsent : versions
Key enums: MoodState (HAPPY / CALM / NEUTRAL / ANXIOUS / SAD / DISTRESSED), RiskLevel (LOW / MEDIUM / HIGH / CRISIS), ReferralStatus, ChatSessionStatus, DeviceStatus, DeviceCommandType, ConsentScope.
All routes are mounted in src/server.ts. Full interactive documentation is available at /docs (Swagger UI) and /openapi.json once the server is running.
| Prefix | Description |
|---|---|
GET /health |
Backend health check |
POST /auth/verify |
Exchange a Firebase ID token for a Happify user session |
/profile |
User profile read/update |
/preferences |
Onboarding, accessibility, and notification preferences |
/mood |
Mood check-ins |
/journal |
Journals with AI-assisted reflection and risk level |
/voice |
Voice-turn upload, transcript, response audio, session history |
/analytics |
Dashboard aggregation and mood-pattern summaries |
/motivation |
Locale-aware daily motivation |
/mindfulness |
Mindfulness content and per-user progress |
/community |
Anonymous posts, comments, support, reports, moderation |
/heatmap |
Anonymous, k-anonymous mood heatmap |
/consents |
Consent documents and consent status |
/referral |
Referrals, psychologist review, and care-chat sessions/messages |
/providers |
Professional provider directory |
/emergency-contacts |
Emergency contact management |
/notifications |
FCM token registration and notification preferences |
/media |
Image upload to S3-compatible storage |
/devices |
Pairing, credentials, telemetry, commands, firmware/OTA (/devices/runtime/* uses device-token auth, not Firebase) |
WS /ws |
Realtime channel subscription (community, care, user:<id>:care, care-chat:<sessionId>) |
The
/voicerouter is mounted before the globalexpress.json()body parser (seeserver.ts) so it can accept raw binary audio uploads; everything else uses JSON.
Create .env from .env.example:
PORT=4000
DATABASE_URL=postgresql://postgres:postgres@localhost:5432/happify?schema=public
CORS_ORIGIN=http://localhost:5173
PUBLIC_API_URL=http://localhost:4000
FIREBASE_PROJECT_ID=happify-990c2
FIREBASE_SERVICE_ACCOUNT_JSON=
AI_SERVICE_BASE_URL=http://localhost:8000
AI_SERVICE_TOKEN=
VOICE_UPSTREAM_TIMEOUT_MS=45000
AI_JOURNAL_TIMEOUT_MS=15000
VOICE_MAX_AUDIO_BYTES=6291456
VOICE_AUDIO_TTL_SECONDS=900
S3_ENDPOINT_URL=
S3_REGION=auto
S3_BUCKET_NAME=
S3_ACCESS_KEY_ID=
S3_SECRET_ACCESS_KEY=
DEVICE_CLAIM_PEPPER=
PAIRING_SESSION_TTL_SECONDS=300
DEVICE_CREDENTIAL_TTL_SECONDS=2592000
DEVICE_OBSERVATION_RETENTION_DAYS=30
HEATMAP_K_ANONYMITY=5| Variable | Description |
|---|---|
DATABASE_URL |
PostgreSQL connection string used by Prisma |
CORS_ORIGIN |
Allowed frontend origin(s), comma-separated |
PUBLIC_API_URL |
Public backend URL used in backend-generated links/assets |
FIREBASE_PROJECT_ID / FIREBASE_SERVICE_ACCOUNT_JSON |
Firebase Admin project + service-account credentials |
AI_SERVICE_BASE_URL / AI_SERVICE_TOKEN |
Single Happify-AI base URL and bearer token for voice + journal processing |
VOICE_UPSTREAM_TIMEOUT_MS / AI_JOURNAL_TIMEOUT_MS |
Timeouts for the two AI integrations |
VOICE_MAX_AUDIO_BYTES / VOICE_AUDIO_TTL_SECONDS |
Voice upload size cap and generated-audio retention |
S3_* |
Object-storage endpoint, region, bucket, and credentials for media |
DEVICE_CLAIM_PEPPER |
Secret used to hash companion-device claim secrets |
PAIRING_SESSION_TTL_SECONDS / DEVICE_CREDENTIAL_TTL_SECONDS |
Device pairing-session and runtime-credential lifetimes |
DEVICE_OBSERVATION_RETENTION_DAYS |
Retention window for device emotion observations |
HEATMAP_K_ANONYMITY |
Minimum unique contributors before a heatmap region is returned (floored at 3) |
β οΈ Never commit.env, Firebase service-account JSON, AI service tokens, S3 keys, or the device claim pepper.
- Node.js 20+ and npm
- A PostgreSQL database
- Firebase Admin service-account credentials
- S3-compatible storage credentials (for media uploads)
- A running Happify-AI instance (for voice + journal analysis)
git clone https://github.com/Happiffy/Happify-BE.git
cd Happify-BE
npm install
cp .env.example .env # then fill in database, Firebase, AI, and S3 credentialsnpm run prisma:generate
npm run prisma:deploy
npm run seedThe seed script is idempotent β safe to re-run β and provisions reference data plus representative demo data. Firebase seed-account passwords are generated only when needed and printed once to the terminal.
npm run devThe server starts at http://localhost:4000. Explore the API interactively at http://localhost:4000/docs.
npm run build # tsc --noEmit (type-check only)
npm start # runs prisma migrate deploy, then starts the servernpx prisma format
npx prisma validate
npm test # Node test runner across utils, voice, analytics, device modules
npm run buildBuilt for
AI-Powered Mental Wellness Platform
Happify-Backend is the API and data hub of Happify, a privacy-aware digital wellbeing ecosystem built around early detection, meaningful support, and lifelong emotional growth:
| Layer | Component | Role |
|---|---|---|
| π Web | Happify-FE | Mood tracking, journaling, anonymous community, care workflows |
| βοΈ Backend | Happify-BE (this repo) | API, PostgreSQL, Firebase, WebSocket hub, safety & moderation |
| π§ AI | Happify-AI | Journal reflection, risk detection, voice processing |
| π± Mobile | Happify-Mobile | Flutter app for on-the-go mood tracking and care access |
| π IoT | Happify-IOT | Voice-companion device paired to a user account |
Outstanding BINUSIAN Team β Garuda Hacks 7.0
| Name | Role |
|---|---|
| Andrian Pratama | Full-stack Developer |
| Khalisa Amanda Sifa Ghaizani | IoT Engineer |
| Michella Arlene Wijaya Radika | Product Developer |
| Stanley Nathanael Wijaya | Product Developer |
This project is licensed under the MIT License β free to use, modify, and distribute.
MIT License
Copyright (c) 2026 Happify β Garuda Hacks 7.0
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software.
"Detect early. Support meaningfully. Grow for life."
Made with π± for Garuda Hacks 7.0