Next.js 16 dashboard for monitoring terrariums with MongoDB, NextAuth and Mongoose.
- Next.js 16 (App Router) + React 19
- NextAuth v5 with
@auth/mongodb-adapter - MongoDB for both auth (driver) and business data (Mongoose)
- TailwindCSS + shadcn/ui + Recharts
- zod validations + uuid/date-fns utilities
- Node.js 18+
- MongoDB instance with two databases (or one shared)
MONGODB_URIfor NextAuth adapterMONGOOSE_URIfor Mongoose models
-
Copy the environment example:
cp .env.local.example .env.local
.env.local.exampleNEXTAUTH_URL=http://localhost:3000 NEXTAUTH_SECRET=changeme MONGODB_URI=mongodb://localhost:27017/terrarium_auth MONGOOSE_URI=mongodb://localhost:27017/terrarium_app WEBHOOK_USER_AGENT=terrarium-monitor/1.0 WEBHOOK_SIGNATURE_SECRET=change-me INGEST_RATE_PER_MINUTE=120
-
Install dependencies
pnpm install
-
Run the dev server
pnpm dev
| Method | Route | Description |
|---|---|---|
| POST | /api/auth/register |
Register credential user |
| GET/POST | /api/v1/terrariums |
List / create terrariums |
| GET/PUT/DELETE | /api/v1/terrariums/:id |
CRUD metadata + cascade delete |
| GET | /api/v1/terrariums/:id/aggregates |
Aggregated data (raw/hourly/daily) |
| GET/POST | /api/v1/terrariums/:id/webhooks |
List/create webhooks |
| PUT/DELETE | /api/v1/terrariums/:id/webhooks/:wid |
Update/delete webhooks |
| POST | /api/v1/record/:uuid |
Public ingestion endpoint |
| POST | /api/v1/health-check |
Trigger downtime health-checks |
All /api/v1/terrariums/* routes (except ingestion) require an authenticated session.
- Raw samples are stored in MongoDB with a TTL index of 31 days. This covers the 30-day “raw” range exposed in the dashboard while leaving 1 extra day of buffer.
- Aggregated collections (hourly, daily, hour-of-day) are retained indefinitely so historical views keep working even after raw samples expire.
curl -X POST http://localhost:3000/api/v1/record/your-terrarium-uuid \
-H "Content-Type: application/json" \
-H "X-Device-Token: your-device-token" \
-d '{
"device_id": "esp32-1",
"sent_at": 1730971200,
"samples": [
{ "t": 1730971200, "type": "TEMPERATURE", "unit": "C", "value": 23.8 },
{ "t": 1730971200, "type": "HUMIDITY", "unit": "%", "value": 76.2 }
]
}'Use the dashboard (Terrarium ➜ Webhooks ➜ “Tester”) or trigger manually:
curl -X POST http://localhost:3000/api/v1/record/your-uuid \
-H "Content-Type: application/json" \
-H "X-Device-Token: ..." \
-d '{ "samples": [{ "t": 1730971200, "type": "HUMIDITY", "unit": "%", "value": 90 }] }'Active webhooks with thresholds that match the ingested values will fire with:
{
"terrariumId": "...",
"metric": "HUMIDITY",
"comparator": "gt",
"threshold": 85,
"current": 90,
"at": "2024-11-07T21:05:00.000Z",
"samplesCountInBatch": 1
}Enable the “Healthcheck webhook” card in the dashboard to be notified when a terrarium stops sending samples. Schedule a cron job (for example with Vercel Cron) that hits POST /api/v1/health-check with the header Authorization: Bearer ${HEALTHCHECK_CRON_SECRET}.
The endpoint scans all enabled terrariums, sends a single webhook per downtime window, and keeps quiet until a new measurement is ingested (which automatically resets the health check status).
