Skip to content

Vidit

License: AGPL v3 Live demo

A web platform for OSINT/GEOINT analysts to archive, reference, and visualize geolocations of armed-conflict events. Interactive map, structured submission flow (coords + source + media + Tiptap proof + tags), community requests, and analyst profiles.

Live at vidit.app (beta).

Work reaches the map through one of four doors. Three of them read an analyst's own X posts and produce machine detections; the fourth is the submit form. Nothing is published until a person vouches for it.

flowchart LR
  classDef spec fill:#eef1fb,stroke:#4a5fa5,color:#33417a
  classDef shared fill:#e3f2f1,stroke:#0f7b7a,color:#0b5c5b
  classDef core fill:#0f7b7a,stroke:#083f3e,stroke-width:3px,color:#ffffff
  classDef store fill:#0b5c5b,stroke:#083f3e,color:#ffffff

  subgraph legend [Legend]
    direction LR
    l1["`what an analyst does`"]:::spec
    l2["`what the machine does`"]:::shared
    l3["`the moment a person vouches`"]:::core
    l4[("`the catalog`")]:::store
    l1 ~~~ l2 ~~~ l3 ~~~ l4
  end

  subgraph doors [Four ways work comes in]
    direction TB
    hand["`**/submit**
    one form: coordinates, source, media, tags, and a Tiptap proof`"]:::spec
    bot["`**tag @ViditBot on X**`"]:::spec
    paste["`**paste one of your own posts**`"]:::spec
    arch["`**bulk import your X export**`"]:::spec
  end

  engine["`**one detection engine, three entries**
  reads the coordinate, the source and the media out of the post`"]:::shared
  det["`**a detection**
  public from the moment it lands, badged as machine output`"]:::shared
  review["`**your review**
  complete it and publish, or reject it`"]:::core
  ev[("`**events**
  one row per geolocation; a published row is corrected by versions, never overwritten`")]:::store
  read["`**/map, /search, /requests, /profile/{username}**
  open to anonymous readers`"]:::spec

  hand --> ev
  bot --> engine
  paste --> engine
  arch --> engine
  engine --> det --> review --> ev
  ev --> read
Loading

The detection engine is documented in docs/ingestion.md, the row and its statuses in docs/data-model.md.


Why open source

100% open source under AGPL-3.0, nothing proprietary. Anyone can self-host the platform; modifications deployed as a network service must publish their source under the same license. Today nothing on the maintainer's hosted instance (vidit.app) is paid. The analyst-facing platform is, and will stay, free; if the hosted instance ever charges for anything, it will be surfaces aimed at consumers of the community's work (alert webhooks, larger exports), never at the analysts producing it. Details in planning/roadmap.mdOpenness & transparency.


Demo

promo-readme.mp4

Tech stack at a glance

Layer Choice
Backend FastAPI (Python 3.12) + SQLAlchemy 2 + GeoAlchemy2 + Alembic
Database PostgreSQL + PostGIS 3 (16 in prod, 18 locally)
Auth Cookie session + double-submit CSRF (JWT payload, PyJWT) + bcrypt + invite codes
Storage AWS S3 + CloudFront (media)
Frontend Next.js 16 (App Router) + TypeScript + Tailwind
Map MapLibre GL JS + CARTO Dark Matter tiles, client-side clustering
Editor Tiptap (rich proof)
Hosting Railway (API + DB) + Vercel (frontend)
Package mgmt uv (backend) + npm (frontend)

Details and rationale: docs/engineering.md.


Repository layout

vidit/
├── backend/          FastAPI service (uv)
│   ├── app/          routers → services → models, Pydantic schemas
│   ├── alembic/      migrations
│   ├── scripts/      one-off ops scripts (mock admin, detection seeder, prod import)
│   └── tests/
├── frontend/         Next.js 16 app (npm)
│   └── src/
│       ├── app/         App Router pages
│       ├── components/
│       ├── contexts/    React context providers (auth, map state)
│       ├── hooks/
│       ├── lib/
│       ├── types/
│       └── proxy.ts     default-deny auth + host canonicalisation
├── video/            promo-as-code pipeline (Playwright capture + Remotion render, `make promo`)
├── docs/             api, backups, data-model, design, engineering (technical reference)
├── planning/         roadmap + next (project planning, not user docs)
├── docker/           daily backup cron image
├── AGENTS.md            project context for AI tools (CLAUDE.md is a one-line `@AGENTS.md` pointer for Claude Code)
├── CHANGELOG.md         release history
├── CODE_OF_CONDUCT.md   Contributor Covenant 2.1
├── CONTRIBUTING.md      PR flow + commits + doc-sync rule
├── LICENSE              AGPL-3.0
├── SECURITY.md          vulnerability reporting
├── docker-compose.yml   PostgreSQL + PostGIS for local dev
├── Makefile             init / dev / seed / test entry points
└── .github/workflows/   backend + frontend CI + manual deploy

More detail: docs/engineering.md.


Documentation

The technical reference is also hosted at docs.vidit.app (MkDocs Material build of docs/).


Getting started (local dev)

make init        # install + env + db-up + migrate (one-shot bootstrap)
make seed        # mock-admin + machine detections from the committed synthetic archive
make import-prod # replace the local DB with the latest production backup (see docs/backups.md)
make dev         # FastAPI :8000 + Next.js :3000 in parallel
make dev-worker  # archive-import worker (optional; without it, archive uploads stay queued)
make test        # backend pytest

make help lists every target individually.

Prerequisites

  • Docker (for PostgreSQL + PostGIS; local and prod both run postgis/postgis:16-3.4, see docs/backups.md)
  • Python 3.12+ and uv
  • Node.js 20+ and npm

Secrets

make init copies .env.example.env (backend) and .env.local.example.env.local (frontend). Defaults are wired for localhost; every var is documented inline in backend/.env.example and frontend/.env.local.example. API docs auto-served at http://localhost:8000/docs.

Bootstrap an account

make seed (or make mock-admin) creates admin@vidit.app / admin directly. To exercise the real invite + registration flow:

  1. Set ADMIN_EMAILS=<your-email> in backend/.env so your account auto-promotes to admin on first login.
  2. Get an invite code: once an admin exists, the /admin panel mints them; for the very first one run make mock-admin to get one.
  3. Register at http://localhost:3000/register with the code.
  4. EMAIL_PROVIDER=console (the local default) prints the confirmation link to backend stdout.

Troubleshooting

  • Database connection failed: ensure docker-compose up -d is running and nothing else holds port 5432.
  • Frontend can't reach the API: check NEXT_PUBLIC_API_URL in frontend/.env.local is http://localhost:8000/api/v1.
  • "Module not found": re-run uv sync (backend) / npm install (frontend), or make install for both.

Working on the project

Backend

cd backend
uv run pytest                              # run tests
uv run ruff check .                        # lint
uv run ruff format .                       # format
uv run alembic revision --autogenerate -m "..."   # new migration

Frontend

cd frontend
npm run lint
npm run build

Conventions

See AGENTS.mdConventions.


License

Licensed under the GNU Affero General Public License v3.0. See CONTRIBUTING.md, SECURITY.md, and CODE_OF_CONDUCT.md.


Acknowledgements

The content shown in the landing video uses real geolocation work from @geo27752, reproduced with their consent. Thanks for letting Vidit show the platform the way analysts actually use it.

About

OSINT/GEOINT geolocation archive for armed-conflict events — open source under AGPL-3.0

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages