Lege Entwicklungsleitfaden und Go-Gerueste an

This commit is contained in:
Jesko Anschütz 2026-03-22 13:42:00 +01:00
parent 7befa61805
commit 6a65505304
17 changed files with 438 additions and 0 deletions

179
DEVELOPMENT.md Normal file
View file

@ -0,0 +1,179 @@
# Info-Board Neu - Entwicklung
## Ziel
Dieses Dokument soll den Einstieg auf einem anderen Entwicklungsrechner moeglichst reibungsfrei machen.
Es beschreibt:
- minimale Voraussetzungen
- wichtige Verzeichnisse
- Build- und Run-Kommandos
- aktuelle Annahmen fuer den lokalen Entwicklungsbetrieb
## Repository
- Remote: `git.az-it.net:az/morz-infoboard.git`
- Standard-Branch: `main`
Projektwurzel:
- `/srv/docker/info-board-neu`
## Wichtige Verzeichnisse
- `docs/` fuer Architektur- und Fachkonzepte
- `server/backend/` fuer das zentrale Go-Backend
- `player/agent/` fuer den Go-basierten Player-Agent
- `player/ui/` spaeter fuer die lokale Player-Oberflaeche
- `ansible/` spaeter fuer Deployment und Provisionierung
- `compose/` spaeter fuer den zentralen Server-Stack
## Aktueller Entwicklungsstand
Bereits vorhanden:
- fachliche Architektur- und Betriebskonzepte
- relationaler Schema-Entwurf in `docs/SCHEMA.md`
- erstes Go-Geruest fuer `server/backend`
- erstes Go-Geruest fuer `player/agent`
Noch nicht vorhanden:
- produktive API-Endpunkte
- Datenbankanbindung
- MQTT-Anbindung
- Player-Sync
- Player-UI
- Compose-Stack fuer lokale Serverdienste
## Voraussetzungen auf dem Entwicklungsrechner
Mindestens empfohlen:
- `git`
- `go` in Version `1.24.x`
- `make`
Spaeter zusaetzlich sinnvoll:
- `docker` und `docker compose`
- `postgresql-client`
- `mosquitto-clients`
## Schnellstart
Repository klonen:
```bash
git clone git.az-it.net:az/morz-infoboard.git
cd morz-infoboard
```
Dokumentationsbasis lesen:
1. `README.md`
2. `PLAN.md`
3. `TECH-STACK.md`
4. `docs/SCHEMA.md`
5. `docs/OFFENE-ARCHITEKTURFRAGEN.md`
## Build-Kommandos
### Backend bauen
```bash
cd server/backend
go build ./...
```
### Agent bauen
```bash
cd player/agent
go build ./...
```
### Alternativ ueber Makefile
```bash
make build
```
## Lokaler Start
### Backend lokal starten
```bash
cd server/backend
go run ./cmd/api
```
Standard:
- HTTP-Adresse: `:8080`
- Health-Endpunkt: `GET /healthz`
- Basis-Endpunkt: `GET /api/v1`
Konfigurierbar ueber:
- `MORZ_INFOBOARD_HTTP_ADDR`
Beispiel:
```bash
MORZ_INFOBOARD_HTTP_ADDR=:18080 go run ./cmd/api
```
### Agent lokal starten
```bash
cd player/agent
go run ./cmd/agent
```
Standardwerte:
- `MORZ_INFOBOARD_SCREEN_ID=unset-screen`
- `MORZ_INFOBOARD_SERVER_URL=http://127.0.0.1:8080`
- `MORZ_INFOBOARD_MQTT_BROKER=tcp://127.0.0.1:1883`
Beispiel:
```bash
MORZ_INFOBOARD_SCREEN_ID=info01-dev \
MORZ_INFOBOARD_SERVER_URL=http://127.0.0.1:8080 \
MORZ_INFOBOARD_MQTT_BROKER=tcp://127.0.0.1:1883 \
go run ./cmd/agent
```
## Aktuelle Architekturentscheidungen mit direkter Auswirkung auf Entwicklung
- `message_wall` wird serverseitig in konkrete Screen-Szenen aufgeloest
- Kampagnengruppen werden serverseitig in konkrete Screen-Assignments expandiert
- `playlist_items` haben im finalen Implementierungsschema keinen direkten `screen_id`-Fremdschluessel
- Provisionierung wird worker-/jumphost-faehig geplant
- API-Fehler sollen einen einheitlichen Fehlerumschlag nutzen
## Empfohlene naechste Implementierungsschritte
1. Backend: einheitliches Fehlerformat und Routing-Grundstruktur anlegen
2. Backend: Konfigurations- und App-Lifecycle stabilisieren
3. Agent: dateibasierte Konfiguration zusaetzlich zu Env vorbereiten
4. Agent: strukturierte Logs und Health-Modell einziehen
5. Danach erst DB-, MQTT- und API-Funktionalitaet ausbauen
## Arbeitsweise
Empfohlen:
- kleine, klar umrissene Commits
- zuerst Konzepte anpassen, dann Code
- Schema und API-Vertrag synchron halten
- neue Fachentscheidungen immer in `docs/` dokumentieren
## Hinweise fuer einen zweiten Entwicklungsrechner
- vor Arbeitsbeginn `git pull --rebase` oder gleichwertig den aktuellen Stand holen
- bei paralleler Arbeit zuerst in den Dokumenten pruefen, ob neue Architekturentscheidungen getroffen wurden
- falls lokale Tools abweichen, mindestens `go version` und `make --version` pruefen

