import { MetricGrid } from "@govoplan/core-webui"; import { useCallback, useEffect, useMemo, useState } from "react"; import { Archive, Boxes, Building2, KeyRound, Eye, Inbox, Pencil, Plus, RefreshCw, Rocket, Save, Trash2 } from "lucide-react"; import { FormGrid, ActionBlockerHint, AdminPageLayout, Button, ConfirmDialog, Dialog, DocumentationHelpLink, FormField, IconButton, MetricCard, SegmentedControl, SelectionList, SelectionListItem, StatePanel, StatusBadge, ToggleSwitch, i18nMessage, useUnsavedChanges, useUnsavedDraftGuard, type ApiSettings } from "@govoplan/core-webui"; import { archivePostbox, createPostboxProtectionTransition, createExactPostbox, createPostboxTemplate, listAdminPostboxes, listPostboxProtectionProfiles, listPostboxProtectionTransitions, listPostboxOrganizationTargets, listPostboxTemplates, materializePostboxTemplate, previewPostboxTemplate, publishPostboxTemplate, retirePostboxTemplate, revisePostboxTemplate, updatePostboxProtectionPolicy, updatePostboxGroupingPolicy, type PostboxDirectoryItem, type PostboxExactCreatePayload, type PostboxGroupingPolicy, type PostboxOrganizationFunction, type PostboxOrganizationStructure, type PostboxOrganizationUnit, type PostboxProtectionPolicy, type PostboxProtectionProfile, type PostboxProtectionProfileId, type PostboxProtectionTransition, type PostboxRoutingPolicy, type PostboxTemplate, type PostboxTemplateCreatePayload, type PostboxTemplatePreview, type PostboxTemplateRevisionPayload } from "../../api/postbox"; import { POSTBOX_ADMIN_DOCUMENTATION, POSTBOX_FIELD_DOCUMENTATION, POSTBOX_INTERFACE_I18N, postboxBusyReason } from "./interfacePatterns"; type AdminMode = "templates" | "postboxes"; type TemplateDraft = PostboxTemplateCreatePayload & { templateId: string }; type ExactDraft = PostboxExactCreatePayload; type MaterializeDraft = { templateId: string; organization_unit_id: string; function_id: string; context_key: string; }; type ProtectionTransitionDraft = { target_profile: PostboxProtectionProfileId; target_vault_id: string; history_mode: "future_only" | "migrate_history"; authority_mode: "user_consent" | "institutional_key_holders" | "dual_control"; required_quorum: number; user_consent_refs: string; institutional_authorization_refs: string; reason: string; acknowledge_irreversibility: boolean; }; const protectionPolicyDefaults = (): PostboxProtectionPolicy => ({ new_incumbent_history: "since_assignment", history_days: null, ordinary_rotation: "rewrap", compromise_rotation: "reencrypt", recovery_authority: "institutional_key_holders", recovery_quorum: 2, handover_authority: "dual_control", handover_quorum: 2, emergency_access: "dual_control", emergency_quorum: 2, export_authority: "dual_control", export_quorum: 2, destruction_authority: "dual_control", destruction_quorum: 2, external_recipient_assurance: "strong_identity", vacancy_escalation_content_access: "metadata_only" }); const groupingPolicyDefaults = (): PostboxGroupingPolicy => ({ mode: "allow", reason: null }); const routingDefaults = (): PostboxRoutingPolicy => ({ linked_copy: { enabled: false, structure_id: null, relation_type_ids: [], max_depth: 1, stop_unit_id: null, stop_unit_type_id: null, target_function_type_id: null, target_template_id: null, fanout: "nearest", allowed_classifications: ["internal"], allowed_producer_modules: [], require_expiry: false, max_retention_days: null }, attention: { mode: "none", delay_minutes: null }, shared_visibility: { mode: "none" } }); const templateDefaults = (): TemplateDraft => ({ templateId: "", slug: "", name: "", description: "", function_type_id: null, scope_kind: "tenant", scope_id: null, scope_structure_id: null, scope_relation_type_ids: [], name_pattern: "{unit_name} / {function_name}", address_pattern: "{template_slug}.{unit_slug}.{function_slug}", classification: "internal", allow_vacant_delivery: true, portal_visible: false, encryption_profile: "server_envelope_v1", encryption_vault_id: "", protection_policy: protectionPolicyDefaults(), grouping_policy: groupingPolicyDefaults(), routing_policy: routingDefaults() }); const exactDefaults = (): ExactDraft => ({ name: "", description: "", organization_unit_id: "", function_id: "", address_key: "", classification: "internal", portal_visible: false, encryption_profile: "server_envelope_v1", encryption_vault_id: "", protection_policy: protectionPolicyDefaults(), grouping_policy: groupingPolicyDefaults() }); const protectionTransitionDefaults = ( postbox?: PostboxDirectoryItem | null ): ProtectionTransitionDraft => { const authority = postbox?.protection_policy?.handover_authority || "dual_control"; return { target_profile: postbox?.encryption_profile === "server_envelope_v1" ? "external_e2ee_v1" : "server_envelope_v1", target_vault_id: postbox?.encryption_vault_id || "", history_mode: "future_only", authority_mode: authority, required_quorum: Math.max( authority === "dual_control" ? 2 : 1, postbox?.protection_policy?.handover_quorum || 1 ), user_consent_refs: "", institutional_authorization_refs: "", reason: "", acknowledge_irreversibility: false }; }; export default function PostboxAdminPanel({ settings, canManageBindings, canManageTemplates }: { settings: ApiSettings; canManageBindings: boolean; canManageTemplates: boolean; }) { const [mode, setMode] = useState( canManageTemplates ? "templates" : "postboxes" ); const [templates, setTemplates] = useState([]); const [postboxes, setPostboxes] = useState([]); const [units, setUnits] = useState([]); const [structures, setStructures] = useState([]); const [protectionProfiles, setProtectionProfiles] = useState([]); const [protectionTransitions, setProtectionTransitions] = useState([]); const [selectedTemplateId, setSelectedTemplateId] = useState(""); const [selectedPostboxId, setSelectedPostboxId] = useState(""); const [loading, setLoading] = useState(true); const [busy, setBusy] = useState(false); const [error, setError] = useState(""); const [success, setSuccess] = useState(""); const [templateDialogOpen, setTemplateDialogOpen] = useState(false); const [templateDraft, setTemplateDraft] = useState(templateDefaults); const [templateBaseline, setTemplateBaseline] = useState(templateDefaults); const [templatePreview, setTemplatePreview] = useState(null); const [templatePreviewLoading, setTemplatePreviewLoading] = useState(false); const [exactDialogOpen, setExactDialogOpen] = useState(false); const [exactDraft, setExactDraft] = useState(exactDefaults); const [exactBaseline, setExactBaseline] = useState(exactDefaults); const [materializeDialogOpen, setMaterializeDialogOpen] = useState(false); const [materializeDraft, setMaterializeDraft] = useState({ templateId: "", organization_unit_id: "", function_id: "", context_key: "" }); const [materializeBaseline, setMaterializeBaseline] = useState({ templateId: "", organization_unit_id: "", function_id: "", context_key: "" }); const [archiveTarget, setArchiveTarget] = useState(null); const [retireTarget, setRetireTarget] = useState(null); const [protectionDialogOpen, setProtectionDialogOpen] = useState(false); const [protectionDraft, setProtectionDraft] = useState(protectionTransitionDefaults); const [protectionBaseline, setProtectionBaseline] = useState(protectionTransitionDefaults); const [policyDialogOpen, setPolicyDialogOpen] = useState(false); const [policyDraft, setPolicyDraft] = useState(protectionPolicyDefaults); const [policyBaseline, setPolicyBaseline] = useState(protectionPolicyDefaults); const [groupingPolicyDialogOpen, setGroupingPolicyDialogOpen] = useState(false); const [groupingPolicyDraft, setGroupingPolicyDraft] = useState(groupingPolicyDefaults); const [groupingPolicyBaseline, setGroupingPolicyBaseline] = useState(groupingPolicyDefaults); const { requestDiscard } = useUnsavedChanges(); const selectedTemplate = useMemo( () => templates.find((template) => template.id === selectedTemplateId) ?? templates[0] ?? null, [templates, selectedTemplateId] ); const selectedPostbox = useMemo( () => postboxes.find((postbox) => postbox.id === selectedPostboxId) ?? postboxes[0] ?? null, [postboxes, selectedPostboxId] ); const functionTypes = useMemo(() => { const values = new Map(); for (const unit of units) { for (const fn of unit.functions) { if (fn.function_type_id && !values.has(fn.function_type_id)) { values.set(fn.function_type_id, fn.name); } } } return [...values].map(([id, name]) => ({ id, name })); }, [units]); const unitTypes = useMemo(() => { const values = new Map(); for (const unit of units) { if (unit.unit_type_id && !values.has(unit.unit_type_id)) { values.set(unit.unit_type_id, unit.name); } } return [...values].map(([id, example]) => ({ id, example })); }, [units]); const templateDirty = templateDialogOpen && draftKey(templateDraft) !== draftKey(templateBaseline); const exactDirty = exactDialogOpen && draftKey(exactDraft) !== draftKey(exactBaseline); const materializeDirty = materializeDialogOpen && draftKey(materializeDraft) !== draftKey(materializeBaseline); const protectionDirty = protectionDialogOpen && draftKey(protectionDraft) !== draftKey(protectionBaseline); const policyDirty = policyDialogOpen && draftKey(policyDraft) !== draftKey(policyBaseline); const groupingPolicyDirty = groupingPolicyDialogOpen && draftKey(groupingPolicyDraft) !== draftKey(groupingPolicyBaseline); useUnsavedDraftGuard({ dirty: templateDirty || exactDirty || materializeDirty || protectionDirty || policyDirty || groupingPolicyDirty, title: "Unsaved Postbox administration draft", message: "Save or discard the open Postbox administration draft before leaving this surface.", onSave: saveActiveDraft, onDiscard: discardAdminDraft }); const load = useCallback(async () => { setLoading(true); setError(""); try { const [nextTemplates, nextPostboxes, organizationTargets, profileCatalog] = await Promise.all([ canManageTemplates ? listPostboxTemplates(settings) : Promise.resolve([]), canManageBindings ? listAdminPostboxes(settings) : Promise.resolve([]), listPostboxOrganizationTargets(settings), listPostboxProtectionProfiles(settings) ]); setTemplates(nextTemplates); setPostboxes(nextPostboxes); setUnits(organizationTargets.units); setStructures(organizationTargets.structures); setProtectionProfiles(profileCatalog.profiles); setSelectedTemplateId((current) => current && nextTemplates.some((template) => template.id === current) ? current : nextTemplates[0]?.id ?? "" ); setSelectedPostboxId((current) => current && nextPostboxes.some((postbox) => postbox.id === current) ? current : nextPostboxes[0]?.id ?? "" ); } catch (loadError) { setError(errorMessage(loadError)); } finally { setLoading(false); } }, [canManageBindings, canManageTemplates, settings]); useEffect(() => { void load(); }, [load]); useEffect(() => { if (!canManageBindings || !selectedPostboxId) { setProtectionTransitions([]); return; } let cancelled = false; void listPostboxProtectionTransitions(settings, selectedPostboxId) .then((values) => { if (!cancelled) setProtectionTransitions(values); }) .catch((transitionError) => { if (!cancelled) setError(errorMessage(transitionError)); }); return () => { cancelled = true; }; }, [canManageBindings, selectedPostboxId, settings]); function openNewTemplate() { const next = templateDefaults(); setTemplatePreview(null); setTemplateDraft(next); setTemplateBaseline(next); setTemplateDialogOpen(true); } function openTemplateRevision(template: PostboxTemplate) { const revision = currentRevision(template); if (!revision) return; const next = { templateId: template.id, slug: template.slug, name: template.name, description: template.description || "", function_type_id: revision.function_type_id ?? null, scope_kind: revision.scope_kind, scope_id: revision.scope_id ?? null, scope_structure_id: revision.scope_structure_id ?? null, scope_relation_type_ids: revision.scope_relation_type_ids ?? [], name_pattern: revision.name_pattern, address_pattern: revision.address_pattern, classification: revision.classification, allow_vacant_delivery: revision.allow_vacant_delivery, portal_visible: revision.portal_visible, encryption_profile: revision.encryption_profile, encryption_vault_id: revision.encryption_vault_id ?? "", protection_policy: revision.protection_policy ?? protectionPolicyDefaults(), grouping_policy: revision.grouping_policy ?? groupingPolicyDefaults(), routing_policy: revision.routing_policy ?? routingDefaults() }; setTemplatePreview(null); setTemplateDraft(next); setTemplateBaseline(next); setTemplateDialogOpen(true); } async function saveTemplate(): Promise { setBusy(true); setError(""); setSuccess(""); try { if (templateDraft.templateId) { const currentTemplate = templates.find( (item) => item.id === templateDraft.templateId ); if (!currentTemplate) throw new Error("The template is no longer available."); await revisePostboxTemplate( settings, currentTemplate, revisionPayload(templateDraft) ); setSuccess("A new immutable template revision was created."); } else { await createPostboxTemplate(settings, { slug: templateDraft.slug, name: templateDraft.name, description: templateDraft.description || null, ...revisionPayload(templateDraft) }); setSuccess("Postbox template created as a draft."); } setTemplateBaseline(templateDraft); setTemplateDialogOpen(false); await load(); return true; } catch (actionError) { setError(errorMessage(actionError)); return false; } finally { setBusy(false); } } async function previewTemplate() { setTemplatePreviewLoading(true); setError(""); try { const preview = await previewPostboxTemplate(settings, { slug: templateDraft.slug, name: templateDraft.name, description: templateDraft.description || null, ...revisionPayload(templateDraft), template_id: templateDraft.templateId || null, limit: 200 }); setTemplatePreview(preview); } catch (actionError) { setTemplatePreview(null); setError(errorMessage(actionError)); } finally { setTemplatePreviewLoading(false); } } async function publishSelected() { if (!selectedTemplate) return; setBusy(true); setError(""); setSuccess(""); try { await publishPostboxTemplate( settings, selectedTemplate, selectedTemplate.current_revision ); setSuccess(i18nMessage("i18n:govoplan-postbox.published_revision_message", { revision: selectedTemplate.current_revision })); await load(); } catch (actionError) { setError(errorMessage(actionError)); } finally { setBusy(false); } } function openExact() { const unit = units.find((item) => item.functions.length); const next = { ...exactDefaults(), organization_unit_id: unit?.id ?? "", function_id: unit?.functions[0]?.id ?? "" }; setExactDraft(next); setExactBaseline(next); setExactDialogOpen(true); } async function saveExact(): Promise { setBusy(true); setError(""); setSuccess(""); try { await createExactPostbox(settings, { ...exactDraft, description: exactDraft.description || null, address_key: exactDraft.address_key || null }); setExactBaseline(exactDraft); setExactDialogOpen(false); setSuccess("Exact function-bound Postbox created."); await load(); return true; } catch (actionError) { setError(errorMessage(actionError)); return false; } finally { setBusy(false); } } function openProtectionTransition() { if (!selectedPostbox) return; const next = protectionTransitionDefaults(selectedPostbox); setProtectionDraft(next); setProtectionBaseline(next); setProtectionDialogOpen(true); } async function saveProtectionTransition(): Promise { if (!selectedPostbox) return false; setBusy(true); setError(""); setSuccess(""); try { const transition = await createPostboxProtectionTransition( settings, selectedPostbox, { idempotency_key: crypto.randomUUID(), target_profile: protectionDraft.target_profile, target_vault_id: protectionDraft.target_profile === "server_envelope_v1" ? protectionDraft.target_vault_id.trim() || null : null, history_mode: protectionDraft.history_mode, authority_mode: protectionDraft.authority_mode, required_quorum: protectionDraft.required_quorum, user_consent_refs: lineSeparated(protectionDraft.user_consent_refs), institutional_authorization_refs: lineSeparated( protectionDraft.institutional_authorization_refs ), reason: protectionDraft.reason.trim(), acknowledge_irreversibility: protectionDraft.acknowledge_irreversibility } ); setProtectionTransitions((current) => [ transition, ...current.filter((item) => item.id !== transition.id) ]); setProtectionBaseline(protectionDraft); setProtectionDialogOpen(false); setSuccess( transition.state === "completed" ? "Postbox protection profile changed and historical content migration completed." : "Postbox protection profile changed for new messages. Historical content is awaiting approved client transformations." ); await load(); return true; } catch (actionError) { setError(errorMessage(actionError)); return false; } finally { setBusy(false); } } function openProtectionPolicy() { if (!selectedPostbox) return; const next = selectedPostbox.protection_policy || protectionPolicyDefaults(); setPolicyDraft(next); setPolicyBaseline(next); setPolicyDialogOpen(true); } async function saveProtectionPolicy(): Promise { if (!selectedPostbox) return false; setBusy(true); setError(""); setSuccess(""); try { await updatePostboxProtectionPolicy(settings, selectedPostbox, policyDraft); setPolicyBaseline(policyDraft); setPolicyDialogOpen(false); setSuccess("Postbox protection and hand-over policy updated."); await load(); return true; } catch (actionError) { setError(errorMessage(actionError)); return false; } finally { setBusy(false); } } function openGroupingPolicy() { if (!selectedPostbox) return; const next = selectedPostbox.grouping_policy || groupingPolicyDefaults(); setGroupingPolicyDraft(next); setGroupingPolicyBaseline(next); setGroupingPolicyDialogOpen(true); } async function saveGroupingPolicy(): Promise { if (!selectedPostbox) return false; setBusy(true); setError(""); setSuccess(""); try { await updatePostboxGroupingPolicy( settings, selectedPostbox, groupingPolicyDraft ); setGroupingPolicyBaseline(groupingPolicyDraft); setGroupingPolicyDialogOpen(false); setSuccess("Unified-inbox separation policy updated."); await load(); return true; } catch (actionError) { setError(errorMessage(actionError)); return false; } finally { setBusy(false); } } function openMaterialize(template: PostboxTemplate) { const revision = currentRevision(template); const compatible = compatibleTargets(units, revision?.function_type_id); const unit = compatible[0]; const next = { templateId: template.id, organization_unit_id: unit?.id ?? "", function_id: unit?.functions[0]?.id ?? "", context_key: "" }; setMaterializeDraft(next); setMaterializeBaseline(next); setMaterializeDialogOpen(true); } async function materialize(): Promise { setBusy(true); setError(""); setSuccess(""); try { await materializePostboxTemplate(settings, materializeDraft.templateId, { organization_unit_id: materializeDraft.organization_unit_id, function_id: materializeDraft.function_id, context_key: materializeDraft.context_key || null }); setMaterializeBaseline(materializeDraft); setMaterializeDialogOpen(false); setSuccess("Stable Postbox address resolved and materialized."); await load(); return true; } catch (actionError) { setError(errorMessage(actionError)); return false; } finally { setBusy(false); } } async function confirmArchive() { if (!archiveTarget) return; setBusy(true); setError(""); setSuccess(""); try { await archivePostbox(settings, archiveTarget); setSuccess("Postbox archived. Messages and delivery evidence were retained."); setArchiveTarget(null); await load(); } catch (actionError) { setError(errorMessage(actionError)); } finally { setBusy(false); } } async function confirmRetire() { if (!retireTarget) return; setSelectedTemplateId(retireTarget.id); setBusy(true); setError(""); setSuccess(""); try { await retirePostboxTemplate(settings, retireTarget); setSuccess("Postbox template retired. Existing addresses remain durable."); setRetireTarget(null); await load(); } catch (actionError) { setError(errorMessage(actionError)); } finally { setBusy(false); } } function saveActiveDraft(): Promise { if (templateDirty) return saveTemplate(); if (exactDirty) return saveExact(); if (materializeDirty) return materialize(); if (protectionDirty) return saveProtectionTransition(); if (policyDirty) return saveProtectionPolicy(); if (groupingPolicyDirty) return saveGroupingPolicy(); return Promise.resolve(true); } function discardAdminDraft() { if (templateDialogOpen) { setTemplateDraft(templateBaseline); setTemplateDialogOpen(false); } if (exactDialogOpen) { setExactDraft(exactBaseline); setExactDialogOpen(false); } if (materializeDialogOpen) { setMaterializeDraft(materializeBaseline); setMaterializeDialogOpen(false); } if (protectionDialogOpen) { setProtectionDraft(protectionBaseline); setProtectionDialogOpen(false); } if (policyDialogOpen) { setPolicyDraft(policyBaseline); setPolicyDialogOpen(false); } if (groupingPolicyDialogOpen) { setGroupingPolicyDraft(groupingPolicyBaseline); setGroupingPolicyDialogOpen(false); } } function closeTemplateDialog() { const close = () => { setTemplateDraft(templateBaseline); setTemplateDialogOpen(false); }; if (templateDirty) requestDiscard(close); else close(); } function closeExactDialog() { const close = () => { setExactDraft(exactBaseline); setExactDialogOpen(false); }; if (exactDirty) requestDiscard(close); else close(); } function closeMaterializeDialog() { const close = () => { setMaterializeDraft(materializeBaseline); setMaterializeDialogOpen(false); }; if (materializeDirty) requestDiscard(close); else close(); } function closeProtectionDialog() { const close = () => { setProtectionDraft(protectionBaseline); setProtectionDialogOpen(false); }; if (protectionDirty) requestDiscard(close); else close(); } function closePolicyDialog() { const close = () => { setPolicyDraft(policyBaseline); setPolicyDialogOpen(false); }; if (policyDirty) requestDiscard(close); else close(); } function closeGroupingPolicyDialog() { const close = () => { setGroupingPolicyDraft(groupingPolicyBaseline); setGroupingPolicyDialogOpen(false); }; if (groupingPolicyDirty) requestDiscard(close); else close(); } return ( } onClick={() => requestDiscard(() => void load())} disabled={loading || busy} disabledReason={postboxBusyReason(loading, busy)} /> {mode === "templates" && canManageTemplates ? ( ) : null} {mode === "postboxes" && canManageBindings ? ( ) : null} } > setMode(value as AdminMode)} options={[ ...(canManageTemplates ? [{ id: "templates", label: "Templates" }] : []), ...(canManageBindings ? [{ id: "postboxes", label: "Postboxes" }] : []) ]} ariaLabel="Postbox administration section" /> {mode === "postboxes" && !units.some((unit) => unit.functions.length) ? ( ) : null} {mode === "templates" ? ( void publishSelected()} onRetire={() => selectedTemplate && setRetireTarget(selectedTemplate)} onMaterialize={openMaterialize} busy={busy} canManageBindings={canManageBindings} /> ) : ( )} { setTemplateDraft(draft); setTemplatePreview(null); }} onPreview={() => void previewTemplate()} onClose={closeTemplateDialog} onSave={() => void saveTemplate()} /> void saveExact()} /> item.id === materializeDraft.templateId) ?? null} units={units} busy={busy} onChange={setMaterializeDraft} onClose={closeMaterializeDialog} onSave={() => void materialize()} /> void saveProtectionTransition()} /> void saveProtectionPolicy()} /> void saveGroupingPolicy()} /> void confirmArchive()} onCancel={() => setArchiveTarget(null)} /> void confirmRetire()} onCancel={() => setRetireTarget(null)} /> ); } function TemplateWorkspace({ templates, selected, onSelect, onRevise, onPublish, onRetire, onMaterialize, busy, canManageBindings }: { templates: PostboxTemplate[]; selected: PostboxTemplate | null; onSelect: (id: string) => void; onRevise: (template: PostboxTemplate) => void; onPublish: () => void; onRetire: () => void; onMaterialize: (template: PostboxTemplate) => void; busy: boolean; canManageBindings: boolean; }) { const revision = selected ? currentRevision(selected) : null; return (
{selected && revision ? ( <>
Template

{selected.name}

{selected.description || "No description."}

{canManageBindings ? ( ) : null}
Revision
{revision.revision}{revision.published_at ? " · Published" : " · Draft"}
Function type
{revision.function_type_id || "Any function type"}
Scope
{revision.scope_kind}{revision.scope_id ? ` · ${revision.scope_id}` : ""}
Classification
{revision.classification}
Vacant delivery
{revision.allow_vacant_delivery ? "Accepted" : "Blocked"}
Hierarchy copies
{revision.routing_policy.linked_copy.enabled ? i18nMessage("i18n:govoplan-postbox.depth_label", { fanout: revision.routing_policy.linked_copy.fanout, depth: revision.routing_policy.linked_copy.max_depth }) : "Disabled"}
Vacancy escalation
{revision.routing_policy.attention.mode === "vacancy_escalation" ? i18nMessage("i18n:govoplan-postbox.minutes_label", { minutes: revision.routing_policy.attention.delay_minutes }) : "Disabled"}
Encryption
{revision.encryption_profile}
Name pattern
{revision.name_pattern}
Address pattern
{revision.address_pattern}

Immutable revisions

{selected.revisions.map((item) => (
{i18nMessage("i18n:govoplan-postbox.revision_label", { revision: item.revision })} {item.classification} · {item.scope_kind}
))}
) : ( } title="Select a template" description="Published revisions lazily resolve stable unit-specific addresses." /> )}
); } function PostboxWorkspace({ postboxes, selected, transitions, onSelect, onChangeProtection, onEditPolicy, onEditGroupingPolicy, onArchive, busy }: { postboxes: PostboxDirectoryItem[]; selected: PostboxDirectoryItem | null; transitions: PostboxProtectionTransition[]; onSelect: (id: string) => void; onChangeProtection: () => void; onEditPolicy: () => void; onEditGroupingPolicy: () => void; onArchive: (postbox: PostboxDirectoryItem) => void; busy: boolean; }) { return (
{selected ? ( <>
Postbox

{selected.name}

{selected.address}

Organization unit
{selected.organization_unit_name || "None"}
Function
{selected.function_name || "None"}
Address key
{selected.address_key}
Classification
{selected.classification}
Current holders
{selected.holder_count}
Vacancy
{selected.vacant ? "Vacant" : "Staffed"}
Context
{selected.context_key || "None"}
Template revision
{selected.template_revision_id || "Exact Postbox"}
Protection
{protectionProfileLabel(selected.encryption_profile)}
Key epoch
{selected.key_epoch}
New incumbent history
{selected.protection_policy.new_incumbent_history.replaceAll("_", " ")}
External recipient assurance
{selected.protection_policy.external_recipient_assurance.replaceAll("_", " ")}
Unified-inbox policy
{selected.grouping_policy.mode.replaceAll("_", " ")}
{transitions.length ? (

Protection transitions

{transitions.slice(0, 5).map((transition) => (
{protectionProfileLabel(transition.target_profile)} {transition.history_mode.replaceAll("_", " ")} · {transition.completed_count}/{transition.message_count} messages
))}
) : null} ) : ( } title="Select a Postbox" description="Materialized Postboxes remain durable through vacancy and reassignment." /> )}
); } function TemplateDialog({ open, draft, units, structures, templates, protectionProfiles, functionTypes, unitTypes, busy, preview, previewLoading, onChange, onPreview, onClose, onSave }: { open: boolean; draft: TemplateDraft; units: PostboxOrganizationUnit[]; structures: PostboxOrganizationStructure[]; templates: PostboxTemplate[]; protectionProfiles: PostboxProtectionProfile[]; functionTypes: Array<{ id: string; name: string }>; unitTypes: Array<{ id: string; example: string }>; busy: boolean; preview: PostboxTemplatePreview | null; previewLoading: boolean; onChange: (draft: TemplateDraft) => void; onPreview: () => void; onClose: () => void; onSave: () => void; }) { const isRevision = Boolean(draft.templateId); const scopeOptions = draft.scope_kind === "unit_type" ? unitTypes.map((item) => ({ id: item.id, label: `${item.id} (${item.example})` })) : units.map((unit) => ({ id: unit.id, label: unit.name })); const linkedCopy = draft.routing_policy.linked_copy; const attention = draft.routing_policy.attention; const selectedScopeStructure = structures.find( (item) => item.id === draft.scope_structure_id ); const selectedStructure = structures.find( (item) => item.id === linkedCopy.structure_id ); const selectedProtectionProfile = protectionProfiles.find( (item) => item.id === draft.encryption_profile ); const updateRouting = (routing_policy: PostboxRoutingPolicy) => { onChange({ ...draft, routing_policy }); }; const updateLinkedCopy = ( next: Partial ) => { updateRouting({ ...draft.routing_policy, linked_copy: { ...linkedCopy, ...next } }); }; const valid = draft.name.trim() && draft.slug.trim() && draft.name_pattern.trim() && draft.address_pattern.trim() && (draft.scope_kind === "tenant" || Boolean(draft.scope_id)) && (draft.scope_kind !== "subtree" || Boolean(draft.scope_structure_id)) && selectedProtectionProfile?.available && (draft.encryption_profile !== "server_envelope_v1" || Boolean(draft.encryption_vault_id?.trim())) && ( !linkedCopy.enabled || Boolean( linkedCopy.structure_id && linkedCopy.target_function_type_id && linkedCopy.target_template_id && linkedCopy.allowed_classifications.length && linkedCopy.allowed_producer_modules.length ) ); return ( } > onChange({ ...draft, name: event.target.value })} /> onChange({ ...draft, slug: event.target.value })} /> onChange({ ...draft, description: event.target.value })} /> {draft.scope_kind !== "tenant" ? ( ) :
} {draft.scope_kind === "subtree" ? ( <>
{(selectedScopeStructure?.relation_types || []) .filter((item) => item.status === "active" && item.is_hierarchical) .map((item) => ( ))} {selectedScopeStructure && !selectedScopeStructure.relation_types.some( (item) => item.status === "active" && item.is_hierarchical ) ? No active hierarchical relation type. : null} {!selectedScopeStructure ? All active hierarchical relations are used unless specific types are selected. : null}
) : null} onChange({ ...draft, name_pattern: event.target.value })} /> onChange({ ...draft, address_pattern: event.target.value })} /> onChange({ ...draft, classification: event.target.value })} />
onChange({ ...draft, allow_vacant_delivery: checked })} />
onChange({ ...draft, portal_visible: checked })} />
onChange({ ...draft, encryption_profile, encryption_vault_id: encryption_profile === "server_envelope_v1" ? draft.encryption_vault_id : null })} onVaultChange={(encryption_vault_id) => onChange({ ...draft, encryption_vault_id })} onPolicyChange={(protection_policy) => onChange({ ...draft, protection_policy })} /> onChange({ ...draft, grouping_policy })} />
Hierarchy linked copies Copy to explicitly bounded function Postboxes in one selected structure.
updateLinkedCopy({ enabled, allowed_classifications: linkedCopy.allowed_classifications.length ? linkedCopy.allowed_classifications : [draft.classification] })} />
{linkedCopy.enabled ? ( updateLinkedCopy({ max_depth: Math.max(1, Math.min(20, Number(event.target.value) || 1)) })} /> updateLinkedCopy({ allowed_classifications: commaSeparated(event.target.value) })} /> updateLinkedCopy({ allowed_producer_modules: commaSeparated(event.target.value) })} />
updateLinkedCopy({ require_expiry })} />
updateLinkedCopy({ max_retention_days: event.target.value ? Math.max(1, Math.min(36500, Number(event.target.value))) : null })} />
updateRouting({ ...draft.routing_policy, attention: checked ? { mode: "vacancy_escalation", delay_minutes: attention.delay_minutes || 1440 } : { mode: "none", delay_minutes: null } })} />
{attention.mode === "vacancy_escalation" ? ( updateRouting({ ...draft.routing_policy, attention: { mode: "vacancy_escalation", delay_minutes: Math.max( 1, Math.min(43200, Number(event.target.value) || 1) ) } })} /> ) :
} ) : null}
{preview ? : null}

