Crowdsourced locations of first-aid kits, AEDs, and other emergency supplies.
AidMap is a lightweight Flask application that lets communities crowdsource the locations of critical emergency resourcesβlike first-aid kits, AEDs, and general emergency kitsβonto an interactive Mapbox map. Submissions can include photos, are vetted via a built-in moderator workflow with optional two-factor authentication, and can be upvoted to highlight the most useful entries.
- Live site: aidmap.live
- Tech: Python + Flask, SQLite, Mapbox GL JS
- Topics: crowdsourcing, emergency-response, first aid, mapping
- Features
- Quickstart
- Configuration
- API
- Data Model
- Frontend and Resource Types
- Deployment
- Security Notes
- Contributing
- Roadmap
- Acknowledgments
- License
- Users submit latitude/longitude, resource type, description, and optional image (PNG/JPEG).
- Password-based moderator login with optional TOTP 2FA (Google Authenticator compatible).
- Approve or reject pending submissions.
- Simple per-browser voting with lookback window to reduce repeat votes.
- Mapbox-powered interactive map showing approved resources, colored by type.
- Update labels and colors in a JSON file without code changes.
- Strict content security policy, file size limits, MIME checks, and session scoping.
- Python 3.11+
- A Mapbox access token: account.mapbox.com
Clone and install:
git clone https://github.com/dankeg/AidMap.git
cd AidMap
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txtSet environment:
export MAPBOX_TOKEN="pk.your-mapbox-token"
# Optional but recommended for local moderation:
export ADMIN_USERNAME="admin"
export ADMIN_PASSWORD="choose-a-strong-password"
# Optional: bootstrap credentials path
# export ADMIN_BOOTSTRAP_PATH="$PWD/temp_credentials.txt"Start the app:
python app.py
# or with Gunicorn (recommended for prod-like runs)
gunicorn -c gunicorn_config.py app:app| Variable | Required | Description |
|---|---|---|
MAPBOX_TOKEN |
β | Mapbox access token used by frontend |
ADMIN_USERNAME |
β (default: admin) |
Moderator username |
ADMIN_PASSWORD |
β | If unset, random credentials are generated |
ADMIN_BOOTSTRAP_PATH |
β (default: temp_credentials.txt) |
File to store bootstrap credentials |
Other in-code defaults:
MAX_CONTENT_LENGTH = 16MBSESSION lifetime = 2 hours- Allowed MIME types:
image/jpeg,image/jpg,image/png
- If
ADMIN_PASSWORDis unset on first run, one-time credentials and a new TOTP secret are generated. - If set, moderators can enable 2FA via the moderator UI.
| Method | Route | Description |
|---|---|---|
GET |
/api/submissions |
Returns approved submissions |
GET |
/api/submissions/{id}/image |
Returns base64 image + MIME type |
POST |
/api/submit |
Submit new location (multipart/form-data) |
POST |
/api/vote/{submission_id} |
One vote per browser (30-day window) |
| Method | Route | Description |
|---|---|---|
POST |
/api/moderator/login |
Login, returns 2FA flag |
POST |
/api/moderator/login/totp |
Verify TOTP |
POST |
/api/moderator/logout |
Logout moderator |
GET |
/api/moderator/pending |
List pending submissions |
POST |
/api/moderator/approve/{id} |
Approve submission |
POST |
/api/moderator/reject/{id} |
Reject (delete) submission |
- SQLite database at
instance/medical_supplies.db - Schema: see
schema.sql
Tables
submissions: entries withstatus,votes,timestamps, optional image blobvotes: unique(submission_id, vote_token)with 30-day enforcementmoderators: username, password hash, optional TOTP secret
Reset Database
rm instance/medical_supplies.db
python app.py- Map UI uses
MAPBOX_TOKEN. - Resource categories are defined in
static/data/resource_types.json:
{
"value": "first_aid",
"label": "First Aid Kit",
"markerColor": "#FF0000",
"badgeBackground": "#FFF",
"badgeColor": "#000"
}Restart the app after edits. Submissions are validated against these entries.
gunicorn -c gunicorn_config.py app:app- Place Gunicorn behind Nginx/Apache/Caddy.
- Enforce HTTPS and caching.
- Ensure
instance/is writable for SQLite. - For scaling, migrate to a managed RDBMS.
- Provide secrets securely.
- Rotate moderator credentials periodically.
- Use strong moderator credentials.
- Enable and store TOTP secrets securely.
- CSP, X-Frame-Options, and similar headers are enforced.
- Uploads restricted to PNG/JPEG β€16MB.
- Votes are tokenized, not authenticated.
We welcome contributions that improve accessibility, data quality, and moderation UX.
- Open an issue for bugs or proposals.
- Fork β Branch β PR with clear description.
- Keep PRs focused and small.
- Include before/after screenshots for UI changes.
- Add tests where possible.
- Optional user accounts for trusted contributors
- Map filters and search
- Additional resource types and localization
- Export/backup tooling
- Rate-limiting and spam prevention
- CI, tests, and coverage
- Map rendering by Mapbox.
- Thanks to the open-source community for the Flask + mapping ecosystem.
This projectβs license is TBD.
Add a LICENSE file (e.g., MIT/Apache-2.0) and update the badge when chosen.
- Repository: github.com/dankeg/AidMap
- Branch:
main - Homepage: aidmap.live