feat: Update Authentik integration and enhance Docker Compose templates

This commit is contained in:
Matt Batchelder
2026-03-14 22:51:52 -04:00
parent 150549a20d
commit c2e03de8bb
7 changed files with 174 additions and 188 deletions

73
.github/copilot-instructions.md vendored Normal file
View File

@@ -0,0 +1,73 @@
# Project Guidelines — OTS Signs Orchestrator
## Architecture
Layered MVVM desktop app for provisioning and managing Xibo CMS instances on Docker Swarm.
- **OTSSignsOrchestrator.Core** — class library: services, EF Core data access, models, configuration. Reusable across UIs.
- **OTSSignsOrchestrator.Desktop** — Avalonia 11 UI: views, view models, DI setup. References Core.
- **templates/** — Docker Compose + PHP templates with `{{PLACEHOLDER}}` substitution.
### Key patterns
- Services injected via `IServiceProvider` (registered in `App.axaml.cs``ConfigureServices()`)
- Singletons: stateful services (SSH connections, Docker CLI). Transient: stateless logic.
- Configuration via `IOptions<T>` bound from `appsettings.json` (see `AppOptions.cs` for all sections).
- Bitwarden Secrets Manager is the source of truth for all sensitive config. `SettingsService` caches in-memory.
- Local SQLite DB (`otssigns-desktop.db`) stores SSH hosts + operation logs. Credentials encrypted via Data Protection API.
### External integrations
Xibo CMS REST API (OAuth2), Authentik SAML IdP, Bitwarden Secrets SDK, Docker Swarm (via SSH), Git (LibGit2Sharp), MySQL 8.4, NFS volumes, Pangolin/Newt VPN.
## Build and Test
```bash
# Build
dotnet build OTSSignsOrchestrator.Desktop/OTSSignsOrchestrator.Desktop.csproj
# Run
dotnet run --project OTSSignsOrchestrator.Desktop/OTSSignsOrchestrator.Desktop.csproj
# No test suite currently — no xUnit/NUnit projects
```
- .NET 9.0, Avalonia 11.2.3, CommunityToolkit.Mvvm 8.4
- Runtime identifiers: `linux-x64`, `win-x64`, `osx-x64`, `osx-arm64`
- EF Core migrations in `OTSSignsOrchestrator.Core/Migrations/`
## Conventions
### ViewModels
- Inherit `ObservableObject` (CommunityToolkit.Mvvm). Use `[ObservableProperty]` for bindable fields and `[RelayCommand]` for commands.
- React to changes via `partial void OnXxxChanged(T value)` methods generated by the toolkit.
- Resolve services from `IServiceProvider` in constructors. Navigation via `MainWindowViewModel.CurrentView`.
- Confirmation dialogs use `Func<string, string, Task<bool>> ConfirmAsync` property — wired by the View.
### Views (Avalonia XAML)
- Compiled bindings enabled (`x:CompileBindings="True"`). DataTemplates in `MainWindow.axaml` map ViewModel types to View UserControls.
- Layout: DockPanel with status bar (bottom), sidebar nav (left), dynamic ContentControl (center).
- Style: Fluent theme, dark palette (`#0C0C14` accents).
### Services
- Interface + implementation pattern for testable services (`IXiboApiService`, `IDockerCliService`, etc.).
- `SshDockerCliService` is a singleton — **must call `SetHost(host)` before each operation** in loops.
- All long operations are `async Task`. Use `IsBusy` + `StatusMessage` properties for UI feedback.
### Naming
- Customer abbreviation: exactly 3 lowercase letters (`^[a-z]{3}$`).
- Stack name: `{abbrev}-cms-stack`. Service: `{abbrev}-web`. DB: `{abbrev}_cms_db`.
- Secret names built via `AppConstants` helpers (e.g., `CustomerMysqlPasswordSecretName(abbrev)`).
- `AppConstants.SanitizeName()` filters to `[a-z0-9_-]`.
### Data layer
- Entities in `Core/Models/Entities/`, DTOs in `Core/Models/DTOs/`.
- `XiboContext` applies unique index on `SshHost.Label` and encrypts credential fields.
- Add new migrations via: `dotnet ef migrations add <Name> --project OTSSignsOrchestrator.Core --startup-project OTSSignsOrchestrator.Desktop`
## Pitfalls
- **SSH singleton state**: `SshDockerCliService.SetHost()` must be called before each host operation — stale host causes silent failures.
- **Bitwarden cache**: After creating secrets during deployment, call `FlushCacheAsync()` before reading them back.
- **Data Protection keys**: Stored in `%APPDATA%/OTSSignsOrchestrator/keys`. If lost, encrypted SSH passwords are unrecoverable.
- **Docker volumes are sticky**: Failed deploys leave volumes with old NFS driver options. Use `PurgeStaleVolumes: true` to force fresh volumes (causes data loss).
- **No saga/rollback**: Instance creation spans Git → MySQL → Docker → Xibo. Partial failures leave orphaned resources; cleanup is manual via `OperationLog`.
- **Template CIFS→NFS compat**: Old `{{CIFS_*}}` tokens still render correctly as NFS equivalents.