Available pattern variables include template, unit, function, and optional context names or slugs. Published revisions are immutable.

); } function TemplateImpactPreview({ preview }: { preview: PostboxTemplatePreview; }) { return (
Dry-run impact No Postboxes or addresses were created.
{preview.truncated ? : null}
{preview.diagnostics.length ? (

{preview.diagnostics.join(", ")}

) : null}
{preview.targets.map((target) => (
{target.name} {target.organization_unit_name} · {target.function_name} {target.address} {target.diagnostics.length ? ( {target.diagnostics.join(", ")} ) : null}
{target.holder_count} holder{target.holder_count === 1 ? "" : "s"}
))} {!preview.targets.length ? (

The scope contains no matching active function.

) : null}
); } function ExactPostboxDialog({ open, draft, units, protectionProfiles, busy, onChange, onClose, onSave }: { open: boolean; draft: ExactDraft; units: PostboxOrganizationUnit[]; protectionProfiles: PostboxProtectionProfile[]; busy: boolean; onChange: (draft: ExactDraft) => void; onClose: () => void; onSave: () => void; }) { const unit = units.find((item) => item.id === draft.organization_unit_id); const selectedProtectionProfile = protectionProfiles.find( (item) => item.id === draft.encryption_profile ); const valid = Boolean( draft.name.trim() && draft.organization_unit_id && draft.function_id && selectedProtectionProfile?.available && ( draft.encryption_profile !== "server_envelope_v1" || draft.encryption_vault_id?.trim() ) ); return ( } > onChange({ ...draft, name: event.target.value })} /> onChange({ ...draft, address_key: event.target.value })} /> onChange({ ...draft, classification: event.target.value })} /> onChange({ ...draft, description: event.target.value })} />
onChange({ ...draft, portal_visible: checked })} />
onChange({ ...draft, encryption_profile, encryption_vault_id: encryption_profile === "server_envelope_v1" ? draft.encryption_vault_id : null })} onVaultChange={(encryption_vault_id) => onChange({ ...draft, encryption_vault_id })} onPolicyChange={(protection_policy) => onChange({ ...draft, protection_policy })} /> onChange({ ...draft, grouping_policy })} />
); } function ProtectionConfigurationFields({ profile, vaultId, policy, profiles, profileLocked = false, onProfileChange, onVaultChange, onPolicyChange }: { profile: PostboxProtectionProfileId; vaultId: string; policy: PostboxProtectionPolicy; profiles: PostboxProtectionProfile[]; profileLocked?: boolean; onProfileChange: (profile: PostboxProtectionProfileId) => void; onVaultChange: (vaultId: string) => void; onPolicyChange: (policy: PostboxProtectionPolicy) => void; }) { const selected = profiles.find((item) => item.id === profile); const updatePolicy = (next: Partial) => { onPolicyChange({ ...policy, ...next }); }; return (
Content protection and hand-over policy The institution chooses the protection boundary. Managed envelope encryption is the recommended standard.
{selected?.standard ? : null}
{selected?.description} {profile === "server_envelope_v1" ? ( onVaultChange(event.target.value)} /> ) : (
{profile === "external_e2ee_v1" ? "An approved external client or producer must supply ciphertext, a signed manifest, wrapped keys, and a digest. GovOPlaN cannot decrypt message content." : "Content is stored without encryption. Transport and infrastructure controls still apply."}
)} {policy.new_incumbent_history === "bounded_days" ? ( updatePolicy({ history_days: Math.max(1, Math.min(36500, Number(event.target.value) || 1)) })} /> ) :
} updatePolicy({ recovery_authority })} /> updatePolicy({ recovery_quorum })} /> updatePolicy({ handover_authority: handover_authority as PostboxProtectionPolicy["handover_authority"] })} /> updatePolicy({ handover_quorum })} /> updatePolicy({ emergency_quorum })} /> updatePolicy({ export_authority: export_authority as PostboxProtectionPolicy["export_authority"] })} /> updatePolicy({ export_quorum })} /> updatePolicy({ destruction_quorum })} />
); } function AuthorityField({ label, value, includeDisabled = false, onChange }: { label: string; value: "disabled" | "user_consent" | "institutional_key_holders" | "dual_control"; includeDisabled?: boolean; onChange: (value: "disabled" | "user_consent" | "institutional_key_holders" | "dual_control") => void; }) { return ( ); } function GroupingPolicyFields({ policy, onChange }: { policy: PostboxGroupingPolicy; onChange: (policy: PostboxGroupingPolicy) => void; }) { return (
Unified-inbox separation Keep source containers and institutional responsibilities visibly separated where required.
onChange({ ...policy, reason: event.target.value || null })} />
); } function QuorumField({ label, value, onChange }: { label: string; value: number; onChange: (value: number) => void; }) { return ( onChange(Math.max(1, Math.min(20, Number(event.target.value) || 1)))} /> ); } function ProtectionPolicyDialog({ open, postbox, draft, profiles, busy, onChange, onClose, onSave }: { open: boolean; postbox: PostboxDirectoryItem | null; draft: PostboxProtectionPolicy; profiles: PostboxProtectionProfile[]; busy: boolean; onChange: (policy: PostboxProtectionPolicy) => void; onClose: () => void; onSave: () => void; }) { return (
} > {postbox ? ( undefined} onVaultChange={() => undefined} onPolicyChange={onChange} /> ) : null}

