From f81fb4e7696e9fdf21d671e7aa78f0510698e5aa Mon Sep 17 00:00:00 2001 From: ZDDC Date: Thu, 7 May 2026 09:30:31 -0500 Subject: [PATCH] docs: canonical folder layout, role-based ACL, WORM, lazy creation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update reference.html § 9 (transmittal workflow): replace the legacy per-party tree (project/{party-name}/{incoming,received,issued}) with the current canonical layout — project root has working/, staging/, reviewing/, archive/, and per-party folders sit under archive//{mdl,incoming,received,issued}/. Note lazy creation, case-fold matching, the per-user virtual / entry, mdl opening the table editor, and the staging↔working drafting mirror. Add a "Drafting a response transmittal" subsection describing how inbound submittals (-SUB- @ IFR/IFA) flow through staging→working into archive//issued/ as RS* responses. Update index.html "Access control via .zddc files" bullet to describe what the server actually does today: cascade direction, the five verbs (r/w/c/d/a), explicit deny via empty grant, and the X-Auth-Request-Email convention. Add new bullets for roles (with a short YAML example), WORM archive folders + drop-in producer pattern, lazy folder creation + case-fold matching, the cascade tracer admin endpoint, and an expanded OPA paragraph (input shape, cache TTL, fail-open flag, --print-rego=federal). Update the install card's tool-folder list to use lowercase canonical names, mention browse, and add mdl.table.html as the per-party MDL view. Co-Authored-By: Claude Opus 4.7 (1M context) --- index.html | 26 +++++++++++++++++++------ reference.html | 52 ++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/index.html b/index.html index 52d4a14..ebabf23 100644 --- a/index.html +++ b/index.html @@ -175,9 +175,21 @@

