Harbor is a lightweight civic technology project for finding nearby survival resources quickly and anonymously. The current MVP+ helps people browse Wilmington, Delaware resources such as food pantries, shelters, clinics, public restrooms, libraries, charging/Wi-Fi locations, warming/cooling centers, and transportation support.
The project is intentionally practical: fast resource lookup, clear availability signals, anonymous community reporting, and a calm mobile-first interface.
Harbor helps people find essential local resources under stressful conditions without requiring an account, exposing unnecessary personal data, or depending on heavy interfaces.
Resource information is often scattered across PDFs, websites, phone lines, social posts, and outdated directories. For someone trying to find food, shelter, restrooms, transportation, or a place to charge a phone, the experience needs to be simple, current, and usable on a mobile device.
Harbor addresses this by providing:
- A focused public directory of survival resources.
- Anonymous browsing for core features.
- Community verification reports for freshness and trust.
- Offline-friendly saved resource snapshots.
- A list-first interface that works even when maps or bandwidth are unreliable.
- Browse public resources by category and city.
- View detailed resource information, including address, phone, website, hours, accessibility notes, eligibility notes, and intake notes.
- Submit anonymous verification reports for incorrect or changed information.
- See lightweight trust indicators such as community report count, recent community updates, and recently updated status.
- View recent anonymous community updates on resource detail pages.
- Save viewed resources locally for offline reference.
- Toggle an optional OpenStreetMap view while keeping the resource list primary.
- Access backend health, OpenAPI documentation, and Prometheus-compatible metrics.
Harbor currently uses a simple full-stack architecture. The backend is designed as the first service in a future microservice system, but the current implementation keeps scope small enough for a solo developer or student project.
flowchart LR
user["User on mobile or desktop"]
frontend["React + Vite frontend"]
backend["Spring Boot resource-service"]
db[("PostgreSQL")]
local["Browser localStorage"]
docs["Swagger / OpenAPI"]
user --> frontend
frontend -->|"REST API"| backend
frontend -->|"offline snapshots"| local
backend -->|"JPA + Flyway"| db
backend --> docs
flowchart TB
subgraph Browser
app["Harbor web app"]
offline["Saved resources in localStorage"]
leaflet["Optional Leaflet map"]
end
subgraph API
controller["REST controllers"]
services["Domain services"]
repositories["JPA repositories"]
end
subgraph PostgreSQL
categories["resource_categories"]
resources["resources"]
hours["resource_hours"]
statuses["resource_status"]
reports["verification_reports"]
orgs["organizations"]
end
app --> controller
app --> offline
app --> leaflet
controller --> services
services --> repositories
repositories --> categories
repositories --> resources
repositories --> hours
repositories --> statuses
repositories --> reports
repositories --> orgs
sequenceDiagram
participant User
participant Web as React frontend
participant API as resource-service
participant DB as PostgreSQL
User->>Web: Search resources
Web->>API: GET /api/resources?city=Wilmington
API->>DB: Query public resources
DB-->>API: Resources, status, categories
API-->>Web: Resource summaries with trust metadata
Web-->>User: List-first results
User->>Web: Submit anonymous report
Web->>API: POST /api/resources/{id}/verification-reports
API->>DB: Store pending verification report
API-->>Web: Created report
Web-->>User: Confirmation message
- Java 21
- Spring Boot 3.5.x
- Spring Web
- Spring Data JPA / Hibernate
- PostgreSQL
- Flyway
- Bean Validation
- Lombok
- Spring Boot Actuator
- Springdoc OpenAPI / Swagger UI
- Docker
- React
- TypeScript
- Vite
- Tailwind CSS
- Leaflet / React Leaflet
- Browser localStorage for offline snapshots
- Docker Compose
- PostgreSQL 16
- OpenAPI documentation
- Actuator health endpoints
- Prometheus metrics endpoint
- Request correlation IDs in API responses and logs
Screenshots are intentionally tracked as placeholders for now. Add final images or GIFs under docs/screenshots/ as the UI stabilizes.
docs/screenshots/home-page.svg
docs/screenshots/resource-detail.svg
docs/screenshots/offline-mode.svg
docs/screenshots/map-view.svg
docs/screenshots/verification-reporting.svg
When the backend is running locally:
- Swagger UI:
http://localhost:8081/swagger-ui.html - OpenAPI JSON:
http://localhost:8081/v3/api-docs - Health check:
http://localhost:8081/actuator/health - Prometheus metrics:
http://localhost:8081/actuator/prometheus
| Method | Endpoint | Purpose |
|---|---|---|
GET |
/api/categories |
List active resource categories |
GET |
/api/resources |
List public resources |
GET |
/api/resources?category=food |
Filter resources by category |
GET |
/api/resources?city=Wilmington |
Filter resources by city |
GET |
/api/resources?page=0&size=10 |
Paginated resource lookup |
GET |
/api/resources/{id} |
View resource detail |
POST |
/api/resources/{id}/verification-reports |
Submit anonymous community report |
GET |
/api/organizations |
List organizations associated with resources |
List resources:
curl http://localhost:8081/api/resourcesFilter food resources:
curl "http://localhost:8081/api/resources?category=food&page=0&size=5"View a resource:
curl http://localhost:8081/api/resources/11111111-1111-4111-8111-111111111111Submit an anonymous verification report:
curl -X POST \
http://localhost:8081/api/resources/11111111-1111-4111-8111-111111111111/verification-reports \
-H "Content-Type: application/json" \
-d '{
"reportType": "shelter_full",
"description": "Staff said no beds were available tonight.",
"suggestedValue": {
"reporterKind": "anonymous"
}
}'Supported report types:
food_unavailableshelter_fullrestroom_closedwifi_offlineunsafe_locationincorrect_hoursinaccessibleother
- Java 21
- Docker Desktop or compatible Docker runtime
- Node.js 20 or newer
- npm
From the repository root:
docker compose up --buildThe backend runs at:
http://localhost:8081
The current Docker Compose setup exposes PostgreSQL on the host for local inspection:
localhost:5434
To rebuild the database from Flyway migrations:
docker compose down -v
docker compose up --buildcd web-app
npm install
npm run devVite usually starts at:
http://127.0.0.1:5173
If that port is already in use, Vite may choose another 517x port. The backend CORS configuration allows local Vite development ports in that range.
The root docker-compose.yml is for local/dev only. It starts:
postgres: PostgreSQL database with persistent Docker volume.resource-service: Spring Boot API container on port8081.prometheus: local metrics scraper on port9090.grafana: local dashboard UI on port3000.
Common commands:
docker compose up --build
docker compose up --build -d
docker compose logs -f resource-service
docker compose down
docker compose down -vBackend configuration is provided through environment variables. Use .env.example as a safe template and keep local .env files out of commits.
SPRING_PROFILES_ACTIVE=docker
SPRING_DATASOURCE_URL=jdbc:postgresql://postgres:5432/harbor
SPRING_DATASOURCE_USERNAME=postgres
SPRING_DATASOURCE_PASSWORD=harbor-local-password
HARBOR_SEED_DATA_ENABLED=true
HARBOR_OPENAPI_ENABLED=true
HARBOR_CORS_ALLOWED_ORIGIN_PATTERNS=http://localhost:517*,http://127.0.0.1:517*
Frontend configuration:
VITE_API_BASE_URL=http://localhost:8081
Harbor supports environment-specific backend profiles:
local: host-based local development with seed data and OpenAPI enabled.docker: local Docker Compose development with seed data and OpenAPI enabled.prod: production-safe runtime defaults with externalized secrets, explicit CORS, OpenAPI disabled by default, and seed data disabled.
Production deployments should set SPRING_PROFILES_ACTIVE=prod, provide database credentials through the runtime secret manager, set HARBOR_CORS_ALLOWED_ORIGIN_PATTERNS to the frontend domain, and keep HARBOR_SEED_DATA_ENABLED=false.
Version metadata is available at:
/api/version
/actuator/info
See docs/deployment-readiness.md for backend deployment, frontend deployment, migration strategy, rollback plan, and health check verification.
.
|-- docker-compose.yml
|-- README.md
|-- resource-service/
| |-- Dockerfile
| |-- pom.xml
| `-- src/main/
| |-- java/com/harbor/resourceservice/
| | |-- category/
| | |-- common/
| | |-- organization/
| | |-- resource/
| | `-- verification/
| `-- resources/db/migration/
`-- web-app/
|-- package.json
`-- src/
|-- api/
|-- components/
|-- features/
|-- pages/
`-- types/
Resource data benefits from strong relational modeling: categories, organizations, hours, statuses, and verification reports all have clear relationships and constraints. PostgreSQL also supports mature indexing, migrations, and future geospatial options through PostGIS if Harbor later needs more advanced location search.
Docker keeps local development reproducible. A reviewer can start the API and database with one command without manually installing PostgreSQL or matching local database settings.
OpenStreetMap keeps the map experience aligned with Harbor's civic and privacy-first goals. It avoids vendor lock-in, does not require Google API keys for the MVP, and supports a lightweight optional map view while the list remains the primary interface.
The most important Harbor workflows are finding resources and reporting incorrect information. Requiring login would add friction, privacy concerns, and implementation complexity before the core public utility is proven. Account-based saved resources, admin review tools, and organization users can be added later without blocking anonymous access.
Maps are useful, but they can be slow, battery-heavy, and harder to scan under stress. Harbor presents resources as a readable list first, with the map as a secondary option. This keeps the interface useful on small screens and unreliable connections.
Harbor is meant for real-world use, including stressful conditions, older phones, limited battery, spotty service, and users who rely on assistive technology. Clear contrast, semantic HTML, keyboard access, readable cards, and minimal visual noise are product requirements, not polish.
- Anonymous access for core resource browsing.
- Calm visual design with restrained colors and readable spacing.
- Mobile-first layouts with thumb-friendly controls.
- List-first browsing with optional map support.
- Clear loading, empty, and error states.
- Screen-reader friendly labels and semantic structure.
- No ads, gamification, social feeds, or unnecessary animation.
- AI is not part of the current MVP and is not required for survival-critical workflows.
Harbor currently focuses on one backend service and one frontend application:
- Resource directory
- Category filtering
- Resource detail pages
- Seeded Wilmington, Delaware resource data
- Anonymous verification reports
- Community freshness metadata
- Offline local resource snapshots
- Optional map view
- API documentation and health checks
- Add admin review workflows for pending verification reports.
- Add organization-managed resource updates.
- Add stronger data quality workflows and audit history.
- Add PostGIS-backed distance search.
- Add notification subscriptions for critical resource changes.
- Add deployment configuration for a low-cost cloud environment.
- Add observability dashboards with Prometheus and Grafana.
- Add service boundaries for notification, search, and verification only when the product needs them.
- Add optional translation and plain-language assistance after the core directory remains reliable without it.
Harbor is designed to demonstrate practical full-stack engineering:
- Spring Boot service design with domain-based package organization.
- PostgreSQL schema design with Flyway migrations.
- REST API design with OpenAPI documentation.
- Dockerized local development.
- React + TypeScript frontend with reusable components.
- Accessibility-aware, mobile-first product thinking.
- Clear tradeoffs around privacy, reliability, and scope control.