mivanchenko 2515c8835b
Test backoffice (smb-crm) / test (push) Successful in 1m37s
Fix: public booking page mixed both Filialen's barbers before any was picked
applyLocationFilter()'s "!selectedLocation" check was meant to mean "only
one Filiale exists, nothing to filter" but also fired in the multi-Filiale
case before the customer had clicked one yet, showing every barber from
every location mixed together in Mitarbeiter. Now keyed on LOCATIONS.length
instead, so with 2+ Filialen nothing shows until one is actually selected.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 03:07:11 +02:00

smb-online — "Get Your Small Business Online"

A productized service that gets local small businesses online: landing page + online booking + lead capture + small automations. Built to be thoroughly tracked and logged — every client, lead, booking and invoice lives in a Postgres CRM (sole source of truth), driven by n8n on the homelab.

Full documentation (architecture, data model, every component): Documentation.md.

Delivery tiers — an internal signal, not a fixed product

tier (A = free Google stack, B = self-hosted/privacy) started as two fixed product bundles but is being decoupled from the public offering (see TODO.md): which stack a client actually gets is a decision made with the client, case-by-case, and recorded on their clients row (tier, stack_notes) — it's no longer baked into the demos. In practice, booking has already converged on one shared self-hosted service (Easy!Appointments, see deploy/booking/) used for every client regardless of tier.

Repository layout

Documentation.md           Full architecture / component reference — start here for "how it works"
backoffice/                 Postgres CRM + Flask API + operator dashboard (the source of truth)
deploy/
  clients/                   One isolated nginx stack per signed client + new-client.sh scaffolder
  booking/                    Shared Easy!Appointments booking service (all clients)
  smb-demos/                  Public demo/preview hosting (Apache)
  backup/                      Daily Postgres backup script (cron on the homelab)
n8n/                         Exported n8n workflows (lead-intake, onboarding, booking-sync, renewal-reminder)
playbooks/                   Operator playbooks (outreach, lead-to-customer, tier-a, tier-b)
templates/landing/           Landing-page demos + client preview pages
  demo-tier-a/                  "Schnittpunkt" barbershop demo
  demo-tier-b/                  "PhysioVital" physio practice demo
  demo-pizzeria/                "Bella Napoli" pizzeria demo w/ online ordering
templates/onboarding/        Internal "create client" form → n8n onboarding workflow

View the demos

They are self-contained HTML — open directly:

xdg-open templates/landing/demo-tier-a/index.html    # barbershop
xdg-open templates/landing/demo-tier-b/index.html    # physio practice
xdg-open templates/landing/demo-pizzeria/index.html  # pizzeria / online ordering

Or serve them all with the chooser page:

python3 -m http.server 8080 --directory templates/landing
# → http://localhost:8080/   (links to all three demos)

Lead/callback forms POST live to the n8n lead-intake webhook; booking widgets link to the shared Easy!Appointments instance. Nothing here is stubbed anymore — see Documentation.md §4.5 for the full workflow wiring.

Phases (status)

Tracked against actual repo state — see Documentation.md for what backs each checkmark.

  • Phase 1 — Demo landing pages
  • Phase 2 — Accounts & setup: Google account + workbook, n8n live, Google creds bound, Vaultwarden (clients.vault_ref), domain (wildcard *.mivanchenko.de)
  • Phase 3 — CRM (Postgres-only, no Sheets mirror) + n8n lead-intake & renewal workflows
  • Phase 4 — Demo forms + booking wired live to n8n webhooks (lead-intake, booking-sync)
  • Phase 5 — First real client + reception v1 — onboarding automation and per-client deploy tooling exist and are exercised (deploy/clients/); not verifiable from the repo alone whether a paying client is live
  • Phase 6 — AI receptionist (Claude Haiku 4.5) — not started

Operator is in an Ausbildung as Cloud Engineer at NETWAYS. This offering deliberately stays out of NETWAYS's lane (no managed cloud hosting / monitoring / OpenStack/K8s hosting for clients). Before taking paying clients: (1) check the Ausbildungsvertrag for a Nebentätigkeit clause and get written employer approval if required; (2) Gewerbeanmeldung + Kleinunternehmerregelung (§19 UStG) once revenue starts; (3) confirm with the IHK / a Steuerberater if unsure.

S
Description
No description provided
Readme 860 KiB
Languages
HTML 56.3%
Python 39.7%
PLpgSQL 2%
CSS 1%
JavaScript 0.6%
Other 0.4%