Skip to content

Repository files navigation

Terra Sentinel

Intelligent landslide monitoring & early-warning dashboard. React + TypeScript + Vite, styled with Tailwind CSS v4, animated with Framer Motion, and wired to Firebase Realtime Database for live field-sensor data.

The app runs out of the box in simulation mode — a clearly labeled banner and generated data — until you supply real Firebase credentials. No code changes are required to go live; only environment variables.


1. Quick start

npm install
cp .env.example .env   # fill in your Firebase web config
npm run dev

Open the printed local URL. With no .env values set, the dashboard runs entirely on simulated data so you can preview every section immediately.

2. Connecting your Firebase project

  1. Create a Realtime Database in your Firebase project (production mode).
  2. Copy the six values from Project settings → General → Your apps → Web app into .env.
  3. Restart npm run dev. Once all required variables are present, Terra Sentinel switches out of simulation mode automatically — the simulated banner disappears and every listener connects to your real project.

Expected database schema

All paths are declared in one place — src/lib/firebase/paths.ts — so you can repoint the dashboard at a different schema without touching any component:

stations/primary/live      → { moisture, temperature, humidity, tilt, rainfall, battery, signal, timestamp }
stations/primary/history   → { <pushId>: { ...same shape as live } }
stations/primary/alerts    → { <pushId>: { timestamp, severity, reason, values, dismissed? } }
stations/primary/health    → { firebaseLatencyMs, lastSyncTimestamp, sensorUptimePct, espOnline, batteryPct, apiStatus }
stations/primary/info      → { name, latitude, longitude, elevationMeters }

If your ESP32 firmware writes to different paths, edit dbPaths in src/lib/firebase/paths.ts only.

Recommended security rules (read-only dashboard)

The dashboard never writes to the database — it only calls onValue. Lock writes down at the database level so no client, including this one, can write without explicit future authentication:

{
  "rules": {
    "stations": {
      ".read": "auth != null",
      ".write": false
    }
  }
}

Swap auth != null for true only for early local testing on a non-production project — never in a deployed app. When you add Firebase Authentication later, gate .read per user/role instead.

3. Project structure

src/
  components/
    layout/     Navbar, Footer, loading screen, empty/error states
    hero/       Landing hero with parallax
    status/     Live status bar
    sensors/    Sensor cards + sparkline
    chart/      Multi-dataset realtime graph
    history/    Searchable, sortable, exportable history table
    map/        Station location + map placeholder
    alerts/     Animated alert timeline
    risk/       Signature contour-ring risk gauge
    health/     System diagnostics grid
    ui/         Shared primitives (Section, RevealOnScroll, Counter)
  hooks/        useTerraData (data layer), useDarkMode
  lib/
    firebase/   config.ts (init), paths.ts (schema), listeners.ts (subscribe/unsubscribe helpers)
    mockData.ts Simulation data generator
    utils.ts    Formatting, CSV export, class merging
  types/        Shared TypeScript types + risk-scoring logic

4. Design system

Token Value
Primary #1E8E3E
Accent #4CAF50
Danger #D32F2F
Warning #F9A825
Background #F7F9FA
Type Inter (SF Pro Display fallback)

The signature visual element is the risk gauge: concentric contour-line arcs, styled after a topographic survey map, that fill outward as the composite risk score rises — a direct visual echo of the terrain the system is watching, rather than a generic circular progress ring.

Dark mode is class-based (:root.dark), remembers the user's choice in localStorage, and follows the OS preference when set to "system." All animation respects prefers-reduced-motion.

5. Data reliability

  • Every Firebase listener is registered through subscribePath in src/lib/firebase/listeners.ts, which always returns an unsubscribe function; every consuming hook cleans up on unmount.
  • Connection state is derived from Firebase's own .info/connected path, not guessed from listener activity.
  • On disconnect, the hook backs off 4 seconds before re-attaching listeners rather than looping immediately, so it never spams the database.
  • The dashboard is strictly read-only: src/lib/firebase exposes no write helpers at all.

6. Building and deploying

npm run build      # type-checks with tsc -b, then builds with Vite
npm run preview    # serve the production build locally

dist/ is a static bundle — deploy it to Firebase Hosting, Vercel, Netlify, or any static host.

Firebase Hosting:

npm install -g firebase-tools
firebase login
firebase init hosting   # point the public directory at "dist"
npm run build
firebase deploy

Remember to add your production domain to the Firebase project's Authorized domains list once Authentication is enabled.

7. A note on rendering strategy

This app is a client-rendered Vite SPA rather than server-rendered. Terra Sentinel's entire reason for existing is a live onValue subscription to Realtime Database — that connection only exists in the browser, so a server-rendered shell would still ship a client bundle to open it and would add build complexity (a Node runtime, hydration, streaming) without reducing time-to-first-live-reading. If you later add public marketing pages that benefit from SSR/SEO independent of the live dashboard, the cleanest path is a separate Next.js (or similar) marketing site that links into this dashboard, rather than converting the realtime app itself.

8. Linting & formatting

npm run lint     # eslint . (TypeScript + React Hooks rules)
npm run format   # prettier --write .

About

a light website to monitor real time landslide condetions using the terra sential project

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages