Development guide for GEORISE - an AI-driven geospatial platform for incident management and multi-agency dispatch with real-time tracking
Development instructions for GEORISE, an AI-driven geospatial platform for incident management and multi-agency dispatch with real-time responder tracking.
GEORISE uses a monorepo structure with five main components:
1. **Frontend** (`frontend/`): Public/admin web portal built with React, Vite, Tailwind CSS, and Leaflet for mapping
2. **Responder App** (`responder-app/`): Mobile-first PWA for field agents using React, Vite, and Socket.IO
3. **Backend** (`backend/`): REST API and Socket.IO server using Node.js, Express, Prisma ORM, and PostGIS
4. **AI Service** (`ai-service/`): Incident classification microservice using Python FastAPI and AfroXLMR model
5. **Infrastructure** (`infra/`): Docker Compose configuration for PostgreSQL with PostGIS extension
1. **Start the database** (from `infra/` directory):
```bash
docker compose up -d
```
2. **Start the backend** (from `backend/` directory, runs on port 4000):
```bash
npm run dev
```
3. **Start the frontend** (from `frontend/` directory, runs on port 5173):
```bash
npm run dev
```
4. **Start the responder app** (from `responder-app/` directory, runs on port 5174):
```bash
npm run dev
```
5. **Start the AI service** (from `ai-service/` directory, runs on port 8001):
```bash
uvicorn main:app --reload --port 8001
```
```bash
npx prisma migrate dev
```
```bash
npm run seed
```
This populates agencies, users, and demo incidents.
```bash
npx prisma generate
```
```bash
npm run simulate:responder
```
Organize backend code into domain modules under `src/modules/{domain}/`:
**Standard CRUD Operations:**
Use the Prisma client for standard database operations.
**Spatial Queries with PostGIS:**
Use `prisma.$queryRaw` for PostGIS spatial operations:
```typescript
// Example: Find nearby incidents
const nearbyIncidents = await prisma.$queryRaw`
SELECT * FROM incidents
WHERE ST_DWithin(
location::geography,
ST_SetSRID(ST_MakePoint(${longitude}, ${latitude}), 4326)::geography,
${radiusInMeters}
)
`;
```
**GeoJSON Handling:**
Use the centralized logger (`src/logger.ts` with Pino) instead of `console.log`:
```typescript
import logger from '../logger';
logger.info('Incident created', { incidentId });
logger.error('Failed to dispatch', { error: err.message });
```
Apply input validation using Zod schemas with the `validate` middleware:
```typescript
import { validate } from '../middleware/validate';
import { createIncidentSchema } from './incident.schema';
router.post('/incidents', validate(createIncidentSchema), controller.create);
```
**Authentication:**
Use `AuthContext` for managing JWT tokens and user roles:
```typescript
const { user, token, login, logout } = useAuth();
```
**Offline Support:**
Use `idb-keyval` to cache incidents and forms when offline:
```typescript
import { set, get } from 'idb-keyval';
// Cache incident data
await set('incidents', incidentList);
// Retrieve when offline
const cachedIncidents = await get('incidents');
```
**Basic Map Setup:**
Use `react-leaflet` components for map rendering:
```tsx
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
<MapContainer center={[lat, lng]} zoom={13}>
<TileLayer url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" />
</MapContainer>
```
**Marker Clustering:**
Use `react-leaflet-cluster` for displaying many incident markers:
```tsx
import MarkerClusterGroup from 'react-leaflet-cluster';
<MarkerClusterGroup>
{incidents.map(incident => (
<Marker key={incident.id} position={[incident.lat, incident.lng]} />
))}
</MarkerClusterGroup>
```
**Heatmaps:**
Use `leaflet.heat` for analytics visualization:
```typescript
import L from 'leaflet';
import 'leaflet.heat';
const heatLayer = L.heatLayer(coordinates, { radius: 25 });
```
Connect to Socket.IO for live incident and responder updates:
```typescript
import { io } from 'socket.io-client';
const socket = io('http://localhost:4000', {
auth: { token: authToken }
});
// Listen for new incidents
socket.on('incident:new', (incident) => {
// Update UI
});
// Listen for responder location updates
socket.on('responder:update', (data) => {
// Update responder marker position
});
```
**Endpoint:** `POST /classify`
**Request Body:**
```json
{
"title": "Fire at downtown building",
"description": "Large fire reported at 123 Main St. Multiple floors affected."
}
```
**Response:**
```json
{
"predicted_category": "Fire",
"severity_score": 0.89,
"confidence": 0.92
}
```
The AI service checks the `models/` directory for local weights. If not found, it falls back to the HuggingFace base AfroXLMR model.
Different user roles have different access levels:
The backend `dispatch` module automatically finds the nearest available responder using PostGIS spatial queries:
```typescript
// Find nearest responder
const nearestResponder = await prisma.$queryRaw`
SELECT id, ST_Distance(
last_location::geography,
ST_SetSRID(ST_MakePoint(${incidentLng}, ${incidentLat}), 4326)::geography
) as distance
FROM responders
WHERE status = 'available'
ORDER BY distance
LIMIT 1
`;
```
The backend emits events to specific rooms for targeted notifications:
Each service requires its own `.env` file. Ensure the following files exist:
Common environment variables:
1. **PostGIS Coordinate Order**: PostGIS uses `(longitude, latitude)` order for points, while Leaflet uses `[latitude, longitude]` arrays. Always convert appropriately.
2. **Prisma Client Generation**: Always run `npx prisma generate` after modifying the Prisma schema to update TypeScript types.
3. **Environment Variables**: Ensure each service has its own `.env` file with the required variables before starting development.
4. **Spatial Query Performance**: Add spatial indexes to PostGIS geometry columns for better query performance on large datasets.
5. **Real-time Event Handling**: Always clean up Socket.IO event listeners when components unmount to prevent memory leaks.
6. **Offline-First Design**: Implement proper offline caching and synchronization for the responder PWA to ensure field agents can work without connectivity.
1. **Unit Tests**: Test service layer business logic in isolation
2. **Integration Tests**: Test API endpoints with a test database
3. **Spatial Queries**: Verify PostGIS queries return expected results with known coordinates
4. **Real-time Events**: Test Socket.IO event emission and reception
5. **Offline Scenarios**: Test PWA functionality with network throttling
6. **AI Classification**: Test edge cases and fallback behavior when the AI service is unavailable
Leave a review
No reviews yet. Be the first to review this skill!
# Download SKILL.md from killerskills.ai/api/skills/geospatial-incident-management-platform-development/raw