A GIS + workflow prototype for road construction lifecycle management, targeting local government road management staff in Nagoya.
- Frontend: React + TypeScript + Vite, Mantine UI, Zustand, React Query, MapLibre GL JS
- Backend: Node.js + TypeScript + Fastify, Drizzle ORM
- Database: PostgreSQL + PostGIS
- NGSI-LD: FIWARE Orion-LD context broker
- DevOps: Docker Compose
- Node.js 20+
- Docker & Docker Compose
- npm or pnpm
-
Start infrastructure services:
docker compose up -d db mongo orion-ld
-
Install dependencies:
npm install
-
Generate database migrations:
cd backend npm run db:generate npm run db:migrate npm run db:seed cd ..
-
Start development servers:
npm run dev
This starts:
- Backend API at http://localhost:3000
- Frontend at http://localhost:5173
Run everything in containers:
docker compose up -dnagoya-construction-lifecycle/
├── backend/ # Fastify API server
│ ├── src/
│ │ ├── db/ # Database schema & migrations
│ │ ├── routes/ # API endpoints
│ │ ├── services/ # Business logic
│ │ └── ngsi/ # NGSI-LD context files
│ └── drizzle/ # Migration files
├── frontend/ # React application
│ └── src/
│ ├── components/ # UI components
│ ├── features/ # Feature modules
│ ├── hooks/ # Custom hooks
│ └── stores/ # Zustand state
├── shared/ # Shared TypeScript types
└── sample-data/ # Sample GeoJSON data
| Endpoint | Method | Description |
|---|---|---|
/events |
GET, POST | List/Create events |
/events/:id |
GET, PUT | Get/Update event |
/events/:id/status |
PATCH | Change status |
/events/:id/decision |
PATCH | Set post-end decision |
/assets |
GET, POST | List/Create assets |
/assets/:id |
GET, PUT | Get/Update asset |
/assets/:id/retire |
PATCH | Retire asset |
/inspections |
GET, POST | List/Create inspections |
/import/geojson |
POST | Import GeoJSON |
/export/geojson |
GET | Export GeoJSON |
- Construction Event Lifecycle: Planned → Active → Ended
- Map Visualization: Events and road assets displayed on MapLibre GL JS
- Post-End Decision: Permanent change or archive after event ends
- Road Asset Traceability: All changes linked to source events
- NGSI-LD Sync: Real-time sync to Orion-LD context broker
DATABASE_URL: PostgreSQL connection stringORION_LD_URL: Orion-LD endpointPORT: Server port (default: 3000)TZ: Timezone (default: Asia/Tokyo)
VITE_API_URL: Backend API URL
- URL: https://eventflow.uixai.org
- Host: EC2 (ubuntu@18.177.72.233)
- SSH:
ssh -i ~/.ssh/eventflow-prod-key.pem ubuntu@18.177.72.233
# Sync code to EC2
rsync -avz --exclude 'node_modules' --exclude '.git' \
-e "ssh -i ~/.ssh/eventflow-prod-key.pem" \
./ ubuntu@18.177.72.233:/home/ubuntu/nagoya-construction-lifecycle/
# Rebuild and restart
ssh -i ~/.ssh/eventflow-prod-key.pem ubuntu@18.177.72.233 \
"cd /home/ubuntu/nagoya-construction-lifecycle && docker compose up -d --build"-
PostgreSQL Password Fix: The database volume may have a different password than docker-compose.yml. A
docker-compose.override.ymlis configured to automatically reset the password via healthcheck:services: db: healthcheck: test: ["CMD-SHELL", "pg_isready -U postgres && psql -U postgres -c \"ALTER USER postgres WITH PASSWORD 'postgres'\" > /dev/null 2>&1 || true"]
-
Uploads Volume Mount: The API container requires access to the uploads directory for import diffs and snapshots:
volumes: - ./backend/uploads:/app/uploads
-
Services:
nagoya-api: Backend API (port 3000)nagoya-web: Frontend (port 5173)nagoya-db: PostgreSQL + PostGISnagoya-martin: MVT tile servernagoya-caddy: Reverse proxy with HTTPS
# Check API logs
docker logs nagoya-api --tail 50
# Reset DB password manually if needed
docker exec nagoya-db psql -U postgres -c "ALTER USER postgres WITH PASSWORD 'postgres';"
docker restart nagoya-api nagoya-martinPrivate - Eukarya Inc.