Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .agents/skills/work-in-nextcloud-app/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ Stop immediately if production systems, Git history rewriting, new production de
- Develop executable UI logic test-first; additionally cover layout, accessibility, and Nextcloud integration with suitable smoke or browser checks.
- Treat a time-boxed exploratory spike or hard-to-isolate Nextcloud integration as an explicitly justified deviation. Discard spike code or characterize it before adoption; choose the truthful broader integration level when isolation would hide the real contract.
- Use the local fast entries named by `AGENTS.md`, normally `php tests/run.php` and `node tests/run-js.mjs`; dependency-light PHP smokes run in isolated processes. Run LocalBase and every affected consumer contract/smoke suite after a LocalBase contract change.
- In local pre-production, app tests may use shared LocalBase test helpers through relative repository paths. Add heavier packaging/autoload structure or a larger test framework only when path handling, runners, assertions, mocks, or fixtures are materially duplicated or impair readability.
- PHP classes must not remain coupled through distributed relative `require` or `require_once` chains. Production classes under `lib/` use Nextcloud's PSR-4 app autoloader; a bundled category-A dependency uses exactly one reproducibly generated, app-local, namespace-isolated Composer autoloader. Never use a shared workspace autoloader, shared cross-app `vendor/`, or neighboring production repository path as a delivery mechanism. Category-B services remain separate runtime apps and are consumed only through their public activation- and version-aware contracts.
- Every app uses one central app-local test bootstrap/autoloader for dependency-light PHP tests. It may resolve a test-only LocalBase helper through exactly one central transition point until a versioned development dependency exists, but individual tests must not retain direct relative LocalBase class paths after migration. Nextcloud integration tests may load the documented Nextcloud test bootstrap; template partials, explicit process/test entrypoints, and the one-time bootstrap of a bundled Composer autoloader remain justified includes rather than class-load chains.
- When a writing task first touches executable PHP or PHP tests in an app that has not yet migrated, include that app's complete autoload migration as a separate preparatory step in the same app scope. An app is complete only when distributed manual class requires and production fallback requires are gone, allowed includes are limited and reviewable, relevant app and provider/consumer PHP tests are green, and release checks contain neither development dependencies nor foreign repository paths. Documentation-only, formatting-only, and JavaScript-only work does not trigger an artificial PHP migration.
- Known overall and app coverage must not decline unnoticed. Aim for at least 85 percent line coverage for new or materially changed executable code, report PHP and JavaScript separately, and fully cover security invariants regardless of percentages. Coverage is a warning and delivery indicator, not a substitute for meaningful assertions.
- Do not prepare a commit or release with red relevant fast tests, contract tests, security checks, coverage gates, or delivery gates.

Expand All @@ -82,6 +84,7 @@ Stop immediately if production systems, Git history rewriting, new production de

## Git and completion report

- When Simon asks for the next open steps, priorities, remaining work, or a similar outlook, include every applicable pending migration and unresolved decision from accepted ADRs and documented rollout plans. Report its current status, trigger, and required approval gate, and distinguish work executable now from work triggered by a later app change and work that is currently undecidable. Mentioning an item does not expand the current write scope or authorize a gated change.
- Do not commit, push, release, deploy, or use `git add .` without Simon's explicit authorization. Stage individual files only when staging was requested.
- Before a commit, show `git status --short`, `git diff --stat`, and `git diff --name-only`. Never use `git reset --hard`, `git clean`, force-push, history rewrite, or versioned backup copies.
- Run relevant local tests, `git diff --check`, and the repository's own structure/fast check. For an explicitly authorized cross-app contract change, validate every provider and consumer repository from its own root and use the Parent workspace check only as an additional coordinator.
Expand Down
9 changes: 9 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,12 @@ jobs:
run: |
php tests/run.php
node tests/run-js.mjs

