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
Three versions are deployed on the same EC2 server with isolated services:
| Domain | Version | Branch | Purpose | Container Prefix | Database |
|---|---|---|---|---|---|
| v1.eventflow.uixai.org | V1 (Frozen) | main (tag: v1.0.0) |
Stable production baseline | nagoya-*-v1 |
nagoya_construction_v1 |
| eventflow.uixai.org | Current | main |
Active development | nagoya-* |
nagoya_construction |
| demo.eventflow.uixai.org | Auth Demo | frontend |
Role-based access control demo | nagoya-demo-* |
nagoya_construction_demo |
Key Features by Version:
- V1: Original feature set (frozen)
- Current: Latest features + bug fixes
- Demo: Showcase for department-scoped authentication system
- Host: EC2 (ubuntu@18.177.72.233)
- SSH:
ssh -i ~/.ssh/eventflow-prod-key.pem ubuntu@18.177.72.233 - Reverse Proxy: Caddy (handles all three domains)
# SSH to server
ssh -i ~/.ssh/eventflow-prod-key.pem ubuntu@18.177.72.233
# Navigate to project
cd ~/eventflow
# Update code
git pull origin main
# Rebuild and restart main services
docker compose up -d --build
# Restart Caddy to pick up config changes
docker restart nagoya-caddySee detailed guide: docs/DEMO_DEPLOYMENT.md
# SSH to server
ssh -i ~/.ssh/eventflow-prod-key.pem ubuntu@18.177.72.233
cd ~/eventflow
# Checkout demo branch
git fetch origin
git checkout frontend
git pull origin frontend
# Build and start demo services
docker compose -f docker-compose.demo.yml up -d --build
# Restart Caddy
docker restart nagoya-caddyV1 is frozen and should not be updated unless critical security fixes are needed.
# Use docker-compose.v1.yml if updates are necessary
docker compose -f docker-compose.v1.yml 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 by Version:
Main (eventflow.uixai.org):
nagoya-api: Backend APInagoya-web: Frontendnagoya-db: PostgreSQL + PostGISnagoya-martin: MVT tile servernagoya-mongo: MongoDB for NGSI-LDnagoya-orion-ld: FIWARE Orion-LD
V1 (v1.eventflow.uixai.org):
nagoya-api-v1: Backend API (frozen)nagoya-web-v1: Frontend (frozen)nagoya-db-v1: PostgreSQL + PostGISnagoya-martin-v1: MVT tile server
Demo (demo.eventflow.uixai.org):
nagoya-demo-api: Backend APInagoya-demo-web: Frontend with auth systemnagoya-demo-db: PostgreSQL + PostGISnagoya-demo-martin: MVT tile servernagoya-demo-mongo: MongoDB for NGSI-LDnagoya-demo-orion-ld: FIWARE Orion-LD
Shared:
nagoya-caddy: Reverse proxy with HTTPS (serves all three domains)
# 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.