22
Makefile Normal file
View file

@ -0,0 +1,22 @@
BACKEND_DIR=server/backend
AGENT_DIR=player/agent
.PHONY: build build-backend build-agent run-backend run-agent fmt
build: build-backend build-agent
build-backend:
cd $(BACKEND_DIR) && go build ./...
build-agent:
cd $(AGENT_DIR) && go build ./...
run-backend:
cd $(BACKEND_DIR) && go run ./cmd/api
run-agent:
cd $(AGENT_DIR) && go run ./cmd/agent
fmt:
cd $(BACKEND_DIR) && go fmt ./...
cd $(AGENT_DIR) && go fmt ./...

View file

@ -16,6 +16,7 @@ Die Trennung von `/srv/docker/infoboard-netboot` ist sinnvoll, damit:
- Schema-Entwurf: `docs/SCHEMA.md`
- API- und MQTT-Vertrag: `API-MQTT-VERTRAG.md`
- Technologieentscheidungen: `TECH-STACK.md`
- Entwicklungsleitfaden: `DEVELOPMENT.md`
- Template-/Kampagnenkonzept: `docs/TEMPLATE-KONZEPT.md`
- Provisionierungskonzept: `docs/PROVISIONIERUNGSKONZEPT.md`
- Player-Konzept: `docs/PLAYER-KONZEPT.md`

View file

@ -6,3 +6,9 @@ Hier liegen spaeter Rollen, Playbooks und Inventories fuer:
- Updates bestehender Screens
- Server-Deployment
- Display-spezifische Konfigurationen
Naechster geplanter Ausbau:
- Rolle `signage_provision`
- Rolle `signage_player`
- Beispiel-Inventories fuer Wand- und Einzelanzeigen

View file

@ -9,3 +9,7 @@ Geplant:
- `systemd/` fuer Units
- `config/` fuer Beispielkonfigurationen
- `scripts/` fuer lokale Hilfsskripte
Aktuell vorhanden:
- `agent/` mit erstem Go-Geruest

16
player/agent/README.md Normal file
View file

@ -0,0 +1,16 @@
# Agent
Dieses Verzeichnis enthaelt das erste Geruest fuer den `player-agent`.
Ziel fuer die erste Ausbaustufe:
- lokaler Dienst in Go
- Konfiguration laden
- Startfaehigkeit und klares Logging
- vorbereitete Struktur fuer Sync, MQTT, Cache und Kommandos
Geplante Unterstruktur:
- `cmd/agent/` fuer den Startpunkt
- `internal/app/` fuer Initialisierung und Laufzeit
- `internal/config/` fuer Konfiguration

View file

@ -0,0 +1,23 @@
package main
import (
"log"
"os"
"git.az-it.net/az/morz-infoboard/player/agent/internal/app"
)
func main() {
logger := log.New(os.Stdout, "agent ", log.LstdFlags|log.LUTC)
application, err := app.New()
if err != nil {
logger.Fatalf("init agent: %v", err)
}
logger.Printf("starting agent for screen %s", application.Config.ScreenID)
if err := application.Run(); err != nil {
logger.Fatalf("run agent: %v", err)
}
}

3
player/agent/go.mod Normal file
View file

