Überblick¶
Stand: nach T01, T02, T03, T04, T06, T09, T10, T17, T23 (Projektgerüst, Theme, og-Komponenten, Zeitformate, Datenbank, native Anbindung an die Antenne,
Standort-Kern, Host-API zur Antenne, Onboarding-Screens und Screen Kontakte). Gebaut sind
das App-Gerüst, die Kern-Grundlagen (log.ts, platform.ts, models/), das Theme, die 22 Komponenten in src/app/ui/
(13 Grundkomponenten aus T01, 9 Zustandskomponenten aus T02), die
Daten-Schicht, der Serial-Client mit Antennen-Port und Mock-Gerät, der Entsperr-Schlüssel, die native USB-Serial-Anbindung für Android sowie
die Nachrichten- und Kontaktdienste.
Der Standort-Kern (src/app/core/location/) bestimmt den eigenen Standort und rechnet Entfernung und Richtung.
Die Seiten „Verbinden“ und „Name“ (T09) und der Screen „Kontakte“ (T10) sind gebaut; die übrigen Seiten unter features/ sind
noch leere Stubs. Alles, was noch fehlt, trägt im Diagramm und im
Ordnerbaum den Vermerk „geplant: Txx".
Aufgabenteilung: Die Antenne (Heltec V3) besitzt Identität, Kontaktschlüssel, Verschlüsselung, Zähler und Kontaktliste. Die App ist Oberfläche und Verlaufsspeicher; sie schickt Klartext über die Host-API und hält nur das Entsperr-Geheimnis im Android Keystore.
Schichten¶
flowchart TD
subgraph App["App – src/app"]
Root["app.component.ts<br>ion-app und Router-Ausgang"]
Config["app.config.ts<br>Router und Ionic, Modus md"]
Routes["app.routes.ts<br>13 Routen, lazy geladen"]
end
subgraph Ui["Oberfläche"]
Pages["features/<br>eine Seite pro Ordner<br>Verbinden und Name (T09)<br>Kontakte (T10)"]
Components["ui/<br>og- Komponenten<br>Grundkomponenten (T01)<br>Zustandskomponenten (T02)"]
end
subgraph Core["Kern – src/app/core"]
Basis["log.ts, platform.ts, models/"]
Start["app-start.service.ts<br>(T04)"]
Data["data/<br>Datenbank und Repositories<br>(T04)"]
Antenna["antenna/<br>Serial-Client, Antennen-Port, Mock-Gerät<br>(T23), USB-Transport (T06)"]
Keystore["keystore/<br>Entsperr-Token, X25519<br>(T23), natives Plugin (T06)"]
Crypto["crypto/<br>Hex und Base64<br/>(T03)"]
Format["format/<br>Zeit- und Funkformate<br/>(T03)"]
Messaging["messaging/<br>Nachrichten, Limits, Signal-Level<br/>(T03, T23)"]
Handshake["handshake/<br>Kontakte, Pairing<br>(T23), geplant: T11"]
Backup["backup/<br>geplant: T14"]
Location["location/<br>GPS-Kern, Geo-Funktionen<br>(T17)"]
Groups["groups/<br>geplant: T20"]
end
Root --> Routes
Routes --> Pages
Pages --> Components
Pages --> Basis
Root --> Basis
Basis --> Start
Basis --> Data
Basis --> Antenna
Basis --> Keystore
Basis --> Crypto
Basis --> Format
Basis --> Messaging
Basis --> Handshake
Basis --> Backup
Basis --> Location
Basis --> Groups
Der Vermerk „geplant: Txx" bedeutet: Der Teil ist noch nicht gebaut und wird im genannten Ticket umgesetzt. Knoten ohne diesen Vermerk existieren bereits auf dem aktuellen Branch.
Ordnerstruktur¶
src/
app/
app.component.ts ion-app mit ion-router-outlet
app.config.ts Provider (Router, Ionic)
app.routes.ts Routen
core/
log.ts log.debug/info/warn/error
platform.ts isNative(), STATUS_BAR_COLOR
models/ antenna, contact, device, errors, handshake, message, settings
app-start.service.ts Datenbank, Einstellungen, Antenne starten (T04, T23)
antenna/ Serial-Client, Antennen-Port, Mock-Gerät (T23), USB-Transport (T06)
backup/ geplant: T14
crypto/ Hex, Base64 (T03)
data/ Datenbank und Repositories (T04, T23)
format/ Zeit- und Funkformate (T03)
groups/ geplant: T20
handshake/ Kontakte spiegeln, Pairing (T23), Scanner geplant: T11
keystore/ Entsperr-Token, X25519, Wrap (T23), natives Plugin (T06)
location/ GPS-Kern, Geo-Funktionen (T17)
messaging/ Limits, Signal-Level (T03), Nachrichten, Reaktionen (T23)
settings/ Einstellungen (T04)
features/
chat/ geplant: T12
einstellungen/ geplant: T13, T14
gruppe/ geplant: T20
handshake/ geplant: T11
kontakte/ Screen Kontakte (T10)
name/ Screen Name (T09)
standort/ geplant: T18
verbinden/ Screen Verbinden (T09)
ui/ og-Grundkomponenten (T01), Zustandskomponenten (T02)
environments/ environment.ts, environment.prod.ts
theme/ tokens.scss, typography.scss, global.scss
test-setup.ts WebCrypto für Vitest und jsdom
index.html lang="de", Titel "OffGrid"
main.ts
Schichten im Detail¶
| Schicht | Ort | Aufgabe | Stand |
|---|---|---|---|
| App | src/app/app.*.ts |
Wurzel-Komponente, Provider, Routen | fertig (T00) |
| Oberfläche | src/app/features/, src/app/ui/ |
Screens und wiederverwendbare og--Komponenten |
Grundkomponenten (T01), Zustandskomponenten (T02), Seiten „Verbinden“ und „Name“ (T09), Screen „Kontakte“ (T10) |
| Kern | src/app/core/ |
Services ohne Oberfläche: Daten, Antenne, Entsperr-Schlüssel, Messaging, Standort | Grundgerüst (T00), Formate (T03), Daten (T04), Antenne und Nachrichten (T23), native Plugins (T06), Standort-Kern (T17) |
| Typen | src/app/core/models/ |
Kontakt, Nachricht, Antenne, Gerät (Host-API), Handshake-Fehler, Settings, Fehlercodes | fertig (T00, T23) |
| Theme | src/theme/ |
Design-Tokens, Schriften, globales Styling | fertig (T00) |
Plattform-Weiche¶
src/app/core/platform.ts liefert isNative() über Capacitor.isNativePlatform():
- Im Browser (
npm start):isNative()istfalse. Es gibt kein Android und keine Antenne. - Auf Android:
isNative()isttrue. Statusleiste und Splash-Screen setzt der App-Start.
Die Weiche liegt in app.config.ts auf Provider-Ebene und betrifft nur die Leitung zur Antenne, den Entsperr-Schlüssel und die Daten:
| Token | Browser | Android |
|---|---|---|
SerialTransport |
MockSerialTransport (simuliertes Gerät) |
UsbSerialTransport (T06, natives USB-Plugin) |
KeystoreService |
BrowserKeystoreService (Schlüssel im Arbeitsspeicher) |
AndroidKeystoreService (T06, natives Keystore-Plugin) |
DatabaseService und Repositories |
Memory-Implementierungen | SQLite-Implementierungen |
AntennaPort, SerialClient, MessagingService und HandshakeService sind für beide Plattformen dieselben Klassen. Auf Android verbindet sich die
App nach einem resume erneut, wenn die Antenne disconnected ist (src/app/app.config.ts). Zusätzlich gilt: Ist
localStorage.getItem('og.mock') === '1', laufen auch auf Android das simulierte Gerät und der Arbeitsspeicher-Schlüssel (Vorführen ohne
Hardware). Das Einstellen und Zurücksetzen passiert nur über die Entwickler-Konsole, es gibt dafür keine Oberfläche.
Auch der Standort hat eine Weiche: Im Browser und im Mock gibt es keinen echten GPS, dort liefert LocationService nach 600 ms den
Demo-Fix aus Luzern. Nur nativ fragt der Dienst den GPS und die Berechtigung ab (Details in Standort).
Konventionen¶
- Nur Standalone-Komponenten,
ChangeDetectionStrategy.OnPush, Abhängigkeiten mitinject(). - Zustand in Services als
signal(), abgeleitet mitcomputed(). Die App ist zoneless: jede asynchrone Änderung schreibt in ein Signal. - Ionic-Komponenten nur als Rahmen (
ion-app,ion-router-outlet,ion-header,ion-content,ion-footer). Alles Sichtbare sind eigeneog--Komponenten. - Farben und Grössen kommen ausschliesslich aus den Tokens in
src/theme/tokens.scss. - Alle sichtbaren Texte sind Deutsch (Schweiz).
Siehe dazu auch Services, Datenmodell und CI.