Skip to content

qppd/snake-sightings

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

10 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Sagip Ahas β€” Snake Sightings 🐍

A geospatial safety platform for reporting and tracking snake encounters in the Philippines. Citizens can report sightings safely (heatmap only, no exact coordinates exposed), responders handle incidents with exact GPS access, and admins manage verification and analytics.

🌟 Features

Feature Citizens Responders Admins
View heatmap (no exact pins) βœ… βœ… βœ…
Report sightings (click-to-place map) βœ… ❌ ❌
Respond to incidents (exact GPS pins + 100m search zones) ❌ βœ… βœ…
Manage users & roles ❌ ❌ βœ…
Verify responder applications ❌ ❌ βœ…
System audit logs ❌ ❌ βœ…
Analytics dashboard ❌ ❌ βœ…

πŸ—οΈ Tech Stack

Frontend

  • Next.js 16.2.6 (App Router, Turbopack)
  • React 19.2.4
  • TailwindCSS v4 (@import "tailwindcss" + @theme directives)
  • Framer Motion 12.38 (animations, page transitions)
  • Leaflet / OpenStreetMap (all map views, zero API keys)
  • @tanstack/react-query (data caching)

Backend

  • Supabase (Auth, PostgreSQL, RLS, Realtime, Storage)
  • Row Level Security (20+ policies, privacy-first)
  • Auth: Email/password + OAuth (Google, GitHub)

πŸ“ Project Structure

src/
β”œβ”€β”€ proxy.ts                           # Next.js proxy middleware (auth + role guard)
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ layout.tsx                     # Root layout (providers, fonts)
β”‚   β”œβ”€β”€ page.tsx                       # Citizen landing: hero, heatmap, safety cards
β”‚   β”œβ”€β”€ globals.css                    # Tailwind v4 design system (@theme, @utility)
β”‚   β”œβ”€β”€ providers.tsx                  # Framer Motion LazyMotion
β”‚   β”œβ”€β”€ login/page.tsx                 # Login + signup (Google/GitHub OAuth, email/password)
β”‚   β”œβ”€β”€ report/page.tsx                # Click-to-place map report form
β”‚   β”œβ”€β”€ auth/
β”‚   β”‚   β”œβ”€β”€ callback/route.ts          # OAuth callback handler
β”‚   β”‚   └── logout/route.ts            # Server-side logout (cookie clearing)
β”‚   β”œβ”€β”€ responder/
β”‚   β”‚   β”œβ”€β”€ page.tsx                   # Responder dashboard (cases, map, profile)
β”‚   β”‚   └── apply/page.tsx             # Responder application form
β”‚   └── admin/
β”‚       β”œβ”€β”€ layout.tsx
β”‚       └── page.tsx                   # Admin panel (5 tabs: Overview, Users, Verification, Sightings, Logs)
β”œβ”€β”€ components/
β”‚   β”œβ”€β”€ UserProvider.tsx               # User context (user + role)
β”‚   β”œβ”€β”€ map/
β”‚   β”‚   β”œβ”€β”€ HeatmapMap.tsx             # Citizen view β€” translucent circles, no pins
β”‚   β”‚   β”œβ”€β”€ ResponderMap.tsx           # Responder view β€” exact pins + 100m zones
β”‚   β”‚   └── AdminMap.tsx               # Admin view β€” full overlay
β”‚   β”œβ”€β”€ report/
β”‚   β”‚   └── ReportMap.tsx              # Click-to-place pin map
β”‚   └── ui/
β”‚       β”œβ”€β”€ Navbar.tsx                 # Role-aware navigation
β”‚       β”œβ”€β”€ GlassCard.tsx, GlassPanel.tsx
β”‚       β”œβ”€β”€ Button.tsx, Badge.tsx
β”‚       β”œβ”€β”€ Input.tsx, Modal.tsx
β”‚       β”œβ”€β”€ LoadingSpinner.tsx, Skeleton.tsx
β”‚       └── Toast.tsx, Sidebar.tsx
β”œβ”€β”€ lib/
β”‚   β”œβ”€β”€ supabase.ts                    # Singleton createBrowserClient + all types
β”‚   β”œβ”€β”€ supabase-provider.tsx          # Supabase context provider
β”‚   β”œβ”€β”€ query-provider.tsx             # React Query client
β”‚   └── utils.ts                       # cn() helper
└── hooks/
    β”œβ”€β”€ useSightings.ts                # Fetch + realtime subscription
    └── useRealtime.ts                 # Generic realtime hook