deploy-staging:
name: Staging-Deployment
if: github.event_name == 'push'
needs: [php, javascript, consumer-contracts]
uses: Filzmann/br-nextcloud-apps/.github/workflows/deploy-staging.yml@main
with:
app-id: localbase
secrets: inherit
13 changes: 11 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ Aktuell enthalten:
- PHP-Modelltrait `OCA\LocalBase\Model\ModelApiTrait`.
- PHP-Logger `OCA\LocalBase\Service\AppLogger` fuer sichere, skalare Log-Kontexte mit App-ID und optionaler User-ID.
- PHP-Gruppenhelfer `OCA\LocalBase\Service\GroupProvisioningService` zum idempotenten Anlegen beliebiger Nextcloud-Gruppen.
- Neutraler Kalendervertrag `AbsenceQueryEvent`/`AbsenceInterval` fuer optionale, read-only Abwesenheitsprovider. `planned` liefert `U?` ohne Blockade, `approved` liefert `U` mit Blockade.
- Neutraler Kalendervertrag `AbsenceEmployeeDiscoveryEvent`/`AbsenceQueryEvent`/`AbsenceInterval` fuer optionale, read-only Abwesenheitsprovider. Die Discovery bleibt auf einen halboffenen Zeitraum begrenzt, liefert ausschließlich normalisierte Konto-UIDs und bleibt ohne Provider leer. `planned` liefert `U?` ohne Blockade, `approved` liefert `U` mit Blockade.
- `CalendarContext` und `CalendarContextSettingsService` definieren Land, ISO-3166-2-Region und fachliche IANA-Zeitzone organisationsweit. `DE`, `DE-BE` und `Europe/Berlin` bleiben Bestandsdefaults. Persönliche Nextcloud-Zeitzonen dürfen ausschließlich individuelle Terminanzeigen beeinflussen. Der Kontext ist im gemeinsamen AD-Adminbereich änderbar und wird bei bestehenden persönlichen Dashboardlayouts additiv eingeblendet.
- `HolidayCalendarService` liefert Schulferien und gesetzliche Feiertage als validierten, read-only Jahresvertrag für den gemeinsamen Kalenderkontext. `OpenHolidaysClient` ist der einzige externe Provideradapter; `HolidayCalendarCacheStore` hält regionsgebundene Jahresstände in der LocalBase-AppConfig. Ein täglicher Hintergrundjob aktualisiert das laufende und die zwei folgenden Jahre. Bei Providerfehlern bleibt ein vorhandener Stand als `stale` verfügbar, Erstabrufe werden sicher als `unavailable` ausgewiesen und nach kurzer Sperrfrist erneut versucht.
- `AdOrganizationDefinition`, `AdOrganizationSettingsService`, `AdOrganizationHierarchy` und `AdOrganizationPermissionPolicy` bilden die konfigurierbaren gemeinsamen AD-Gruppen, Anzeigenamen, Bereiche, Teamansichten, Hierarchie und Peer-Grenzen fuer Kalender, Urlaub und Assistenzplanung ab.
- `AdSuiteAdminSettingsService` speichert app-übergreifend verwendete Peer-Freigaben semantisch nach Rollen und stellt sie AD Kalender, AD Urlaub und der administrativen OrgSuite-Oberfläche gemeinsam bereit.
- Rollen und Bereiche werden über stabile semantische Schlüssel referenziert; konfigurierbare Nextcloud-Gruppen-IDs oder Anzeigenamen dürfen nicht als Fachschlüssel in App-Code dupliziert werden.
- Die initiale Reihenfolge umfasst Fahrzeugverwaltung nach IT, Empfang nach Sekretariat sowie im Pflegebereich stellvertretende PDL, Büroorganisation Pflege und Pflegefachkraft. Für den Bürobereich bleibt Büroleitung, stellvertretende Büroleitung, Einsatzbegleitung und Büromitarbeiter*innen maßgeblich. Die im Adminbereich gespeicherte Reihenfolge bleibt für alle Verbraucher verbindlich.
- Organisationsvertrag Version 2 ergänzt bestehende Version-1-Einstellungen additiv um `deputy_pdl`, `care_office`, `fleet_management` und `reception`, die freigegebenen Hierarchiekanten sowie Urlaubsansichten. Bestehende Werte und Kanten bleiben erhalten; Gruppen-ID-Kollisionen und Zyklen werden abgelehnt.
- Organisationsvertrag Version 3 trennt `finance` und `payroll` additiv unter `finance_lead`; die bestehende Finanzgruppen-ID bleibt erhalten. Der read-only `AdOrganizationSnapshot` enthält nur Rollen und Bereiche, keine Mitgliederlisten, und ist bei fehlender oder ungültiger Persistenz nicht freigabefähig.
- `diagramOrder` speichert davon getrennt ausschließlich die globale Links-rechts-Anordnung der Organigrammkarten innerhalb ihrer Hierarchieebene. Beim horizontalen Drag-and-drop bestimmt der Zwischenraum zwischen zwei Karten die neue Einfügeposition. Diese visuelle Anordnung verändert weder Rollen-/Bereichsreihenfolgen noch Kalender, Rechte oder Hierarchiekanten.
- Das Organigramm bleibt automatisch nach Hierarchieebenen angeordnet; freie X-/Y-Knotenpositionen sind kein Bestandteil des Organisationsvertrags. Karten derselben Ebene stehen waagerecht nebeneinander und verwenden innerhalb definierter Mindest-/Maximalgrenzen nur ihre benötigte Breite; sie brechen nicht in scheinbare zusätzliche Hierarchiezeilen um. Der persönliche Zoom wird in 10-Prozent-Schritten von 50 bis 150 Prozent über `IUserConfig` geräteübergreifend gespeichert. Der verschobene Ausschnitt bleibt wegen unterschiedlicher Viewportgrößen flüchtig. Zoom und Ausschnitt verändern weder Hierarchie und Diagrammordnung noch die logische Größe der Exporte.
- Fachliche Rolleneinstellungen werden über den Edit-Stift der Diagrammkarten in einem zugänglichen Seitenpanel bearbeitet und gelten für alle Diagrammkarten derselben semantischen Rolle. Technische Gruppen-IDs bleiben dort eingeklappt; die für Kalender und Gruppenlisten verbindliche Rollenreihenfolge bleibt als eigene kompakte Drag-and-drop-Liste sichtbar. Bürobereiche und Urlaubsansichten werden als aufklappbare Einstellungskarten dargestellt.
Expand All @@ -42,7 +43,15 @@ Aktuell enthalten:
- Ungültige Referenzen, doppelte Gruppen-IDs und Hierarchiezyklen werden beim Speichern abgelehnt. Eine ungültige persistierte Definition fällt beim Lesen sicher auf die geprüfte Standarddefinition zurück.
- `ScheduleConflictQueryEvent` liefert vor genehmigten Abwesenheiten read-only Konflikte aus optional aktivierten Planungsapps; Provider loeschen oder aendern dabei keine Daten.
- `IntegrationCapabilityQueryEvent`, `AdIntegrationCapabilities` und `IntegrationCapabilityService` beschreiben optionale Cross-App-Fähigkeiten. Ein leerer Snapshot ist ein zulässiger Standalone-Zustand und erweitert niemals Berechtigungen.
- `StandaloneAppNavigationService` registriert Fachapp-Einstiege nur ohne aktive OrgSuite. `AdProductSuiteService` und die dynamischen Settings-Adapter platzieren die gemeinsame Organisationsverwaltung bei einer Einzelinstallation unter deren Fachprodukt.
- `AdProductCatalog` liest den versionierten AD-Produktkatalog als kanonische
Quelle für Produkt-IDs, Reihenfolge, Routen sowie getrennte Menü-,
Standalone- und Bundle-Eigenschaften. Ungültige oder fehlende Katalogdaten
erweitern weder Navigation noch Berechtigungen.
- `StandaloneAppNavigationService` registriert katalogisierte
Fachapp-Einstiege nur ohne aktive OrgSuite. `AdProductSuiteService` und die
dynamischen Settings-Adapter platzieren die gemeinsame
Organisationsverwaltung bei einer Einzelinstallation unter deren
Fachprodukt.
- Organisationseditor, Admin-API und Persistenz des gemeinsamen AD-Vertrags liegen vollständig in LocalBase. OrgSuite bindet diese Oberfläche ab zwei Produkten nur als Adminadapter ein.
- JavaScript-Basisklasse `window.LocalBase.models.Model`.
- JavaScript-API-Client `window.LocalBase.api.ApiClient`.
Expand Down
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# Changelog