@ -0,0 +1,3 @@
module git.az-it.net/az/morz-infoboard/player/agent
go 1.24.0

View file

@ -0,0 +1,28 @@
package app
import (
"fmt"
"time"
"git.az-it.net/az/morz-infoboard/player/agent/internal/config"
)
type App struct {
Config config.Config
}
func New() (*App, error) {
cfg := config.Load()
if cfg.ScreenID == "" {
return nil, fmt.Errorf("screen id is required")
}
return &App{Config: cfg}, nil
}
func (a *App) Run() error {
for {
time.Sleep(30 * time.Second)
}
}

View file

@ -0,0 +1,26 @@
package config
import "os"
type Config struct {
ScreenID string
ServerBaseURL string
MQTTBroker string
}
func Load() Config {
return Config{
ScreenID: getenv("MORZ_INFOBOARD_SCREEN_ID", "unset-screen"),
ServerBaseURL: getenv("MORZ_INFOBOARD_SERVER_URL", "http://127.0.0.1:8080"),
MQTTBroker: getenv("MORZ_INFOBOARD_MQTT_BROKER", "tcp://127.0.0.1:1883"),
}
}
func getenv(key, fallback string) string {
value := os.Getenv(key)
if value == "" {
return fallback
}
return value
}

View file

@ -8,3 +8,7 @@ Geplant:
- `admin-ui/` fuer die Admin-Oberflaeche
- `tenant-ui/` fuer die Firmenoberflaeche
- `worker/` fuer Provisionierungs- und Hintergrundjobs
Aktuell vorhanden:
- `backend/` mit erstem Go-Geruest

16
server/backend/README.md Normal file
View file

@ -0,0 +1,16 @@
# Backend
Dieses Verzeichnis enthaelt das erste Geruest fuer das zentrale Backend.
Ziel fuer die erste Ausbaustufe:
- HTTP-API in Go
- Health-Endpunkt
- saubere Projektstruktur fuer spaetere API-, Worker- und Datenbankmodule
Geplante Unterstruktur:
- `cmd/api/` fuer den API-Startpunkt
- `internal/app/` fuer App-Initialisierung
- `internal/httpapi/` fuer HTTP-Routing und Handler
- `internal/config/` fuer Konfiguration

View file

@ -0,0 +1,23 @@
package main
import (
"log"
"os"
"git.az-it.net/az/morz-infoboard/server/backend/internal/app"
)
func main() {
logger := log.New(os.Stdout, "backend ", log.LstdFlags|log.LUTC)
application, err := app.New()
if err != nil {
logger.Fatalf("init app: %v", err)
}
logger.Printf("starting backend on %s", application.Config.HTTPAddress)
if err := application.Run(); err != nil {
logger.Fatalf("run backend: %v", err)
}
}

3
server/backend/go.mod Normal file
View file

@ -0,0 +1,3 @@
module git.az-it.net/az/morz-infoboard/server/backend
go 1.24.0

View file

@ -0,0 +1,29 @@
package app
import (
"net/http"
"git.az-it.net/az/morz-infoboard/server/backend/internal/config"
"git.az-it.net/az/morz-infoboard/server/backend/internal/httpapi"
)
type App struct {
Config config.Config
server *http.Server
}
func New() (*App, error) {
cfg := config.Load()
return &App{
Config: cfg,
server: &http.Server{
Addr: cfg.HTTPAddress,
Handler: httpapi.NewRouter(),
},
}, nil
}
func (a *App) Run() error {
return a.server.ListenAndServe()
}

View file

@ -0,0 +1,22 @@
package config
import "os"
type Config struct {
HTTPAddress string
}
func Load() Config {
return Config{
HTTPAddress: getenv("MORZ_INFOBOARD_HTTP_ADDR", ":8080"),
}
}
func getenv(key, fallback string) string {
value := os.Getenv(key)
if value == "" {
return fallback
}
return value
}

View file

@ -0,0 +1,33 @@
package httpapi
import (
"encoding/json"
"net/http"
)
func NewRouter() http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("GET /healthz", func(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, map[string]string{
"status": "ok",
"service": "morz-infoboard-backend",
})
})
mux.HandleFunc("GET /api/v1", func(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, map[string]string{
"name": "morz-infoboard-backend",
"version": "dev",
})
})
return mux
}
func writeJSON(w http.ResponseWriter, status int, payload any) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
_ = json.NewEncoder(w).Encode(payload)
}