$ cat posts/building-campeneste.md~/scorpse/

Building Câmpenește, a calendar for Romania’s rural events

Linked resource ↗https://campeneste.ro/

The question behind Câmpenește was simple. What’s happening in the Romanian countryside this weekend, and can I get there and back in a day?

An event name and a village can get you started. Planning a trip takes a confirmed date, a usable location, and some idea of the drive. An old festival page can look current at a glance while quietly describing last year’s edition. I wanted a guide that made that difference visible. Câmpenește

The Câmpenește homepage with the discovery filters and a configurable departure point

A local build, a public launch, and the work after it

I started with a local app in November 2026. Before putting it online I worked on the catalogue, the map and road routes, duplicate editions, and the way a source could support a confirmed date. Hosting was the next milestone. The public version then gave me more concrete questions to work through, from finding a festival on a phone to deciding what counted as enough evidence to publish a trip guide.

When, in Bucharest time Milestone
8 Nov, 19:52–21:08 Local app first. The catalogue gained road routes, tags, deduplicated editions, county coverage, and source checks for upcoming events.
8 Nov, 21:15–23:21 First Azure preview, then the custom domain and monitoring. Visitor suggestions and scheduled research also entered the app that evening.
9 Nov, early morning Permanent event pages, a faster mobile discovery flow, the first private operations dashboard, and a GitLab pipeline that verified the Azure deployment before publishing a release.
9 Nov, daytime and evening Trip guides, itineraries, driving times between stops, archive photos, admin sessions, weekly editorial review, source triage, and further refinements to discovery and the departure selector.
10 Nov, morning Location and analytics-consent refinements, followed by monitoring for official Facebook sources in the v0.29.0-beta.1 release.

The preview deployment commit came 1 hour 24 minutes after the first local implementation commit. The custom-domain commit followed 3 hours 29 minutes after that first commit. The snapshot used for this article was 39 hours 34 minutes into the recorded Git history. By then, 59 of the 75 commits on main came after the domain setup. Those are elapsed intervals between Git milestones. The local build, launch, and subsequent rounds of refinement each had their own work.

The public app and its data

The public app runs on Node.js 24 LTS and Express. It serves permanent event pages as HTML and uses one catalogue for the list, calendar, and Leaflet map. Visitors can pick a departure point and compare estimated road distances and driving times. The calendar keeps past editions in their actual years and includes entries with documented dates. Browse the catalogue

Calendar view in Câmpenește showing documented event editions and the year and month controls

The data model separates an event series, one edition of that event, and the sources that support what we know. An old edition can tell you that a fair exists. A current source is what lets it appear on this year’s calendar. The curated catalogue starts as JSON in Git. The running app stores observations and cached routes in persistent JSON. It replaces state files atomically on a single instance.

The admin became an editorial workspace

The first dashboard put catalogue coverage, worker health, and visitor suggestions in one place. It grew into an authenticated workspace with tabs for suggestions, research, leads, sources, and statistics, plus a weekly editorial view. I can compare a candidate date with the existing edition, open the source, and decide whether it belongs in the public catalogue. The research worker can surface changes or conflicting evidence, and an optional Azure Foundry review can help triage leads. The catalogue update is a separate editorial decision.

I added password-based sessions using a scrypt hash, secure session cookies in production, and same-origin and CSRF checks for administrative changes. Catalogue editing and backup export stay in the local app. The Azure worker runs a bounded batch on an hourly Logic Apps schedule, and the dashboard can show its health separately from the public site’s health.

Câmpenește admin overview with its catalogue metrics and editorial navigation

Admin screenshot from a local copy loaded with the public seed catalogue. It shows the interface using demonstration data.

A few technical facts from the deployed snapshot

Item At 613c86d, released as v0.29.0-beta.1
Application code 19,972 physical lines across 77 tracked JS, HTML, and CSS files in the app, public UI, and admin.
Tests 9,425 physical lines in 57 tracked test and test-helper files. GitLab pipeline #2215 reported 281 tests passed.
Catalogue 130 series in the tracked seed catalogue. The public catalogue showed coverage across 41 counties when I captured it.
Hosting One Linux Azure App Service Basic B1 instance with persistent storage, and an hourly Azure Logic Apps worker. The preview started on the Free tier.
Delivery GitLab validates the code and packages a release. A protected production child pipeline deploys the ZIP to Azure, checks the live HTTPS version and commit, and then publishes the version tag and release.

The line counts include blank lines and comments. They exclude dependency trees, catalogue data, documentation, and assets. The public health endpoint reports the deployed version and commit. Câmpenește health endpoint

Project documentation

Câmpenește’s design notes, research notes, and release notes are Markdown in Git. Its catalogue and runtime state are JSON, and Express runs the interactive app.

The part I’d keep if I rebuilt it is the distinction between a known series and a confirmed edition. The map helps people find a place. The evidence helps them decide whether it’s worth getting in the car. Visit Câmpenește