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`
|
||||
- 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`
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
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
|
||||
- `tenant-ui/` fuer die Firmenoberflaeche
|
||||
- `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