πŸš€ Getting Started

Prerequisites

  • Node.js 18+ (for Next.js 16)
  • npm or yarn
  • Supabase project (free tier works)

Installation

  1. Clone the repo

    git clone https://github.com/qppd/snake-sightings.git
    cd snake-sightings
  2. Install dependencies

    npm install --legacy-peer-deps
  3. Environment setup Copy .env.example to .env.local and fill in your Supabase credentials:

    cp .env.example .env.local

    Required variables:

    NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
    NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
    SUPABASE_SERVICE_ROLE_KEY=your_service_role_key
    
  4. Run database migration Open your Supabase SQL Editor and run:

    • supabase/migrations/001_initial_schema.sql (complete schema + RLS)
    • supabase/rls.sql (RLS policies β€” already included in migration)
  5. Start the dev server

    npm run dev

    Open http://localhost:3000

πŸ”§ Build

npm run build
npm run start

Vercel Deployment (One-Click)

  1. Push to GitHub
  2. Import repo on Vercel
  3. Add environment variables (same as .env.local)
  4. Deploy β€” no build config needed

πŸ” Auth Architecture

Supabase Client Architecture

Uses single createBrowserClient from @supabase/ssr (cookie-based session storage):

Source Library Creates Instance?
src/lib/supabase.ts @supabase/ssr createBrowserClient() Yes β€” singleton
src/lib/supabase-provider.tsx @supabase/ssr No β€” reuses singleton
src/proxy.ts @supabase/ssr createServerClient() Per-request
auth/callback/route.ts @supabase/ssr createServerClient() Per-request
auth/logout/route.ts @supabase/ssr createServerClient() Per-request

Logout Flow

Server-side POST route clears ALL cookies via maxAge: 0. Navbar uses <form action="/auth/logout" method="POST"> for reliable logout.

Proxy Middleware

src/proxy.ts runs on every request:

  1. Checks session via createServerClient
  2. Redirects unauthenticated users to /login
  3. Fetches user role from profiles table
  4. Enforces role-based route access
  5. Public routes pass through

πŸ—ΊοΈ Map System

Three role-separated map components (Leaflet/OpenStreetMap with SSR-safe dynamic() imports):

  1. HeatmapMap β€” Citizen view: translucent risk-colored circles over metro areas. No pins, no exact coords.
  2. ResponderMap β€” Exact GPS pins + 100m search zone circles for assigned incidents.
  3. AdminMap β€” Full data overlay with all sightings.

Privacy model: Citizens see heatmap only. Responders see exact pins + zones for assigned incidents. Admins see everything.

πŸ‘₯ Roles

Role Default Route Access
citizen / Heatmap, report sightings
responder /responder Dashboard, assigned cases
admin /admin Full system governance
sub_admin /admin Limited moderation

πŸ—„οΈ Database Schema

Tables

  • profiles β€” User profiles (extends auth.users, auto-created on signup)
  • sightings β€” Core data: risk level, GPS coords, description, visibility mode
  • incidents β€” Links responders to sightings they handle
  • responder_applications β€” Verification applications
  • system_logs β€” Audit trail for admin actions

RLS Policies

  • 20+ policies enforcing privacy-first access
  • Citizens: INSERT own sightings, SELECT own + heatmap_only
  • Responders: SELECT only assigned incident sightings
  • Admins: Full read/write
  • get_user_role() function with SECURITY DEFINER to avoid recursion

πŸ“Š Testing

npm test          # Run all tests
npm run test:watch  # Watch mode
npm run test:coverage # Coverage report

πŸ”’ Security

  • No frontend trust β€” RLS enforces all access control server-side
  • Heatmap privacy β€” exact coords never exposed to citizens
  • Cookie-based sessions β€” HttpOnly cookies managed server-side
  • Audit logging β€” All admin actions logged to system_logs
  • Input sanitization β€” RLS prevents unauthorized inserts/updates

πŸ“ License

MIT β€” see LICENSE

🀝 Contributing

  1. Fork the repo
  2. Create a feature branch
  3. Make changes
  4. Run npm run build β€” ensure it compiles
  5. Submit a PR

Built with ❀️ for community safety

About

A geospatial safety platform for reporting and tracking snake encounters in the Philippines. Citizens can report sightings safely (heatmap only, no exact coordinates exposed), responders handle incidents with exact GPS access, and admins manage verification and analytics.

Topics

Resources

Stars

Watchers

Forks