Ablage je Einheit, Stufe 2: Verwaltung und Organisationsseite (#684)

- OrgAdministration: eine neue Einheit bekommt ihren Bereich (Mitglieder:
  die Einheit samt Untereinheiten, schreiben); reservierte Namen und belegte
  Bereichs-Ids werden als Einheiten-Id abgelehnt. Uebergreifende Bereiche
  anlegen (mit Eigentuemer), Name/Zweck/geschuetzte Ordner aendern,
  Mitgliederliste ersetzen, nur leere Bereiche loeschen, nie den eigenen
  einer Einheit. Eine geloeschte Einheit verlaesst alle Mitgliederlisten;
  ihr Bereich geht nur, wenn er leer ist, sonst bleibt er ohne Eigentuemer.
  Nachruesten des eigenen Bereichs fuer Einheiten von vor #684. Alles im
  AuditLog.
- API unter /api/organisation/workspaces; die Uebersicht liefert je Bereich
  Mitglieder, Dateizahl und - von der Instanz berechnet - wer hineinkommt.
- Organisationsseite: Bereiche unter der Struktur, Bearbeitung mit
  Mitglieder-Editor, "Wer hineinkommt", Bereichskarte an der Einheit,
  Bereiche am Agenten. Sprachschluessel en/de.
- Die Nachschau nach einem Absturz bekommt die Organisation mit, sonst
  fände sie einen Aufruf in einem benannten Bereich nicht.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-09-24 16:58:09 +02:00
co-authored by Claude Opus 5.5
parent ff20ce2563
commit 609298dd7a
9 changed files with 850 additions and 10 deletions
@@ -5,7 +5,8 @@ public sealed record OrganisationDto(
IReadOnlyList<UnitDto> Units,
IReadOnlyList<OrgMemberDto> Agents,
IReadOnlyList<string> Problems,
IReadOnlyList<string> KnownTools);
IReadOnlyList<string> KnownTools,
IReadOnlyList<WorkspaceDto> Workspaces);
public sealed record UnitDto(
string Id,
@@ -61,3 +62,38 @@ public sealed record SettingPreviewInputDto(string Setting, string Value, string
public sealed record SettingChangeDto(string AgentId, string DisplayName, string Current, string Proposed, bool Outlier, bool SelectedByDefault);
public sealed record SettingApplyDto(string Setting, IReadOnlyDictionary<string, string> Values, string Reason = "", string? DefaultValue = null);
/// <summary>
/// #684: A workspace with its member list — and, computed by the instance, who that list
/// actually lets in and how far. <see cref="IsUnitOwn"/> marks a unit's own workspace.
/// </summary>
public sealed record WorkspaceDto(
string Id,
string Name,
string Purpose,
string? OwnerUnitId,
bool IsUnitOwn,
IReadOnlyList<WorkspaceMemberDto> Members,
IReadOnlyList<string> ProtectedPaths,
int FileCount,
IReadOnlyList<WorkspaceAccessDto> Access);
/// <summary>A member entry: a unit or an agent; <see cref="Access"/> is Read, Write or Manage.</summary>
public sealed record WorkspaceMemberDto(string? UnitId, string? AgentId, string Access, bool IncludeSubUnits = true);
public sealed record WorkspaceAccessDto(string AgentId, string Access);
public sealed record WorkspaceInputDto(
string Id,
string Name,
string? Purpose = null,
string? OwnerUnitId = null,
IReadOnlyList<WorkspaceMemberDto>? Members = null,
string Reason = "");
public sealed record WorkspaceUpdateDto(string? Name = null, string? Purpose = null, IReadOnlyList<string>? ProtectedPaths = null, string Reason = "");
public sealed record WorkspaceMembersInputDto(IReadOnlyList<WorkspaceMemberDto> Members, string Reason = "");
/// <summary>A change that needs nothing but the reason for the audit log.</summary>
public sealed record ReasonInputDto(string Reason = "");