Files
marktvogt.de/README.md
vikingowl af7b6232e0 docs(readme): correct cache backend naming and bump status date
Architecture table said Redis, but local dev uses Valkey and prod uses
Dragonfly. Both speak the Redis protocol but neither is Redis.
2026-04-29 00:44:53 +02:00

5.8 KiB

Marktvogt

The central portal for medieval markets ("Mittelaltermaerkte") in the DACH region.

Marktvogt connects visitors, merchants, artists, camp groups, and organizers on one platform — replacing the patchwork of Facebook groups, phone calls, mailing lists, and scattered websites that the scene currently runs on.

The name comes from the historical Marktvogt — the keeper of order at medieval markets. Same job, different century.


The Problem

The medieval-market scene in the DACH region is large (hundreds of markets per year) but digitally fragmented:

  • Finding markets: Facebook groups, mittelalterkalender.info, private sites
  • Bookings (merchants, artists, camps): phone, e-mail, Facebook Messenger
  • Camp groups: organize almost exclusively on Facebook
  • Tickets: usually box-office-only or one-off organizer sites

There is no single portal that brings all participants together. Marktvogt is that portal.

The Solution

A two-sided marketplace:

  • Supply side — organizers list markets, open plots, programs, tickets
  • Demand side — visitors discover markets and buy tickets; merchants, artists, and camp groups apply for spots

Network effects: organizers attract applicants, applicants make the platform indispensable for organizers, and visitors follow the content.

Roles

Six roles, with the Veranstalter (organizer) as the central actor:

Role Description
Gast Anonymous visitor — browse markets, no account
User Registered visitor — tickets, favorites, profile
Haendler Merchant group applying for plots
Kuenstler Artist group applying for performance slots
Lager Reenactment camp group applying for camp space
Veranstalter Organizer — creates markets, reviews applications, sells tickets

All applicants (Haendler / Kuenstler / Lager) operate as groups. A solo merchant is just a one-person group. Mitarbeiter (staff) is a sub-role under Veranstalter with granular permissions.


Architecture

Monorepo. Components are plain directories, not git submodules.

Layer Stack
Backend Go REST API + WebSocket; PostgreSQL (PostGIS), Valkey/Dragonfly, S3
Web SvelteKit + Tailwind 4, SSR for SEO, runs on Bun
Mobile Flutter (Android + iOS)
Auth Custom (Go), e-mail+password / magic link / OAuth / 2FA
Payments Stripe Connect
LLM Google Gemini (gemini-2.5-flash-lite) for enrichment
CI/CD Woodpecker (ci.somegit.dev) — .gitlab-ci.yml retained as fallback
Hosting Kubernetes (itsh.dev), Helm chart at helm/marktvogt/
Monitoring Prometheus, Loki, Grafana, Sentry

Repo Layout

backend/    Go REST API + WebSocket chat
web/        SvelteKit frontend (SSR, Bun runtime)
app/        Flutter mobile app
helm/       Monolithic Helm chart (backend + web + Postgres + Dragonfly)
planning/   Vision, roadmap, MVP scope, feature specs (German, ASCII-only)
scripts/    Out-of-band tooling (e.g. K8s secret sync)
.woodpecker/ CI pipelines for somegit.dev

The admin dashboard lives in its own repo and will be added later.


Getting Started

The repo is driven by a Justfile. Run just for the full list.

# One-time setup: pre-commit hooks, web deps, golangci-lint
just hooks-install

# Backend
just backend-dev        # Postgres + Valkey via docker compose
just backend-run        # go run ./cmd/api
just backend-test
just backend-lint

# Web
just web-dev            # SvelteKit dev server
just web-check          # svelte-check (types)
just web-lint

# Everything
just lint
just test
just fmt

For component-specific details, see backend/README.md, web/README.md, and app/README.md.


Deployment

Single Helm release marktvogt in namespace tenant-2, deployed from helm/marktvogt/ (monolithic chart covering backend, web, Postgres, and Dragonfly). CI runs:

helm upgrade marktvogt --reuse-values \
  --set-string backend.image.tag=<sha> \
  --set-string web.image.tag=<sha>

--set-string is mandatory — all-digit short SHAs get float-coerced into scientific notation otherwise, which then fails K8s label validation.

K8s Secrets are pre-created out-of-band by scripts/k8s-secrets-sync.sh reading from .env.helm (gitignored). CI never touches secret values.

The container registry (registry.itsh.dev/vikingowl/marktvogt.de/{backend,web}) is Zot-backed and requires attestations on every pushed image. The Woodpecker pipelines use woodpeckerci/plugin-docker-buildx, which handles this by default.


Status

Active development as of 2026-04-29. backend/, web/, and app/ all contain working code (Go API scaffolding + auth, SvelteKit pages, Flutter skeleton).

  • Current phase scope: planning/15-mvp.md
  • Phased feature plan: planning/17-roadmap.md
  • Vision: planning/00-vision.md

Planning docs are in German and use ASCII only (no umlauts) for cross-platform compatibility.


Conventions

  • API design: REST for CRUD, WebSocket for real-time chat
  • Auth: custom-built using Go libraries — no external auth provider
  • Offline capability: required for QR-ticket validation and venue maps
  • Commits: conventional commit messages
  • Source of truth for product: planning/ — read it before adding features