Lege Entwicklungsleitfaden und Go-Gerueste an
This commit is contained in:
parent
7befa61805
commit
6a65505304
17 changed files with 438 additions and 0 deletions
179
DEVELOPMENT.md
Normal file
179
DEVELOPMENT.md
Normal 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
22
Makefile
Normal 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 ./...
|
||||||
|
|
@ -16,6 +16,7 @@ Die Trennung von `/srv/docker/infoboard-netboot` ist sinnvoll, damit:
|
||||||
- Schema-Entwurf: `docs/SCHEMA.md`
|
- Schema-Entwurf: `docs/SCHEMA.md`
|
||||||
- API- und MQTT-Vertrag: `API-MQTT-VERTRAG.md`
|
- API- und MQTT-Vertrag: `API-MQTT-VERTRAG.md`
|
||||||
- Technologieentscheidungen: `TECH-STACK.md`
|
- Technologieentscheidungen: `TECH-STACK.md`
|
||||||
|
- Entwicklungsleitfaden: `DEVELOPMENT.md`
|
||||||
- Template-/Kampagnenkonzept: `docs/TEMPLATE-KONZEPT.md`
|
- Template-/Kampagnenkonzept: `docs/TEMPLATE-KONZEPT.md`
|
||||||
- Provisionierungskonzept: `docs/PROVISIONIERUNGSKONZEPT.md`
|
- Provisionierungskonzept: `docs/PROVISIONIERUNGSKONZEPT.md`
|
||||||
- Player-Konzept: `docs/PLAYER-KONZEPT.md`
|
- Player-Konzept: `docs/PLAYER-KONZEPT.md`
|
||||||
|
|
|
||||||
|
|
@ -6,3 +6,9 @@ Hier liegen spaeter Rollen, Playbooks und Inventories fuer:
|
||||||
- Updates bestehender Screens
|
- Updates bestehender Screens
|
||||||
- Server-Deployment
|
- Server-Deployment
|
||||||
- Display-spezifische Konfigurationen
|
- Display-spezifische Konfigurationen
|
||||||
|
|
||||||
|
Naechster geplanter Ausbau:
|
||||||
|
|
||||||
|
- Rolle `signage_provision`
|
||||||
|
- Rolle `signage_player`
|
||||||
|
- Beispiel-Inventories fuer Wand- und Einzelanzeigen
|
||||||
|
|
|
||||||
|
|
@ -9,3 +9,7 @@ Geplant:
|
||||||
- `systemd/` fuer Units
|
- `systemd/` fuer Units
|
||||||
- `config/` fuer Beispielkonfigurationen
|
- `config/` fuer Beispielkonfigurationen
|
||||||
- `scripts/` fuer lokale Hilfsskripte
|
- `scripts/` fuer lokale Hilfsskripte
|
||||||
|
|
||||||
|
Aktuell vorhanden:
|
||||||
|
|
||||||
|
- `agent/` mit erstem Go-Geruest
|
||||||
|
|
|
||||||
16
player/agent/README.md
Normal file
16
player/agent/README.md
Normal 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
|
||||||
23
player/agent/cmd/agent/main.go
Normal file
23
player/agent/cmd/agent/main.go
Normal 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
3
player/agent/go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module git.az-it.net/az/morz-infoboard/player/agent
|
||||||
|
|
||||||
|
go 1.24.0
|
||||||
28
player/agent/internal/app/app.go
Normal file
28
player/agent/internal/app/app.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
26
player/agent/internal/config/config.go
Normal file
26
player/agent/internal/config/config.go
Normal 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
|
||||||
|
}
|
||||||
|
|
@ -8,3 +8,7 @@ Geplant:
|
||||||
- `admin-ui/` fuer die Admin-Oberflaeche
|
- `admin-ui/` fuer die Admin-Oberflaeche
|
||||||
- `tenant-ui/` fuer die Firmenoberflaeche
|
- `tenant-ui/` fuer die Firmenoberflaeche
|
||||||
- `worker/` fuer Provisionierungs- und Hintergrundjobs
|
- `worker/` fuer Provisionierungs- und Hintergrundjobs
|
||||||
|
|
||||||
|
Aktuell vorhanden:
|
||||||
|
|
||||||
|
- `backend/` mit erstem Go-Geruest
|
||||||
|
|
|
||||||
16
server/backend/README.md
Normal file
16
server/backend/README.md
Normal 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
|
||||||
23
server/backend/cmd/api/main.go
Normal file
23
server/backend/cmd/api/main.go
Normal 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
3
server/backend/go.mod
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
module git.az-it.net/az/morz-infoboard/server/backend
|
||||||
|
|
||||||
|
go 1.24.0
|
||||||
29
server/backend/internal/app/app.go
Normal file
29
server/backend/internal/app/app.go
Normal 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()
|
||||||
|
}
|
||||||
22
server/backend/internal/config/config.go
Normal file
22
server/backend/internal/config/config.go
Normal 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
|
||||||
|
}
|
||||||
33
server/backend/internal/httpapi/router.go
Normal file
33
server/backend/internal/httpapi/router.go
Normal 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)
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue