One good plan for tonight, instead of 200 options
A free map of what's on in Paris tonight, sorted by culture and by category — built to help you choose, not to overwhelm you.
The need
After a busy week, people want to go out, but scrolling through hundreds of events is exhausting. Too many options usually ends with staying home.
The idea
The problem isn't a lack of options, it's their number. So the app starts from one simple question — what can I do tonight, close by? — instead of opening on a catalogue.
What I built
- A website that opens directly on tonight's events, on a map, designed for phones first.
- An automatic collector that gathers events from the City of Paris open data, from foreign cultural institutes in Paris (FICEP) and from other public feeds, and refreshes each source on its own schedule.
- A way to browse by culture of origin and by category, so you can follow what you feel like.
- Safety nets: if a source goes down, the last good data keeps being served and the status page says “degraded” instead of crashing.
The result
- 27,623events in its database (measured 6 Oct 2026)
- 0events without a location on the map
- 4open data sources and venue feeds, combined automatically (measured 6 Oct 2026)
Online at eventmap.hamdy-tabsissi.com since 23 August 2026. Every event in its database is placed on the map, and the data refreshes on its own.
In pictures
What I learned
Test the data before designing the product: a quick survey of the source found zero events in Nanterre and fourteen in Montreuil, so I narrowed the scope to Paris instead of maintaining fragile scrapers. And silent bugs cost more than crashes — dates compared as text were quietly hiding events until testing caught it.
Technical details Stack, architecture and decisions — for technical readers
Stack
- Python (FastAPI, asyncio)
- SQLite
- Leaflet + OpenStreetMap
- nginx
- systemd
- Ubuntu 22.04
Architecture at a glance
- Visitor's phone or browser
- nginx — reverse proxy, security headers
- FastAPI app (uvicorn) — systemd service bound to 127.0.0.1, with CPU and memory quotas
- SQLite — events, sources, de-duplication
- Collector every 6 hours ← City of Paris open data + FICEP (OpenAgenda)
How it works
- Asynchronous ingestion (asyncio) of several open feeds — Que faire à Paris (City of Paris, ODbL licence), FICEP and OpenAgenda (.ics) among them — into SQLite, with de-duplication. The live source list is in /health.
- Fault-tolerant refresh, source by source: a failing source never wipes existing data; /health reports each source’s status and switches to “degraded”.
- Scope narrowed from Nanterre–Paris–Montreuil to Paris after an audit of 13 suburban sites found no usable feed (no .ics, no JSON-LD Event). The multi-source architecture stays ready.
- Isolated service: dedicated system user without a shell, systemd CPU and memory quotas, application bound to 127.0.0.1 behind nginx.
- Bug found in testing: dates compared as strings, silently excluding events in production — fixed and documented.
Incidents & fixes
- From 24 Sept to 5 Oct 2026 the City of Paris feed was unreachable from the server (DNS error): EventMap kept serving the last good data and /health reported “degraded”, naming the source. When the feed came back, a database constraint (a duplicate pointing to a row being purged) made every refresh fail silently while /health wrongly said “ok”. Reproduced locally, fixed, covered by two tests and redeployed the same day: 16,160 events refreshed.
Still missing
- Paris only
- Depends on the quality of public open data feeds