Final consumer migration. The Go-coded lists that previously encoded
the ZDDC convention all defer to the .zddc cascade now.
Schema added:
available_tools: [tool1, tool2, ...] concat-union across cascade;
tools not in the union are
denied auto-route at that path
auto_own_fenced: true|false generated auto-own .zddc
carries inherit:false (private
to creator)
Lookups added:
AvailableToolsAt(root, dir) union of available_tools across cascade
IsToolAvailableAt(root, dir, tool)
AutoOwnFencedAt(root, dir) leaf-only
Cascade semantics finalised (per field):
default_tool → leaf→root walk (parent applies to descendants)
available_tools → leaf→root union (each level adds; baseline at root)
auto_own → leaf-only (creating THIS dir specifically)
auto_own_fenced → leaf-only (same)
virtual → leaf-only (THIS dir is virtual, not subtree)
Consumers migrated:
apps.DefaultAppAt → zddc.DefaultToolAt
apps.AppAvailableAt → zddc.IsToolAvailableAt (+ landing special)
EnsureCanonicalAncestors → AutoOwnAt + AutoOwnFencedAt
fs.ListDirectory empty-list fallback → zddc.IsDeclaredPath
fs.virtualCanonicalFolders → zddc.ChildrenDeclaredAt
dispatcher canonical-folder branches → unified into one
cascade-declared block
Hardcoded helpers REMOVED (dead code):
apps.inAncestorWithName
zddc.autoOwnDepthMatch / isAutoOwnDepthMatch
Hardcoded lists kept as data sources for the cascade walker but
no longer drive routing logic:
ProjectRootFolders / PartyFolders / AutoOwnCanonicalNames /
VirtualOnlyCanonicalNames / IsProjectRootFolder / IsArchivePartyFolder /
IsArchivePartyMdlDir — all still defined; only `ProjectRootFolders`
is used by special.go's IsProjectRootFolder. The rest are dead.
Dispatcher unified: the previously-two branches (per-party folder vs
project-root folder) collapse into one cascade-declared-path block
that handles the slash/no-slash convention uniformly:
- no-slash, default_tool=tables → ServeTable (default-MDL fallback)
- no-slash, default_tool set → apps.Serve(tool)
- no-slash, no default_tool → 302 to slash form
- slash, any → ServeDirectory empty-list fallback
The IsDir branch's switch also un-hardcoded — any cascade tool is
served (not just the legacy 3 names), so e.g. /Project/archive/<party>
/incoming (no slash) now serves classifier directly rather than 302'ing
to the slash form.
defaults.zddc.yaml populated with the canonical convention as the
recipe. Operators edit it (or override per-directory on disk) to
change any behaviour — no Go code changes required.
Browse drag-drop scope (working/staging/incoming) is the one remaining
client-side hardcoded regex; cascading that requires the cascade JSON
to be served to the client, which is its own Phase 4 piece.
Tests updated for the new no-slash mdl URL convention (landing MDL
card test) and no-slash stage URLs (nav strip test). All 248
Playwright + all Go tests green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
102 lines
4.3 KiB
YAML
102 lines
4.3 KiB
YAML
# defaults.zddc — embedded baseline configuration for every ZDDC
|
|
# deployment. Baked into the binary via //go:embed in defaults.go,
|
|
# loaded as the bottom-most level of the cascade. Operators override
|
|
# at the on-disk root /.zddc (or any deeper level); to ignore this
|
|
# file entirely, set `inherit: false` on an on-disk .zddc.
|
|
#
|
|
# To export an editable copy for an operator:
|
|
#
|
|
# zddc-server show-defaults > /var/lib/zddc/root/.zddc
|
|
#
|
|
# That places this file at the on-disk root, where the operator can
|
|
# edit it freely. The new file then takes the place of the embedded
|
|
# one (both contribute to the cascade, on-disk wins per-field).
|
|
|
|
title: "ZDDC"
|
|
|
|
# Empty acl at this layer — rules come from on-disk .zddc files above.
|
|
# A deployment with no on-disk root .zddc grants no access (consistent
|
|
# with prior behaviour); operators bootstrap by editing the root file.
|
|
acl:
|
|
permissions: {}
|
|
|
|
# Universal tool baseline. archive (record browser), browse (file
|
|
# tree), and landing (project picker) work everywhere. Each canonical
|
|
# folder below adds its own context-specific tools (mdedit in
|
|
# working/, transmittal in staging/, etc.). The cascade unions
|
|
# available_tools across all levels — leaf restrictions don't drop
|
|
# ancestor entries — so this baseline propagates to every descendant.
|
|
available_tools: [archive, browse, landing]
|
|
|
|
# ── Canonical project structure ────────────────────────────────────────────
|
|
#
|
|
# Every ZDDC project lives at a top-level directory. Under it the
|
|
# convention is four canonical folders: archive (formal record),
|
|
# working (in-progress workspace), staging (outbound prep), reviewing
|
|
# (purely virtual aggregator). Under archive/<party>/ the convention
|
|
# is four more: mdl (deliverables list), incoming (counterparty drop
|
|
# zone), received (immutable submittals), issued (immutable responses).
|
|
#
|
|
# All of this is expressed via the recursive paths: schema. None of
|
|
# the directories need to exist on disk — the cascade walker resolves
|
|
# behaviour from this declaration, so a fresh project lands on
|
|
# usable empty views at every well-known URL.
|
|
#
|
|
# Operators override any of this by mirroring the structure in an
|
|
# on-disk .zddc and changing what they need; on-disk values win.
|
|
|
|
paths:
|
|
# First segment under root is the project name; "*" matches any.
|
|
"*":
|
|
paths:
|
|
archive:
|
|
default_tool: archive
|
|
paths:
|
|
# Second segment under archive/ is the party name.
|
|
"*":
|
|
paths:
|
|
mdl:
|
|
default_tool: tables
|
|
available_tools: [tables]
|
|
# The mdl folder is virtual by convention — the
|
|
# tables tool serves it from the embedded default
|
|
# spec even when the on-disk folder doesn't exist.
|
|
virtual: true
|
|
incoming:
|
|
default_tool: classifier
|
|
available_tools: [classifier]
|
|
# First write into incoming/ auto-creates an owner
|
|
# grant so the creator can manage their own drops.
|
|
auto_own: true
|
|
received:
|
|
default_tool: archive
|
|
# received/ is WORM — express as ACL elsewhere; the
|
|
# default convention is simply "no auto_own here".
|
|
issued:
|
|
default_tool: archive
|
|
working:
|
|
default_tool: mdedit
|
|
available_tools: [mdedit, classifier]
|
|
# working/ auto-owns the first creator + the per-user homes
|
|
# below.
|
|
auto_own: true
|
|
paths:
|
|
"*": # per-user home dir
|
|
default_tool: mdedit
|
|
available_tools: [mdedit, classifier]
|
|
auto_own: true
|
|
# Per-user home is private by default: the generated
|
|
# auto-own .zddc carries inherit:false so ancestor ACL
|
|
# grants don't reach inside. The user can edit the file
|
|
# to grant collaborators access.
|
|
auto_own_fenced: true
|
|
staging:
|
|
default_tool: transmittal
|
|
available_tools: [transmittal, classifier]
|
|
auto_own: true
|
|
reviewing:
|
|
default_tool: mdedit
|
|
available_tools: [mdedit]
|
|
# reviewing/ is purely virtual — the aggregator handler
|
|
# synthesises listings from received/ ↔ staging/ ↔ issued/.
|
|
virtual: true
|