A live event can look effortless from the audience. Behind the scenes, it can be a maze of spreadsheets, chat groups, forms, uploaded files, scoring sheets, and last-minute decisions.

ArtFlow started from that gap. Its first real-world context was organizing university arts events, including a singing competition and stage performances. The goal was never just another voting page or a prettier registration form. It was to make the entire event workflow consistent, recoverable, and explainable—especially when things change minutes before going live.

I'm sharing the project while its v2 architecture is actively evolving, both to explain the engineering decisions and to hear from people who have built or run similar systems.

The problem isn't one missing tool

For a competition, you might already have:

  • a form for registration;
  • a spreadsheet for contestants and scores;
  • chat messages for missing materials and urgent updates;
  • a separate voting link for the audience;
  • manually assembled results and archives.

Each part works on its own. The failure happens between them. Is the lineup finalized? Has the judging round been locked? Can a corrected score overwrite an already confirmed result? Is a rehearsal vote accidentally mixed into the real tally? What should staff see when a connection drops?

These aren't just UI questions. They are questions about authority, state, and recovery.

From a competition app to a composable EventOps platform

ArtFlow v1 was a Django-based system built around an actual event workflow. After that experience, I started rebuilding the product as ArtFlow v2 / ArtFlow-Plus: a composable operations platform for competitions and complex events.

The intended user-facing product has four surfaces:

  • Studio — define the event, its rules, forms, roles, and workflows.
  • Ops — prepare the real people, materials, reviews, and operational tasks.
  • Live — operate the event, control scoring/voting, and handle on-site changes.
  • Portal — give participants, judges, staff, and audiences appropriate views and actions.

These aren't four unrelated applications. They share an Activity Engine and reusable capabilities such as registration, materials, competition, voting, ticketing, publishing, grouping, tasks, and archive.

Different event shapes are composed from capabilities and default definitions. The repository currently includes packs for singer competitions, stage-show collection, review awards, and voting-oriented workflows. Tests cover distinct event journeys on the same core instead of duplicating a separate engine for each format.

Correctness before a flashy live dashboard

The most important engineering choices are about preserving meaning under pressure:

1. A single authoritative write path. Commands produce a receipt, audit information, domain facts, and an outbox record within one transaction. Retries should be explainable, not silently applied twice.

2. Explicit finality. A configured release is immutable. Confirmed results have a controlled publishing path; corrections shouldn't quietly rewrite history.

3. Rehearsal and formal execution are isolated. Event mode affects facts, votes, rankings, events, and projections—not just a visual badge in the UI.

4. Realtime is a convenience, not the source of truth. A WebSocket can signal that something changed. HTTP remains the recovery authority if the realtime connection disappears.

5. Capabilities have boundaries. One capability should not reach into another capability's tables and reinterpret its business facts. Cross-capability behavior goes through explicit contracts.

This approach is more work than creating an impressive demo page, but it targets the failures that matter during an actual event.

Under the hood

The current v2 development baseline uses:

  • TypeScript 7 / Node.js 24
  • Fastify 5 with TypeBox contracts and OpenAPI
  • React 19 for the web surfaces
  • PostgreSQL 18 with Kysely
  • a transactional outbox and projection relay
  • a single realtime core with WebSocket invalidation signals and HTTP recovery

The repository also documents architectural decisions, invariants, test gates, event-shape validation, and a roadmap. Those documents are part of how the system is reviewed, not just an afterthought.

What is available today—and what isn't

The public repository's main branch now tracks v2, the only active development line. The historical Django 1.x implementation is preserved at tag v1.0.2.

v2 has implemented and tested many core journeys. It is still being developed, and the repository explicitly tracks remaining gaps—including some public content/program surfaces, spreadsheet/document exports, and more advanced competition formats. I'm not presenting it as a finished, universally deployable SaaS product or claiming that every planned surface is complete.

One licensing detail matters: ArtFlow is source-available, not OSI-licensed open source. The project offers PolyForm Noncommercial and PolyForm Internal Use terms, with separate written licensing for uses outside those grants. Please check the actual license before reuse or deployment.

I'd love feedback from event operators and builders

If you've helped run competitions, conferences, campus events, festivals, or live productions: which failure modes did your tools handle badly?

I'm particularly interested in:

  • judging and result correction under time pressure;
  • last-minute changes to participants or schedules;
  • concurrent staff actions and permission boundaries;
  • unreliable venue networks and recovery behavior;
  • keeping rehearsals from contaminating formal records.

Project and technical documentation: ArtFlow on GitHub

Architecture and product scope: ArtFlow GOAL

Thanks for reading. I'd be happy to compare notes with anyone solving similar operational problems.