## 0.10.0-rc.2

- Gemeinsamen API-Client um den lokalisierten Nextcloud-Fehlervertrag mit stabilem `error`-Feld ergänzt; ältere `message`-Antworten bleiben kompatibel.

## 0.10.0-rc.1

- Organisationsvertrag Version 3 mit getrennten Rollen `finance` und `payroll` ergänzt; bestehende Finanzgruppen bleiben beim Upgrade erhalten.
- Datensparsamen, unveränderlichen Organisationssnapshot für Fachapp-Berechtigungen veröffentlicht.
- Fehlende oder ungültige Organisationspersistenz im Snapshot explizit als nicht freigabefähig markiert.
- Synthetische Demoorganisation um die getrennte Lohnrolle ergänzt.

## 0.9.0-rc.1

- Versionierten AD-Produktkatalog als kanonischen Providervertrag ergänzt.
- AD Recruitment als Standalone-, Menü-, Suite- und Einzelbundle-Produkt aufgenommen.
- Bestehende Standalone-Navigation auf Katalogroute und -reihenfolge umgestellt.

## 0.7.0-rc.1

- Optionale Capability-Verträge für eigenständig installierbare AD-Fachprodukte ergänzt.
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

Gemeinsame Basisbausteine für die lokalen AD- und BR-Nextcloud-Apps. LocalBase besitzt keine eigene Navigation und wird als technische Infrastruktur mit den AD-Fachprodukten ausgeliefert.