zddc-server is a small Go binary purpose-built to serve ZDDC archives. Any web server gives you online mode; zddc-server adds things a generic web server can't:

    -
  • Access control via .zddc files. Behind a reverse proxy that authenticates users and sets an X-Auth-Request-Email request header, zddc-server consults YAML .zddc files in directories — cascading bottom-up; deeper rules override. Common shapes (paired open/closed projects + third-party-restricted vendor folders) are documented with worked examples in the access-control reference. No database, no admin UI.
  • -
  • OPA-compatible policy decider. Federal and other regulated customers can swap the built-in evaluator for an external Open Policy Agent server with their own audited Rego policies — set ZDDC_OPA_URL and the same .zddc files become inputs to your engine instead of ours. Wire format is OPA-canonical (POST /v1/data/zddc/access/allow). Default mode adds zero new dependencies; external mode is a configuration flip.
  • +
  • Access control via .zddc files. Behind a reverse proxy that authenticates users and sets an X-Auth-Request-Email request header, zddc-server consults YAML .zddc files at every directory along the path. The cascade walks root→leaf; the closest match wins. Five verbs (r read, w overwrite, c create, d delete, a admin / edit ACL) gate every operation. An empty grant (e.g. "*@vendor.com": "") is an explicit deny. Common shapes (paired open/closed projects, third-party-restricted vendor folders) are documented with worked examples in the access-control reference. No database, no admin UI.
  • +
  • Roles for human-readable grants. A .zddc may declare named roles whose members are email patterns; permissions then reference the role name instead of pasting the same wildcard everywhere: +
    roles:
    +  qc-reviewers:
    +    members: ["*@quality.org", "alice@example.com"]
    +acl:
    +  permissions:
    +    qc-reviewers: rwd
    +    "*@example.com": r
    +Role definitions cascade like everything else; a child .zddc redefining the same role name shadows the ancestor for that subtree.
  • +
  • WORM archive folders. Anything under archive/<party>/issued/ or archive/<party>/received/ enforces write-once via a verb mask: ancestor grants are reduced to r only, while a .zddc placed at the WORM folder itself can still grant rc (create-but-not-overwrite) to specific principals — that's how a doc controller drops a fresh transmittal into the immutable record. Root admins (the admins: list in the root .zddc) bypass the mask as the deliberate escape hatch for mis-filed documents.
  • +
  • Lazy folder creation, case-fold matching. Drop a .zddc file into an empty directory and the canonical project layout (working/, staging/, archive/<party>/{mdl,incoming,received,issued}/) materialises on the first write into each path — never on bare reads. Folder names are matched case-insensitively, so an existing Working/ is reused rather than shadowed by a new working/ sibling. Each authenticated viewer sees a virtual working/<your-email>/ entry; first write makes it real.
  • +
  • OPA-compatible policy decider. Federal and other regulated customers can swap the built-in evaluator for an external Open Policy Agent server with their own audited Rego policies — set ZDDC_OPA_URL and the server POSTs the request's user, path, action, and the full .zddc cascade chain to /v1/data/zddc/access/allow. Decisions are cached per (user, path, action) with a configurable TTL (ZDDC_OPA_CACHE_TTL); failures fail closed by default (ZDDC_OPA_FAIL_OPEN=1 flips it). The bundled NIST AC-6 strict-cascade preset is dumpable via --print-rego=federal. Default mode adds zero new dependencies; external mode is a configuration flip.
  • Designed for regulated environments. Hardened TLS (NIST SP 800-52 Rev. 2 cipher allowlist + HSTS), pluggable policy engine, federal-mode strict-least-privilege Rego shipping out of the box, structured audit logging, documented vulnerability-disclosure process. Specific federal-track work (FIPS-validated build, signed-token proxy↔server channel, code-signed tool fetches) is on a clear roadmap — see the federal compliance page for the supported deployment shape and what an integrator adds during ATO.
  • +
  • Cascade tracer for operators. Admins can hit /.profile/effective-policy?path=<url> to see the resolved ACL chain at any path — every level's grants, the role evaluation, the final verb-set. Useful when a permission isn't behaving the way the operator expected.
  • Virtual .archive URL space. GET /Project/.archive/123-XYZ.html resolves to the canonical revision file at request time. Computed from filenames; no cache, no separate index file.
  • Per-request access logging keyed to the authenticated user; conservative HTTP timeouts; optional file-tee for offline audit (production deployments typically leave logs on stdout for the orchestrator's pipeline to handle).
  • TLS, ETags, conditional GET, CORS, autoindex. The mundane glue.
  • @@ -197,12 +209,14 @@

    Server: just run zddc-server

    The binary has the current-stable build of all five tools baked in at compile time. They appear automatically at the right paths under ZDDC_ROOT:

      -
    • archive.html at every level (root, project, archive, vendor)
    • -
    • classifier.html in any Incoming, Working, or Staging directory and its subtree
    • -
    • mdedit.html in any Working directory and its subtree
    • -
    • transmittal.html in any Staging directory and its subtree
    • +
    • archive.html and browse.html at every level (root, project, archive, party)
    • +
    • mdedit.html in any working/ directory and its subtree
    • +
    • transmittal.html in any staging/ directory and its subtree
    • +
    • classifier.html in any working/, staging/, or archive/<party>/incoming/ subtree
    • +
    • mdl.table.html at every archive/<party>/ — the per-party Master Deliverables List, served from a built-in default schema unless the party's .zddc declares a custom one
    • index.html (the project picker) at the deployment root
    +

    Folder names are case-insensitive — Working/, working/, and WORKING/ all match the working/ rule.

    ZDDC_ROOT=/srv/zddc ./zddc-server

    To override a tool at any path: drop a real .html file there — that file wins over the baked-in version. To pin a different version, write an apps: entry in any .zddc file along the path:

    # <project>/.zddc
    diff --git a/reference.html b/reference.html
    index a001667..bf96489 100644
    --- a/reference.html
    +++ b/reference.html
    @@ -914,19 +914,46 @@ date   = 4DIGIT "-" 2DIGIT "-" 2DIGIT
             

    Search the deliverable's own tracking number across all transmittal folders in issued/ and received/. Every folder containing that number is part of its history: which package first carried it, what the response was, which resubmittal carried the revision, and what the final outcome was.

    - +
    -

    9. Transmittal workflow

    -

    Each third party (client, contractor, vendor, etc.) has a separate subfolder. All communication with that party lives in one place.

    +

    9. Project layout & transmittal workflow

    +

    A project is a directory containing a single .zddc file. The server materialises the canonical folders below on the first write into them — drop a .zddc in an empty directory, point zddc-server at it, and the layout comes to life as content arrives. Folder names are matched case-insensitively, so a manually-created Working/ is reused rather than shadowed by a new working/.

    project/ - {party-name}/ - incoming/ ← transmittals received from party, awaiting acceptance - received/ ← permanent record of accepted transmittals from party - issued/ ← your copies of transmittals sent to party + .zddc ← the only file an operator must create + working/ ← user-owned drafting workspace; mdedit + for markdown, browse for uploads. + Each authenticated user with access + sees a virtual <your-email>/ + subfolder; first write materialises it. + staging/ ← outbound-transmittal preparation. A + transmittal-named mkdir here also + creates a same-named drafting folder + under working/ as a sibling space. + reviewing/ ← virtual cross-reference of in-progress + review responses; never on disk. + Notes live in working/<rs-name>/. + archive/ ← formal record of issued/received + transmittals, organised by party. + {party-name}/ ← one per counterparty AND one for + ourselves; self-folder is symmetric. + mdl/ ← Master Deliverables List for that + party. Visiting the folder opens the + table editor (mdl.table.html). + Default schema is built into the + server; per-party overrides via a + tables: { mdl: ./mdl.table.yaml } + entry in the party's .zddc. + incoming/ ← that party's drop point. Auto-own + .zddc grants the creator of each new + subfolder full control. + received/ ← permanent record of incoming we've + accepted (WORM — write-once read-many). + issued/ ← permanent record of what we sent to + that party (WORM).
    -

    5-step workflow:

    +

    5-step transmittal workflow:

    @@ -974,6 +1001,15 @@ project/

    What SHA-256 gives you: Mathematical fingerprint of file contents. Single byte change → hash changes. When acknowledgment records hashes, you can verify years later that the file is identical to what was transmitted.

    + +

    Drafting a response transmittal

    +

    Submittals from counterparties (tracking numbers containing -SUB- at status IFR or IFA) require a response transmittal whose status starts with RS (RSA, RSB, RSC, …). The drafting flow uses the same staging↔working pairing as a fresh outbound:

    +
      +
    1. Create staging/<YYYY-MM-DD>_<tracking> (RSA) - <title>/. The date is the planned issue (response-due) date.
    2. +
    3. The server mirrors the folder name into working/; reviewer notes and the response payload are drafted there.
    4. +
    5. The reviewing/ virtual surface lists each in-progress response paired with the source submittal in archive/<party>/received/.
    6. +
    7. When the response is ready, files move from working/ into staging/ for sign-off, then through the standard 5-step transmittal flow into archive/<party>/issued/. Both the staging and working folders are deleted at issue time.
    8. +