First steps after it’s running

So the server is up at {{ dev_url }} and you can log in. Here’s how to actually do development on Midsummer — where things live, how to make a change, and the gates you must keep green.

Where the code lives

midsummer/           # Django project: settings, root URLconf, ASGI/WSGI, middleware
midsummer/common/    # Cross-app shared code (ui.py menus, permissions, triggers, SPA shell)
accounts/  event/  register/  vendors/  staff/  schedule/  shop/  tenant/  kioskos/
                     # The tenant + shared Django apps (see Systems)
ui/                  # MAIN event SPA — Angular 21 + PrimeNG 21 (+ Kendo scheduler)
tenantui/            # Tenant-management SPA — Angular 19 + PrimeNG 19
front/               # Public-schema landing pages (serves built SPA assets via WhiteNoise)
documentation/       # Authoritative deep-dive docs (mirrored from the memory bank)
guides/              # Operational runbooks (tenants, domains, metrics)
scripts/             # Standalone helper scripts

Each backend app follows the Django convention: models.py, views.py, urls.py, serializers.py, admin.py, tests.py, migrations/, plus (where needed) services/, consumers.py, routing.py, tasks.py.

The canonical build + run command

When in doubt, this single invocation rebuilds both frontends and starts the server (it is also what AGENTS.md documents as authoritative):

export MIDSUMMER_PROD=false && ./render-ui-elements.sh && ./render-tenant-ui-elements.sh && ./entrypoint.sh
  • MIDSUMMER_PROD=false keeps you in dev mode. Always leave this false locally.

  • render-ui-elements.sh builds the ui/ SPA into Django static files.

  • render-tenant-ui-elements.sh builds the tenantui/ SPA likewise.

  • entrypoint.sh runs collectstatic, re-applies shared migrations, then launches Hypercorn on {{ dev_port }}.

You only need to re-run the render scripts when frontend code changes.

Making a backend change

  1. Edit the relevant app (register/, vendors/, …). REST endpoints live in each app’s urls.py, mounted under /app/<module>/.

  2. If you change a model, generate and apply a schema migration:

    python manage.py makemigrations <app>
    python manage.py migrate_schemas   # note: migrate_schemas, not migrate (django-tenants)
    
  3. Keep the gates green (see Build & test gates below).

See the Concepts section for the patterns you’ll be working with: the JSON form-builder, the permission model, audit logging, etc.

Making a frontend change

There are two Angular projects with different versions — don’t assume they share code:

Project

Framework

Purpose

ui/

Angular 21 + PrimeNG 21 (+ Kendo)

The event app (register, vendors, schedule, staff, shop)

tenantui/

Angular 19 + PrimeNG 19

Tenant/org admin (events, settings, domains, memberships)

After editing, rebuild the affected SPA into Django static files:

./render-ui-elements.sh            # after editing ui/
./render-tenant-ui-elements.sh     # after editing tenantui/

For a faster inner loop while iterating on a single SPA, you can run its dev server directly, but the Django-served app expects the built static assets, so a final render-* is required before testing inside the running Midsummer app.

Build & test gates

These are the checks the project relies on. Run them before considering a change done.

# Django system check (should be 0 errors; ~19 pre-existing warnings are normal)
python manage.py check

# Migration drift check for the app you touched (should report "no changes")
python manage.py makemigrations <app> --check

# Frontend type-check (exit 0 = pass), for the SPA you edited
cd ui && npx ngc --noEmit -p tsconfig.app.json
# (or) full build
cd ui && npx ng build

A note on the test database

DB-backed tests (python manage.py test) are not runnable in the standard dev environment — the remote Postgres lacks the test_midsummerpool test database (a pre-existing constraint). Pure-helper unit tests (no DB) do run, and are preferred for new business logic. When you can’t run a DB test locally, lean on manage.py check, the migration-drift check, and the frontend type-check above.

Multi-tenancy in practice (local)

Midsummer is schema-isolated per tenant. Locally you typically have a defaultdev tenant with one event. Two things to remember:

  • Migrations that touch shared tables run with migrate_schemas --shared.

  • To operate on tenant data from a shell/management command, run it inside the owning tenant’s schema (the management tooling handles context for the configured tenant). The registration metrics export command, for example, must run inside the owning tenant’s schema so it writes data to the correct path.

Read the multi-tenancy concept page for the full model.

Where to go next