Changing this policy affects future access and governance decisions. It does not change the content-protection profile or rewrite retained messages.

); } function GroupingPolicyDialog({ open, postbox, draft, busy, onChange, onClose, onSave }: { open: boolean; postbox: PostboxDirectoryItem | null; draft: PostboxGroupingPolicy; busy: boolean; onChange: (policy: PostboxGroupingPolicy) => void; onClose: () => void; onSave: () => void; }) { return ( } >

The rule is evaluated whenever a personal grouping or aggregate message projection is used. Existing preferences are retained, but a newly enforced rule prevents an unsafe combined projection and explains its configured source.

); } function ProtectionTransitionDialog({ open, postbox, draft, profiles, busy, onChange, onClose, onSave }: { open: boolean; postbox: PostboxDirectoryItem | null; draft: ProtectionTransitionDraft; profiles: PostboxProtectionProfile[]; busy: boolean; onChange: (draft: ProtectionTransitionDraft) => void; onClose: () => void; onSave: () => void; }) { const selected = profiles.find((item) => item.id === draft.target_profile); const userEvidence = lineSeparated(draft.user_consent_refs); const institutionalEvidence = lineSeparated(draft.institutional_authorization_refs); const evidenceCount = new Set([...userEvidence, ...institutionalEvidence]).size; const requiresUser = ["user_consent", "dual_control"].includes(draft.authority_mode); const requiresInstitution = ["institutional_key_holders", "dual_control"].includes( draft.authority_mode ); const configuredAuthority = postbox?.protection_policy?.handover_authority || "dual_control"; const authoritySatisfiesPolicy = configuredAuthority === "dual_control" ? draft.authority_mode === "dual_control" : configuredAuthority === "user_consent" ? ["user_consent", "dual_control"].includes(draft.authority_mode) : ["institutional_key_holders", "dual_control"].includes(draft.authority_mode); const authoritySatisfiesSource = postbox?.encryption_profile === "external_e2ee_v1" ? ["user_consent", "dual_control"].includes(draft.authority_mode) : postbox?.encryption_profile === "server_envelope_v1" ? ["institutional_key_holders", "dual_control"].includes(draft.authority_mode) : true; const valid = Boolean( postbox && selected?.available && draft.target_profile !== postbox.encryption_profile && (draft.target_profile !== "server_envelope_v1" || draft.target_vault_id.trim()) && draft.reason.trim() && draft.acknowledge_irreversibility && evidenceCount >= draft.required_quorum && (!requiresUser || userEvidence.length) && (!requiresInstitution || institutionalEvidence.length) && (draft.authority_mode !== "dual_control" || draft.required_quorum >= 2) && authoritySatisfiesPolicy && authoritySatisfiesSource && draft.required_quorum >= (postbox?.protection_policy?.handover_quorum || 1) ); return ( } >

New messages switch immediately. Historical migration is separately tracked so interrupted work is visible and resumable.

{selected?.description} {draft.target_profile === "server_envelope_v1" ? ( onChange({ ...draft, target_vault_id: event.target.value })} /> ) :
} onChange({ ...draft, required_quorum })} />