ZDDC/zddc/internal/handler/default-ssr.form.yaml
ZDDC 73e34bed5e feat: per-party RSK + project-level SSR/MDL/RSK rollup tables
Adds the risk register as a sibling of MDL under archive/<party>/, and
three project-level virtual aggregations at <project>/{ssr,mdl,rsk}:

  - SSR aggregates archive/<party>/ssr.yaml; "+ Add row" materializes a
    new party folder (mkdir + auto-own .zddc + ssr.yaml). Renames go
    through X-ZDDC-Op: ssr-rename, which os.Rename's the party
    directory so every row inside follows. Party name doubles as the
    folder name (no opaque IDs) and is path-derived on read.

  - MDL/RSK rollups list every deliverable / every risk across all
    parties with a derived `party` column; "+ Add row" is suppressed
    because party affiliation is ambiguous in the aggregate view.

All four virtual roots are declared `virtual: true` in
defaults.zddc.yaml. Spec/form bytes come from six new embedded
defaults (default-rsk.*, default-ssr.*, default-project-{mdl,rsk}.*)
served via a generalized IsDefaultSpec/IsDefaultSpecAbs that replaces
the MDL-only recognizer. Listing synthesis lives in fs/tree.go;
ACL on each synthetic row evaluates against the canonical
archive/<party>/ chain so non-owners see rows read-only. PUT/DELETE
through virtual URLs rewrite to canonical paths in fileapi.go via
sibling-shape blocks that don't touch the ACL gate. SSR row DELETE
returns 405 (delete the party folder via the archive view).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 21:47:56 -05:00

76 lines
2.4 KiB
YAML

# Default row schema for a Supplier / Subcontractor Status Report
# entry, served by zddc-server when no operator-supplied form.yaml
# exists at <project>/archive/<party>/ssr.form.yaml.
#
# The `name` field doubles as the party folder name (the row's
# stable identifier). It's required on create (+ Add row materializes
# <project>/archive/<name>/) but is stripped from the YAML on save —
# the folder name IS the identity, so storing it inside the file too
# would just be a denormalization. On read the dispatcher injects
# name back into the row data so this form (and the SSR table)
# can display it.
#
# Pattern excludes leading `.` and `_` to avoid colliding with
# fileapi.go's dot/underscore-prefix guards on file paths.
#
# To customize: drop your own form.yaml into
# <project>/archive/<party>/ (sibling to the party's ssr.yaml).
title: Supplier / Subcontractor Status
description: One party's status report. The party name doubles as the archive folder name and is required when creating a new row.
schema:
type: object
required: [name, vendorType, contractNo, scopeSummary]
additionalProperties: false
properties:
name:
type: string
title: Party (folder name)
description: Becomes <project>/archive/<name>/. Typical naming = MasterFormat 4-digit code + C|P + sequence digit (e.g. 0330C1).
pattern: "^[A-Za-z0-9][A-Za-z0-9.-]*$"
minLength: 1
vendorType:
type: string
title: Vendor type
enum: [subcontractor, supplier, consultant, vendor, other]
contractNo:
type: string
title: Contract / PO number
scopeSummary:
type: string
title: Scope summary
contractValue:
type: number
title: Contract value
awardDate:
type: string
title: Award date
format: date
kickoffDate:
type: string
title: Kickoff date
format: date
scheduleStatus:
type: string
title: Schedule status
enum: [on-track, at-risk, behind, completed, on-hold]
deliverablesStatus:
type: string
title: Deliverables status
enum: [on-track, at-risk, behind, completed]
paymentStatus:
type: string
title: Payment status
enum: [current, overdue, hold, complete]
ownerContact:
type: string
title: Owner contact (email)
notes:
type: string
title: Notes
ui:
scopeSummary:
ui:widget: textarea
notes:
ui:widget: textarea