Der öffentliche AD-Organisationsvertrag Version 3 trennt Finanzen und Lohn
unter derselben Leitung. Fachapps konsumieren Rollen und Bürobereiche über
einen unveränderlichen, datensparsamen Snapshot; fehlende oder ungültige
Persistenz erteilt keine fachlichen Rechte.

## Staging-Kompatibilität

- Nextcloud 34
Expand All @@ -23,3 +28,8 @@ Auf Staging- und Zielsystemen wird LocalBase nicht als separates Fachprodukt ins
## Roadmap

Geplante gemeinsame Bausteine und offene Architekturentscheidungen stehen in der [Roadmap](ROADMAP.md).

Für die manuelle Staging-Prüfung der Administrationsoberfläche und der
Cross-App-Verträge steht ein ausfüllbares
[Abnahmeformular](docs/manual-acceptance.md) bereit. Es berücksichtigt, dass
LocalBase keine eigene Fachnavigation besitzt.
34 changes: 34 additions & 0 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,42 @@

Diese Datei bündelt geplante Erweiterungen und offene Architekturentscheidungen. Verbindliche Fach-, Sicherheits- und Architekturregeln stehen in `AGENTS.md`.

## Freigegebene Umsetzungsaufgaben

### LB-BR-GROUPS – Gemeinsamen BR-Gruppenvertrag bereitstellen

Status: bereit nach Klärung der Mitgliedschaftsinvariante

- Konfigurierbare semantische Schlüssel für BR-Mitglieder, Vorsitz und
Stellvertretung bereitstellen; die drei Bedeutungen bleiben getrennt.
- Bestehende Gruppennamen additiv übernehmen. Der Provider benennt oder
löscht keine Gruppen und verändert keine Mitgliedschaften.
- Fehlende, doppelte oder widersprüchliche Gruppenbezüge sicher ablehnen.
- Vor Implementierung entscheiden, ob Vorsitz und Stellvertretung zwingend
zugleich Mitglieder der allgemeinen BR-Gruppe sein müssen.
- Provider-, Migrations- und Deny-Tests gemeinsam mit
`BRT-BR-GROUPS` und `BRS-BR-GROUPS` abnehmen.

## Zukunftsplanung – nicht freigegeben

### LB-L10N – LocalBase-Oberflächen vollständig lokalisieren

Status: später, nicht freigegeben; Pilot-App, Reihenfolge und Rohtext-Gate
werden vor jeder Umsetzung appübergreifend separat freigegeben

- Nur von LocalBase selbst gerenderte sichtbare Texte, Meldungen,
Datumsnamen, Pluralformen und Platzhalter auf Nextcloud-l10n umstellen.
- Konfigurierte Eigennamen, technische Schlüssel, API-Werte und
Organisationsdaten unverändert lassen.
- Deutsche Ausgabe, eine weitere Locale, Fallback, Pluralformen,
Platzhalter und Escaping in PHP und JavaScript testen.
- Erst nach vollständiger Migration einen Rohtext-Check für LocalBase
verbindlich schalten.

## Aktueller Fokus

- Die manuellen Prüfungen werden im ausfüllbaren
[`docs/manual-acceptance.md`](docs/manual-acceptance.md) dokumentiert.
- Bestehende gemeinsame Modelle, API-, UI-, Organisations-, Integrations- und Testverträge klein, dependency-arm und stabil halten.
- Öffentliche Verträge mit den betroffenen Consumer-Apps auf einem realitätsnahen Staging und durch Contract-Tests absichern.
- Den Organisationseditor mit realen Gruppenbesetzungen und großen Organisationsstrukturen visuell und fachlich abnehmen.
Expand Down
12 changes: 6 additions & 6 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,19 @@
<name>Lokale Nextcloud-Basis</name>
<summary>Gemeinsame lokale Basisbausteine für eigene Nextcloud-Apps.</summary>
<description>Stellt kleine, gemeinsam genutzte PHP- und JavaScript-Basisbausteine für eigene lokale Nextcloud-Apps bereit.</description>
<version>0.8.0-rc.2</version>
<version>0.10.0-rc.2</version>
<licence>agpl</licence>
<author>Simon</author>
<namespace>LocalBase</namespace>
<category>tools</category>
<website>https://github.com/Filzmann/ad-suite</website>
<bugs>https://github.com/Filzmann/nextcloud-localbase/issues</bugs>
<repository type="git">https://github.com/Filzmann/nextcloud-localbase</repository>
<namespace>LocalBase</namespace>
<category>tools</category>
<background-jobs>
<job>OCA\LocalBase\BackgroundJob\RefreshHolidayCalendarJob</job>
</background-jobs>
<dependencies>
<php min-version="8.3"/>
<nextcloud min-version="34" max-version="34"/>
</dependencies>
<background-jobs>
<job>OCA\LocalBase\BackgroundJob\RefreshHolidayCalendarJob</job>
</background-jobs>
</info>
30 changes: 27 additions & 3 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,12 @@ sie isoliert aus.

## Kalender- und Abwesenheitsverträge

`AbsenceQueryEvent` und `AbsenceInterval` bilden optionale read-only
Abwesenheitsprovider ab. `planned` liefert `U?` ohne Blockade, `approved`
liefert `U` mit Blockade. `ScheduleConflictQueryEvent` liefert vor genehmigten
`AbsenceEmployeeDiscoveryEvent`, `AbsenceQueryEvent` und `AbsenceInterval`
bilden optionale read-only Abwesenheitsprovider ab. Die Discovery ist an einen
halboffenen Zeitraum gebunden und aggregiert ausschließlich normalisierte
Konto-UIDs; leere und nicht-stringförmige Providerwerte werden verworfen, und
ohne Provider bleibt sie leer. `planned` liefert `U?` ohne Blockade,
`approved` liefert `U` mit Blockade. `ScheduleConflictQueryEvent` liefert vor genehmigten
Abwesenheiten read-only Konflikte aus optionalen Planungsapps; Provider
löschen oder verändern keine Daten.

Expand Down Expand Up @@ -51,6 +54,27 @@ erhalten; Gruppen-ID-Kollisionen, ungültige Referenzen und Hierarchiezyklen
werden abgelehnt. Eine ungültige gespeicherte Definition fällt sicher auf die
geprüfte Standarddefinition zurück.

Version 3 trennt die bisherigen Funktionen unterhalb `finance_lead` in die
stabilen Schlüssel `finance` und `payroll`. Beim Upgrade bleibt die bestehende
Gruppen-ID von `finance` erhalten; `payroll` wird additiv ergänzt. Beide
Rollen bleiben im bisherigen Hierarchie- und Organisationsblock.
Aus Sicherheitsgründen wird die Mitgliedschaft der bisherigen kombinierten
Gruppe nicht automatisch zu `payroll` kopiert: Die Bestandsgruppe wird
`finance` zugeordnet und ihr unveränderter Standardtitel fachlich zu
„Finanzen“ normalisiert. Administrator*innen verschieben Lohn-Mitarbeitende
anschließend bewusst in die neue konfigurierte Lohn-Gruppe. Bis dahin erhält
niemand aus der alten kombinierten Gruppe Zugriff auf Vertragsstammdaten.
Für bestehende Hierarchie-Consumer bleibt die frühere technische Gruppen-ID
`ad-Finanzen-Lohn` als reiner `finance`-Alias lesbar; dieser Alias erteilt
ausdrücklich niemals die neue `payroll`-Rolle.

`AdOrganizationSnapshotService` veröffentlicht Rollen und Bereiche ohne
Mitgliederlisten oder Fachrechte. Der unveränderliche Snapshot enthält
Vertragsversion, Definitionsversion, Gültigkeitsstatus und Prüfsumme. Eine
fehlende, beschädigte oder nur aus Defaults rekonstruierte Persistenz erzeugt
einen ungültigen, leeren Snapshot, aus dem Consumer keine Freigabe ableiten
dürfen.

`AdSuiteAdminSettingsService` speichert app-übergreifende Peerfreigaben
semantisch nach Rollen. Die Organisationsdefinition und diese Freigaben liegen
zentral in LocalBase-AppConfig. Bei Einzelinstallation erscheinen sie im
Expand Down
Loading