diff --git a/.config/dictionaries/project.dic b/.config/dictionaries/project.dic index 9bcf2c5498..200715c2ac 100644 --- a/.config/dictionaries/project.dic +++ b/.config/dictionaries/project.dic @@ -51,6 +51,7 @@ crontabs crontagged csprng cstring +cuelang dalek dashmap Datelike @@ -123,6 +124,7 @@ jorm jormungandr Jörmungandr jsonschema +Justfile kiduri lcov Leay @@ -141,6 +143,7 @@ logcall lookaside maindbname mapref +markdownlint mdlint mdns MEMMAP @@ -200,6 +203,7 @@ pubkey publickey pubspec pwrite +pytest qpsg quic rapidoc diff --git a/.gitignore b/.gitignore index e881c8d539..9f75a0f579 100644 --- a/.gitignore +++ b/.gitignore @@ -84,3 +84,7 @@ $RECYCLE.BIN/ # Dart stuff /pubspec.lock /.dart_tool/**/* + +# Python stuff +.pytest_cache +__pycache__ \ No newline at end of file diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc index e3852a9805..04934f5ab7 100644 --- a/.markdownlint-cli2.jsonc +++ b/.markdownlint-cli2.jsonc @@ -10,7 +10,8 @@ "ignores": [ ".config/dictionaries/**", "**/target/**", - "**/.dart_tool/**" + "**/.dart_tool/**", + "**/.pytest_cache/**" ], // Set standard config options in `/.markdownlint.jsonc` "config": { diff --git a/.vscode/extensions.json b/.vscode/extensions.json index fdc5b1d78d..b6cfac50c0 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -24,5 +24,8 @@ "dtsvet.vscode-wasm", "terrastruct.d2", "fill-labs.dependi", + "nefrob.vscode-just-syntax", + "charliermarsh.ruff", + "ms-python.python", ] } \ No newline at end of file diff --git a/Justfile b/Justfile index 33dd85054d..d632ca712e 100644 --- a/Justfile +++ b/Justfile @@ -15,6 +15,19 @@ check-spelling: earthly +check-spelling +# Fix and Check Markdown files +format-python-code: + ruff check --select I --fix . + ruff format . + +# Fix and Check Markdown files +lint-python: + ruff check . + +# generates specifications data +gen_specs: + just specs/pre-push + # Pre Push Checks - intended to be run by a git pre-push hook. -pre-push: check-markdown check-spelling +pre-push: gen_specs check-markdown check-spelling format-python-code lint-python just rust/pre-push diff --git a/docs/Earthfile b/docs/Earthfile index 15382b4739..94b1f21790 100644 --- a/docs/Earthfile +++ b/docs/Earthfile @@ -4,6 +4,7 @@ IMPORT github.com/input-output-hk/catalyst-ci/earthly/docs:v3.3.0 AS docs-ci IMPORT .. AS repo +IMPORT ../specs AS specs # Copy all the source we need to build the docs src: @@ -13,6 +14,9 @@ src: # Now copy into that any artifacts we pull from the builds. COPY --dir repo+repo-docs/repo /docs/includes + # Copy our generated Signed Document Specification data. + COPY specs+src/signed_doc.json /docs/includes + # Build the docs here. docs: diff --git a/docs/src/architecture/08_concepts/catalyst_docs/.pages b/docs/src/architecture/08_concepts/catalyst_docs/.pages index 15986adb3b..8d05620e77 100644 --- a/docs/src/architecture/08_concepts/catalyst_docs/.pages +++ b/docs/src/architecture/08_concepts/catalyst_docs/.pages @@ -1,5 +1 @@ title: Catalyst Documents -arrange: -- proposal.md -- review.md -- comment.md \ No newline at end of file diff --git a/docs/src/architecture/08_concepts/catalyst_docs/comment.md b/docs/src/architecture/08_concepts/catalyst_docs/comment.md index 3dc31f92f3..a177cf8fc1 100644 --- a/docs/src/architecture/08_concepts/catalyst_docs/comment.md +++ b/docs/src/architecture/08_concepts/catalyst_docs/comment.md @@ -46,17 +46,17 @@ A list of used [Catalyst Signed Document protected header fields](./../signed_do "content-encoding" => "br" ``` -* [`ref`](./../signed_doc/meta.md#ref-document-reference). +* [`ref`](./../signed_doc/metadata.md#ref-document-reference). Reference to a related [Proposal Document], which [`type`](./../signed_doc/spec.md#type) must be equal to [proposal document `type`][Proposal Document] field value. -* [`template`](./../signed_doc/meta.md#ref-document-reference). +* [`template`](./../signed_doc/metadata.md#ref-document-reference). A reference to the comment template document, which [`type`](./../signed_doc/spec.md#type) must be equal to [comment template `type`](#comment-template) field value. -* [`reply`](./../signed_doc/meta.md#reply-reply-reference) (optional). +* [`reply`](./../signed_doc/metadata.md#reply-reply-reference) (optional). A reference to another comment document, where the comment is in reply to the referenced comment. The [`type`](./../signed_doc/spec.md#type) of the replied document @@ -65,7 +65,7 @@ A list of used [Catalyst Signed Document protected header fields](./../signed_do The referenced `comment` must be for the same proposal [`id`](./../signed_doc/spec.md#id), but can be for a different proposal [`ver`](./../signed_doc/spec.md#ver). -* [`section`](./../signed_doc/meta.md#section-section-reference) (optional). +* [`section`](./../signed_doc/metadata.md#section-section-reference) (optional). Used when the comment only applies to a specific section to the document being commented upon, and not the entire document. @@ -106,7 +106,7 @@ A list of used [Catalyst Signed Document protected header fields](./../signed_do "content-encoding" => "br" ``` -* [`category_id`](./../signed_doc/meta.md#category_id) (optional). +* [`category_id`](./../signed_doc/metadata.md#category_id) (optional). A reference to the category document, which [`type`](./../signed_doc/spec.md#type) must be equal to `48c20109-362a-4d32-9bba-e0a9cf8b45be` value. diff --git a/docs/src/architecture/08_concepts/catalyst_docs/proposal.md b/docs/src/architecture/08_concepts/catalyst_docs/proposal.md index 95390a229e..5f5483353a 100644 --- a/docs/src/architecture/08_concepts/catalyst_docs/proposal.md +++ b/docs/src/architecture/08_concepts/catalyst_docs/proposal.md @@ -50,12 +50,12 @@ A list of used [Catalyst Signed Document protected header fields](./../signed_do "content-encoding" => "br" ``` -* [`template`](./../signed_doc/meta.md#ref-document-reference). +* [`template`](./../signed_doc/metadata.md#ref-document-reference). A reference to the proposal template document, which [`type`](./../signed_doc/spec.md#type) must be equal to [proposal template `type`](#proposal-template) field value. -* [`category_id`](./../signed_doc/meta.md#category_id) (optional). +* [`category_id`](./../signed_doc/metadata.md#category_id) (optional). A reference to the category document, which [`type`](./../signed_doc/spec.md#type) must be equal to `48c20109-362a-4d32-9bba-e0a9cf8b45be` value. @@ -112,7 +112,7 @@ A list of used [Catalyst Signed Document protected header fields](./../signed_do "content-encoding" => "br" ``` -* [`category_id`](./../signed_doc/meta.md#category_id) (optional). +* [`category_id`](./../signed_doc/metadata.md#category_id) (optional). A reference to the category document, which [`type`](./../signed_doc/spec.md#type) must be equal to `48c20109-362a-4d32-9bba-e0a9cf8b45be` value. diff --git a/docs/src/architecture/08_concepts/catalyst_docs/review.md b/docs/src/architecture/08_concepts/catalyst_docs/review.md index 749bbdb1dc..09a2a5ae75 100644 --- a/docs/src/architecture/08_concepts/catalyst_docs/review.md +++ b/docs/src/architecture/08_concepts/catalyst_docs/review.md @@ -46,7 +46,7 @@ A list of used [Catalyst Signed Document protected header fields](./../signed_do "content-encoding" => "br" ``` -* [`template`](./../signed_doc/meta.md#ref-document-reference). +* [`template`](./../signed_doc/metadata.md#ref-document-reference). A reference to the review template document, which [`type`](./../signed_doc/spec.md#type) must be equal to [review template `type`](#review-template) field value. diff --git a/docs/src/architecture/08_concepts/catalyst_voting/v2.md b/docs/src/architecture/08_concepts/catalyst_voting/v2.md index 45c1192581..e7fee18641 100644 --- a/docs/src/architecture/08_concepts/catalyst_voting/v2.md +++ b/docs/src/architecture/08_concepts/catalyst_voting/v2.md @@ -35,16 +35,16 @@ A list of used [Catalyst Signed Document protected header fields](./../signed_do "content-type" => "br" ``` -* [`brand_id`](./../signed_doc/meta.md#brand_id). -* [`campaign_id`](./../signed_doc/meta.md#campaign_id). -* [`election_id`](./../signed_doc/meta.md#election_id). -* [`category_id`](./../signed_doc/meta.md#category_id). +* [`brand_id`](./../signed_doc/metadata.md#brand_id). +* [`campaign_id`](./../signed_doc/metadata.md#campaign_id). +* [`election_id`](./../signed_doc/metadata.md#election_id). +* [`category_id`](./../signed_doc/metadata.md#category_id). #### Public vote -For the public vote [`type`](./../signed_doc/spec.md#type) value defined as follows: +For the public vote [`type`](./../signed_doc/metadata.md#type) value defined as follows: -* [`type`](./../signed_doc/spec.md#type): `8de5586c-e998-4b95-8742-7be3c8592803` [UUID] value. +* [`type`](./../signed_doc/metadata.md#type): `8de5586c-e998-4b95-8742-7be3c8592803` [UUID] value. ```CDDL "type" => 37(h'8DE5586CE9984B9587427BE3C8592803') @@ -66,9 +66,9 @@ Following that spec need to define a `choice`, `proof` and `prop-id`. #### Private vote -For the private vote [`type`](./../signed_doc/spec.md#type) value defined as follows: +For the private vote [`type`](./../signed_doc/metadata.md#type) value defined as follows: -* [`type`](./../signed_doc/spec.md#type): `e78ee18d-f380-44c1-a852-80aa6ecb07fe` [UUID] value. +* [`type`](./../signed_doc/metadata.md#type): `e78ee18d-f380-44c1-a852-80aa6ecb07fe` [UUID] value. ```CDDL "type" => 37(h'E78EE18DF38044C1A85280AA6ECB07FE') @@ -112,7 +112,7 @@ the following properties are used: [Catalyst Signed Document]: ./../signed_doc/spec.md -[Catalyst Signed Document content]: ./../signed_doc/spec.md#signed-object-content +[Catalyst Signed Document content]: ./../signed_doc/spec.md#content-type [Generalized Vote Transaction Structure]: ./gen_vote_tx.md [BLAKE2b-512]: https://www.blake2.net/blake2.pdf [ristretto255]: https://ristretto.group diff --git a/docs/src/architecture/08_concepts/immutable_ledger/ledger.md b/docs/src/architecture/08_concepts/immutable_ledger/ledger.md index f3731abdad..4013616331 100644 --- a/docs/src/architecture/08_concepts/immutable_ledger/ledger.md +++ b/docs/src/architecture/08_concepts/immutable_ledger/ledger.md @@ -77,14 +77,14 @@ so its fully follows the structure of the [Catalyst Signed Document] specificati ### Metadata Fields -* [`id`](./../signed_doc/spec.md#id). +* [`id`](./../signed_doc/metadata.md#id). Used as a unique identifier of the chain. So all blocks from the same chain must have the same - [`id`](./../signed_doc/spec.md#id) field value. -* [`ver`](./../signed_doc/spec.md#ver). + [`id`](./../signed_doc/metadata.md#id) field value. +* [`ver`](./../signed_doc/metadata.md#ver). Used as a unique identifier of the block itself. Also the block's creation `timestamp` value is determined from the - [`ver`](./../signed_doc/spec.md#ver) field. + [`ver`](./../signed_doc/metadata.md#ver) field. * [`content type`](./../signed_doc/spec.md#content-type): `application/cbor`. [Catalyst Signed Document content] must be a [CBOR] encoded. @@ -92,24 +92,21 @@ so its fully follows the structure of the [Catalyst Signed Document] specificati 3 => 50 ``` -* [`content encoding`](./../signed_doc/spec.md#content-encoding-optional): +* [`content encoding`](./../signed_doc/spec.md#content-encoding): [Catalyst Signed Document content] must be [Brotli] compressed. ```CDDL "content-type" => "br" ``` -* [`type`](./../signed_doc/spec.md#type): `d9e7e6ce-2401-4d7d-9492-f4f7c64241c3` [UUID] value. +* [`type`](./../signed_doc/metadata.md#type): `d9e7e6ce-2401-4d7d-9492-f4f7c64241c3` [UUID] value. ```CDDL "type" => 37(h'D9E7E6CE24014D7D9492F4F7C64241C3') ``` -* [`ref_hash`](./../signed_doc/meta.md#ref-hash-secured-document-reference). - Previous block reference. - A [`ref`](./../signed_doc/meta.md#ref-document-reference) part **must** be a pair of - [`id`](./../signed_doc/spec.md#id) and - [`ver`](./../signed_doc/spec.md#ver). +* [`ref`](./../signed_doc/metadata.md#ref). + Previous block reference, including Hash of the previous block. ### Content format @@ -144,7 +141,7 @@ Block: ### Block validation rules -* [`id`](./../signed_doc/spec.md#id) +* [`id`](./../signed_doc/metadata.md#id) **MUST** be the same as for the previous block (except for genesis). * `height` **MUST** be incremented by `1` from the previous block height value (except for genesis and final block). *Genesis* block **MUST** have `0` value. @@ -152,24 +149,17 @@ Block: E.g. previous block height is `9` and the *Final* block height is `-10`. * *Final* block is the last one for the specific chain and any other block could not be referenced to the *Final* one. -* [`ver`](./../signed_doc/spec.md#ver) +* [`ver`](./../signed_doc/metadata.md#ver) timestamp value **MUST** be greater or equals than the corresponding `timestamp` of the previous block (except for genesis). -* [`ref_hash`](./../signed_doc/meta.md#ref-hash-secured-document-reference) +* [`ref`](./../signed_doc/metadata.md#ref) **MUST** be a reference to the previous block (except for genesis). * `ledger-type` **MUST** be the same as for the previous block if present (except for genesis). **MANDATORY** field for *Genesis* and *Final* blocks. * `purpose-id` **MUST** be the same as for the previous block if present (except for genesis). **MANDATORY** field for *Genesis* and *Final* blocks. -* [`kid`](./../signed_doc/spec.md#cose-signature-protected-header) field +* [`kid`](./../signed_doc/spec.md#kid) field **MUST** be the same as for the previous block (except for genesis). -* [`ref_hash`](./../signed_doc/meta.md#ref-hash-secured-document-reference)'s - `hash-bytes` CBOR tag value and `bytes` size - **MUST** be the same as for the previous block (except for genesis). - Means that the hash function type and hash size itself must be the same. -* [`ref_hash`](./../signed_doc/meta.md#ref-hash-secured-document-reference) - field for the *Genesis* block **MUST** be omitted. -* `block-data` **MUST** be a [deterministically][CBOR-deterministically-encoded] encoded CBOR. ## Rationale @@ -184,7 +174,6 @@ Block: [Catalyst Signed Document]: ./../signed_doc/spec.md -[Catalyst Signed Document content]: ./../signed_doc/spec.md#signed-object-content -[CBOR-deterministically-encoded]: https://datatracker.ietf.org/doc/html/rfc8949#name-deterministically-encoded-c +[Catalyst Signed Document content]: ./../signed_doc/spec.md#content-type [Brotli]: https://datatracker.ietf.org/doc/html/rfc7932 [CBOR]: https://datatracker.ietf.org/doc/rfc8949/ diff --git a/docs/src/architecture/08_concepts/signed_doc/.pages b/docs/src/architecture/08_concepts/signed_doc/.pages index ffda03396a..176b5b0eb8 100644 --- a/docs/src/architecture/08_concepts/signed_doc/.pages +++ b/docs/src/architecture/08_concepts/signed_doc/.pages @@ -1,5 +1,6 @@ title: Catalyst Signed Document nav: - Specification: spec.md - - Metadata Fields: meta.md + - Metadata Fields: metadata.md - Document Types: types.md + - docs diff --git a/docs/src/architecture/08_concepts/signed_doc/doc_relationships.d2 b/docs/src/architecture/08_concepts/signed_doc/doc_relationships.d2 new file mode 100644 index 0000000000..5a188d40d2 --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/doc_relationships.d2 @@ -0,0 +1,212 @@ +vars: { + d2-config: { + layout-engine: elk + theme-id: 4 + pad: 100 + center: true + } +} + +title: |~md + # Signed Document Relationship Hierarchy +~| {near: top-center} + +copyright: |~md + ## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under CC-BY-4.0 | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +~| {near: bottom-right} + +"Brand Parameters": { + shape: sql_table + "content type": application/json + "type [0]": ebcabeeb-5bc5-4f95-91e8-cab8ca724172 + "id": UUIDv7 + "ver": UUIDv7 + +} + + + +"Campaign Parameters": { + shape: sql_table + "content type": application/json + "type [0]": 5ef32d5d-f240-462c-a7a4-ba4af221fa23 + "id": UUIDv7 + "ver": UUIDv7 + +} + + + +"Category Parameters": { + shape: sql_table + "content type": application/json + "type [0]": 818938c3-3139-4daa-afe6-974c78488e95 + "id": UUIDv7 + "ver": UUIDv7 + +} + + + +"Comment Action Document": { + shape: sql_table + "content type": application/json + "type [0]": 5e60e623-ad02-4a1b-a1ac-406db978ee48 + "type [1]": b679ded3-0e7c-41ba-89f8-da62a17898ea + "type [2]": a5d232b8-5e03-4117-9afd-be32b878fcdd + "id": UUIDv7 + "ver": UUIDv7 + +} + + + +"Election Parameters": { + shape: sql_table + "content type": application/json + "type [0]": 788ff4c6-d65a-451f-bb33-575fe056b411 + "id": UUIDv7 + "ver": UUIDv7 + +} + + + +"Proposal": { + shape: sql_table + "content type": application/json + "type [0]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "id": UUIDv7 + "ver": UUIDv7 + "template": Proposal Template + "collaborators": Collaborators Reference List + "category_id": Category Parameters (Optional) + +} + +"Proposal"."template"->"Proposal Template" +"Proposal"."category_id"->"Category Parameters": Optional + + +"Proposal Comment": { + shape: sql_table + "content type": application/json + "type [0]": b679ded3-0e7c-41ba-89f8-da62a17898ea + "type [1]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "id": UUIDv7 + "ver": UUIDv7 + "ref": Proposal + "template": Proposal Comment Template + "reply": Proposal Comment (Optional) + "section": Section Reference + "category_id": Category Parameters (Optional) + +} + +"Proposal Comment"."ref"->"Proposal" +"Proposal Comment"."template"->"Proposal Comment Template" +"Proposal Comment"."reply"->"Proposal Comment": Optional +"Proposal Comment"."category_id"->"Category Parameters": Optional + + +"Proposal Comment Meta Template": { + shape: sql_table + "content type": application/schema+json + "type [0]": 0ce8ab38-9258-4fbc-a62e-7faa6e58318f + "type [1]": 0ce8ab38-9258-4fbc-a62e-7faa6e58318f + "type [2]": b679ded3-0e7c-41ba-89f8-da62a17898ea + "type [3]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "id": UUIDv7 + "ver": UUIDv7 + "category_id": Category Parameters (Optional) + +} + +"Proposal Comment Meta Template"."category_id"->"Category Parameters": Optional + + +"Proposal Comment Template": { + shape: sql_table + "content type": application/schema+json + "type [0]": 0ce8ab38-9258-4fbc-a62e-7faa6e58318f + "type [1]": b679ded3-0e7c-41ba-89f8-da62a17898ea + "type [2]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "id": UUIDv7 + "ver": UUIDv7 + "template": Proposal Comment Meta Template (Optional) + "category_id": Category Parameters (Optional) + +} + +"Proposal Comment Template"."template"->"Proposal Comment Meta Template": Optional +"Proposal Comment Template"."category_id"->"Category Parameters": Optional + + +"Proposal Meta Template": { + shape: sql_table + "content type": application/schema+json + "type [0]": 0ce8ab38-9258-4fbc-a62e-7faa6e58318f + "type [1]": 0ce8ab38-9258-4fbc-a62e-7faa6e58318f + "type [2]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "id": UUIDv7 + "ver": UUIDv7 + "category_id": Category Parameters (Optional) + +} + +"Proposal Meta Template"."category_id"->"Category Parameters": Optional + + +"Proposal Moderation Action": { + shape: sql_table + "content type": application/json + "type [0]": 5e60e623-ad02-4a1b-a1ac-406db978ee48 + "type [1]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "type [2]": a5d232b8-5e03-4117-9afd-be32b878fcdd + "id": UUIDv7 + "ver": UUIDv7 + +} + + + +"Proposal Submission Action": { + shape: sql_table + "content type": application/json + "type [0]": 5e60e623-ad02-4a1b-a1ac-406db978ee48 + "type [1]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "type [2]": 78927329-cfd9-4ea1-9c71-0e019b126a65 + "id": UUIDv7 + "ver": UUIDv7 + "ref": Proposal + "category_id": Category Parameters + +} + +"Proposal Submission Action"."ref"->"Proposal" +"Proposal Submission Action"."category_id"->"Category Parameters" + + +"Proposal Template": { + shape: sql_table + "content type": application/schema+json + "type [0]": 0ce8ab38-9258-4fbc-a62e-7faa6e58318f + "type [1]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "id": UUIDv7 + "ver": UUIDv7 + "template": Proposal Meta Template (Optional) + "category_id": Category Parameters (Optional) + +} + +"Proposal Template"."template"->"Proposal Meta Template": Optional +"Proposal Template"."category_id"->"Category Parameters": Optional diff --git a/docs/src/architecture/08_concepts/signed_doc/doc_relationships.svg b/docs/src/architecture/08_concepts/signed_doc/doc_relationships.svg new file mode 100644 index 0000000000..8611613820 --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/doc_relationships.svg @@ -0,0 +1,884 @@ +

Signed Document Relationship Hierarchy

+

Copyright

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Copyright:copyright: 2024-2025 IOG Singapore, All Rights Reserved
LicenseThis document is licensed under CC-BY-4.0
Created2024-12-27
Modified2025-04-04
AuthorsAlex Pozhylenkov alex.pozhylenkov@iohk.io
Steven Johnson steven.johnson@iohk.io
+
Brand Parameterscontent typeapplication/jsontype [0]ebcabeeb-5bc5-4f95-91e8-cab8ca724172idUUIDv7verUUIDv7Campaign Parameterscontent typeapplication/jsontype [0]5ef32d5d-f240-462c-a7a4-ba4af221fa23idUUIDv7verUUIDv7Category Parameterscontent typeapplication/jsontype [0]818938c3-3139-4daa-afe6-974c78488e95idUUIDv7verUUIDv7Comment Action Documentcontent typeapplication/jsontype [0]5e60e623-ad02-4a1b-a1ac-406db978ee48type [1]b679ded3-0e7c-41ba-89f8-da62a17898eatype [2]a5d232b8-5e03-4117-9afd-be32b878fcddidUUIDv7verUUIDv7Election Parameterscontent typeapplication/jsontype [0]788ff4c6-d65a-451f-bb33-575fe056b411idUUIDv7verUUIDv7Proposalcontent typeapplication/jsontype [0]7808d2ba-d511-40af-84e8-c0d1625fdfdcidUUIDv7verUUIDv7templateProposal TemplatecollaboratorsCollaborators Reference Listcategory_idCategory Parameters (Optional)Proposal Templatecontent typeapplication/schema+jsontype [0]0ce8ab38-9258-4fbc-a62e-7faa6e58318ftype [1]7808d2ba-d511-40af-84e8-c0d1625fdfdcidUUIDv7verUUIDv7templateProposal Meta Template (Optional)category_idCategory Parameters (Optional)Proposal Commentcontent typeapplication/jsontype [0]b679ded3-0e7c-41ba-89f8-da62a17898eatype [1]7808d2ba-d511-40af-84e8-c0d1625fdfdcidUUIDv7verUUIDv7refProposaltemplateProposal Comment TemplatereplyProposal Comment (Optional)sectionSection Referencecategory_idCategory Parameters (Optional)Proposal Comment Templatecontent typeapplication/schema+jsontype [0]0ce8ab38-9258-4fbc-a62e-7faa6e58318ftype [1]b679ded3-0e7c-41ba-89f8-da62a17898eatype [2]7808d2ba-d511-40af-84e8-c0d1625fdfdcidUUIDv7verUUIDv7templateProposal Comment Meta Template (Optional)category_idCategory Parameters (Optional)Proposal Comment Meta Templatecontent typeapplication/schema+jsontype [0]0ce8ab38-9258-4fbc-a62e-7faa6e58318ftype [1]0ce8ab38-9258-4fbc-a62e-7faa6e58318ftype [2]b679ded3-0e7c-41ba-89f8-da62a17898eatype [3]7808d2ba-d511-40af-84e8-c0d1625fdfdcidUUIDv7verUUIDv7category_idCategory Parameters (Optional)Proposal Meta Templatecontent typeapplication/schema+jsontype [0]0ce8ab38-9258-4fbc-a62e-7faa6e58318ftype [1]0ce8ab38-9258-4fbc-a62e-7faa6e58318ftype [2]7808d2ba-d511-40af-84e8-c0d1625fdfdcidUUIDv7verUUIDv7category_idCategory Parameters (Optional)Proposal Moderation Actioncontent typeapplication/jsontype [0]5e60e623-ad02-4a1b-a1ac-406db978ee48type [1]7808d2ba-d511-40af-84e8-c0d1625fdfdctype [2]a5d232b8-5e03-4117-9afd-be32b878fcddidUUIDv7verUUIDv7Proposal Submission Actioncontent typeapplication/jsontype [0]5e60e623-ad02-4a1b-a1ac-406db978ee48type [1]7808d2ba-d511-40af-84e8-c0d1625fdfdctype [2]78927329-cfd9-4ea1-9c71-0e019b126a65idUUIDv7verUUIDv7refProposalcategory_idCategory Parameters Optional<reply> OptionalOptionalOptionalOptionalOptionalOptionalOptionalOptional + + + + + + + + + + + + +
diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/.pages b/docs/src/architecture/08_concepts/signed_doc/docs/.pages new file mode 100644 index 0000000000..fb5a24abff --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/.pages @@ -0,0 +1 @@ +title: Defined Document Types \ No newline at end of file diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/brand_parameters.md b/docs/src/architecture/08_concepts/signed_doc/docs/brand_parameters.md new file mode 100644 index 0000000000..75563da5b0 --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/brand_parameters.md @@ -0,0 +1,109 @@ +# Brand Parameters + +## Description + +TODO + +```d2 layout="elk" +"Brand Parameters": { + shape: sql_table + "content type": application/json + "type [0]": ebcabeeb-5bc5-4f95-91e8-cab8ca724172 + "id": UUIDv7 + "ver": UUIDv7 + +} +``` + +### Validation + +TODO + +### Business Logic + +#### Front End + +TODO + +#### Back End + +TODO + +## [COSE Header Parameters][RFC9052-HeaderParameters] + +* [content type](../spec.md#content-type) = `application/json` +* [content-encoding](../spec.md#content-encoding) = `[br]` + +## Metadata + +### `type` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Type](../metadata.md#document-type) | +| Type | `ebcabeeb-5bc5-4f95-91e8-cab8ca724172` | + +The document TYPE. + +#### Validation + +**MUST** be a known document type. + +### `id` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +Document ID, created the first time the document is created. +This must be a properly created [UUIDv7][RFC9562-V7] which contains the +timestamp of when the document was created. + +#### Validation + +IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with +[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist. + +### `ver` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +The unique version of the document. +The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id) + +#### Validation + +The document version must always be >= the document ID. + +## Payload + +TODO + +## Signers + +The following user roles may sign documents of this type: + +* Registered + +New versions of this document may be published by: + +* author + +## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7 diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/campaign_parameters.md b/docs/src/architecture/08_concepts/signed_doc/docs/campaign_parameters.md new file mode 100644 index 0000000000..db8819dd94 --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/campaign_parameters.md @@ -0,0 +1,109 @@ +# Campaign Parameters + +## Description + +TODO + +```d2 layout="elk" +"Campaign Parameters": { + shape: sql_table + "content type": application/json + "type [0]": 5ef32d5d-f240-462c-a7a4-ba4af221fa23 + "id": UUIDv7 + "ver": UUIDv7 + +} +``` + +### Validation + +TODO + +### Business Logic + +#### Front End + +TODO + +#### Back End + +TODO + +## [COSE Header Parameters][RFC9052-HeaderParameters] + +* [content type](../spec.md#content-type) = `application/json` +* [content-encoding](../spec.md#content-encoding) = `[br]` + +## Metadata + +### `type` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Type](../metadata.md#document-type) | +| Type | `5ef32d5d-f240-462c-a7a4-ba4af221fa23` | + +The document TYPE. + +#### Validation + +**MUST** be a known document type. + +### `id` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +Document ID, created the first time the document is created. +This must be a properly created [UUIDv7][RFC9562-V7] which contains the +timestamp of when the document was created. + +#### Validation + +IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with +[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist. + +### `ver` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +The unique version of the document. +The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id) + +#### Validation + +The document version must always be >= the document ID. + +## Payload + +TODO + +## Signers + +The following user roles may sign documents of this type: + +* Registered + +New versions of this document may be published by: + +* author + +## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7 diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/category_parameters.md b/docs/src/architecture/08_concepts/signed_doc/docs/category_parameters.md new file mode 100644 index 0000000000..0a92b2d0b7 --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/category_parameters.md @@ -0,0 +1,109 @@ +# Category Parameters + +## Description + +TODO + +```d2 layout="elk" +"Category Parameters": { + shape: sql_table + "content type": application/json + "type [0]": 818938c3-3139-4daa-afe6-974c78488e95 + "id": UUIDv7 + "ver": UUIDv7 + +} +``` + +### Validation + +TODO + +### Business Logic + +#### Front End + +TODO + +#### Back End + +TODO + +## [COSE Header Parameters][RFC9052-HeaderParameters] + +* [content type](../spec.md#content-type) = `application/json` +* [content-encoding](../spec.md#content-encoding) = `[br]` + +## Metadata + +### `type` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Type](../metadata.md#document-type) | +| Type | `818938c3-3139-4daa-afe6-974c78488e95` | + +The document TYPE. + +#### Validation + +**MUST** be a known document type. + +### `id` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +Document ID, created the first time the document is created. +This must be a properly created [UUIDv7][RFC9562-V7] which contains the +timestamp of when the document was created. + +#### Validation + +IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with +[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist. + +### `ver` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +The unique version of the document. +The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id) + +#### Validation + +The document version must always be >= the document ID. + +## Payload + +TODO + +## Signers + +The following user roles may sign documents of this type: + +* Registered + +New versions of this document may be published by: + +* author + +## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7 diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/comment_action_document.md b/docs/src/architecture/08_concepts/signed_doc/docs/comment_action_document.md new file mode 100644 index 0000000000..ad3713daaa --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/comment_action_document.md @@ -0,0 +1,111 @@ +# Comment Action Document + +## Description + +TODO + +```d2 layout="elk" +"Comment Action Document": { + shape: sql_table + "content type": application/json + "type [0]": 5e60e623-ad02-4a1b-a1ac-406db978ee48 + "type [1]": b679ded3-0e7c-41ba-89f8-da62a17898ea + "type [2]": a5d232b8-5e03-4117-9afd-be32b878fcdd + "id": UUIDv7 + "ver": UUIDv7 + +} +``` + +### Validation + +TODO + +### Business Logic + +#### Front End + +TODO + +#### Back End + +TODO + +## [COSE Header Parameters][RFC9052-HeaderParameters] + +* [content type](../spec.md#content-type) = `application/json` +* [content-encoding](../spec.md#content-encoding) = `[br]` + +## Metadata + +### `type` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Type](../metadata.md#document-type) | +| Type | `5e60e623-ad02-4a1b-a1ac-406db978ee48`,
`b679ded3-0e7c-41ba-89f8-da62a17898ea`,
`a5d232b8-5e03-4117-9afd-be32b878fcdd` | + +The document TYPE. + +#### Validation + +**MUST** be a known document type. + +### `id` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +Document ID, created the first time the document is created. +This must be a properly created [UUIDv7][RFC9562-V7] which contains the +timestamp of when the document was created. + +#### Validation + +IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with +[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist. + +### `ver` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +The unique version of the document. +The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id) + +#### Validation + +The document version must always be >= the document ID. + +## Payload + +TODO + +## Signers + +The following user roles may sign documents of this type: + +* Registered + +New versions of this document may be published by: + +* author + +## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7 diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/election_parameters.md b/docs/src/architecture/08_concepts/signed_doc/docs/election_parameters.md new file mode 100644 index 0000000000..132fa96e3a --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/election_parameters.md @@ -0,0 +1,109 @@ +# Election Parameters + +## Description + +TODO + +```d2 layout="elk" +"Election Parameters": { + shape: sql_table + "content type": application/json + "type [0]": 788ff4c6-d65a-451f-bb33-575fe056b411 + "id": UUIDv7 + "ver": UUIDv7 + +} +``` + +### Validation + +TODO + +### Business Logic + +#### Front End + +TODO + +#### Back End + +TODO + +## [COSE Header Parameters][RFC9052-HeaderParameters] + +* [content type](../spec.md#content-type) = `application/json` +* [content-encoding](../spec.md#content-encoding) = `[br]` + +## Metadata + +### `type` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Type](../metadata.md#document-type) | +| Type | `788ff4c6-d65a-451f-bb33-575fe056b411` | + +The document TYPE. + +#### Validation + +**MUST** be a known document type. + +### `id` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +Document ID, created the first time the document is created. +This must be a properly created [UUIDv7][RFC9562-V7] which contains the +timestamp of when the document was created. + +#### Validation + +IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with +[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist. + +### `ver` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +The unique version of the document. +The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id) + +#### Validation + +The document version must always be >= the document ID. + +## Payload + +TODO + +## Signers + +The following user roles may sign documents of this type: + +* Registered + +New versions of this document may be published by: + +* author + +## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7 diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal.md new file mode 100644 index 0000000000..12a9edea7c --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal.md @@ -0,0 +1,183 @@ +# Proposal + +## Description + +A Proposal is a document which describes a proposed solution or project to +address the criteria of a category within a campaign. + +The proposal itself is a draft document, it is not submitted for consideration +unless a [Proposal Submission Action](proposal_submission_action.md) is submitted which references it. + +Proposals themselves are intentionally general, however they may be +linked to a brand/campaign or category via the template used by the proposal. + +The payload of a proposal is controlled by its template. + +```d2 layout="elk" +"Proposal": { + shape: sql_table + "content type": application/json + "type [0]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "id": UUIDv7 + "ver": UUIDv7 + "template": Proposal Template + "collaborators": Collaborators Reference List + "category_id": Category Parameters (Optional) + +} + +"Proposal"."template"->"Proposal Template" +"Proposal"."category_id"->"Category Parameters": Optional +``` + +### Validation + +TODO + +### Business Logic + +#### Front End + +TODO + +#### Back End + +TODO + +## [COSE Header Parameters][RFC9052-HeaderParameters] + +* [content type](../spec.md#content-type) = `application/json` +* [content-encoding](../spec.md#content-encoding) = `[br]` + +## Metadata + +### `type` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Type](../metadata.md#document-type) | +| Type | `7808d2ba-d511-40af-84e8-c0d1625fdfdc` | + +The document TYPE. + +#### Validation + +**MUST** be a known document type. + +### `id` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +Document ID, created the first time the document is created. +This must be a properly created [UUIDv7][RFC9562-V7] which contains the +timestamp of when the document was created. + +#### Validation + +IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with +[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist. + +### `ver` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +The unique version of the document. +The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id) + +#### Validation + +The document version must always be >= the document ID. + +### `template` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Reference](../metadata.md#document-reference) | +| Valid References | [Proposal Template](proposal_template.md) | + +Reference to the template used to create and/or validate this document. + +#### Validation + +In addition to the validation performed for `ref`, +The document payload is not valid if it does not validate completely against the referenced template. + +### `collaborators` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Collaborators Reference List](../metadata.md#collaborators-reference-list) | + +A list of collaborators who may also publish updates to versions of this document. +This should include all parties who have not signed this document directly. + +Every subsequent version can amend the collaborators list. +However, the initial Author can never be removed from being able to +publish a new version of the document. + +#### Validation + +This list does not imply these collaborators have consented to collaborate, only that the author/s +are permitting these potential collaborators to participate in the drafting and submission process. +However, any document submission referencing a proposal MUST be signed by all collaborators in +addition to the author. + +### `category_id` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](../metadata.md#document-reference) | +| Valid References | [Category Parameters](category_parameters.md) | +| Exclusive | brand_id | +| | campaign_id | + +A reference to the Category Parameters Document this document lies under. + +#### Validation + +In addition to the validation performed for `ref`, +Any referenced document that includes a [`category_id`](../metadata.md#category_id) must match the +[`category_id`](../metadata.md#category_id) of the referencing document. +It is also valid for the referenced document to not include this field, if it is +optional for the referenced document. + +## Payload + +Proposal Document drafted for submission to a category of a campaign. + +Must be valid according to the schema of the referenced Template. + +## Signers + +The following user roles may sign documents of this type: + +* Proposer + +New versions of this document may be published by: + +* author +* collaborators + +## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7 diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment.md new file mode 100644 index 0000000000..87468a74ca --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment.md @@ -0,0 +1,218 @@ +# Proposal Comment + +## Description + +## Proposal Comment Document + +A Proposal Comment is a document which comments on a referenced Proposal document. + +Proposal Comments themselves are intentionally general, however they may be +linked to a brand/campaign or category via the template used by the proposal. + +The payload of a proposal comment is controlled by its template. + +```d2 layout="elk" +"Proposal Comment": { + shape: sql_table + "content type": application/json + "type [0]": b679ded3-0e7c-41ba-89f8-da62a17898ea + "type [1]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "id": UUIDv7 + "ver": UUIDv7 + "ref": Proposal + "template": Proposal Comment Template + "reply": Proposal Comment (Optional) + "section": Section Reference + "category_id": Category Parameters (Optional) + +} + +"Proposal Comment"."ref"->"Proposal" +"Proposal Comment"."template"->"Proposal Comment Template" +"Proposal Comment"."reply"->"Proposal Comment": Optional +"Proposal Comment"."category_id"->"Category Parameters": Optional +``` + +### Validation + +TODO + +### Business Logic + +#### Front End + +TODO + +#### Back End + +TODO + +## [COSE Header Parameters][RFC9052-HeaderParameters] + +* [content type](../spec.md#content-type) = `application/json` +* [content-encoding](../spec.md#content-encoding) = `[br]` + +## Metadata + +### `type` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Type](../metadata.md#document-type) | +| Type | `b679ded3-0e7c-41ba-89f8-da62a17898ea`,
`7808d2ba-d511-40af-84e8-c0d1625fdfdc` | + +The document TYPE. + +#### Validation + +**MUST** be a known document type. + +### `id` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +Document ID, created the first time the document is created. +This must be a properly created [UUIDv7][RFC9562-V7] which contains the +timestamp of when the document was created. + +#### Validation + +IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with +[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist. + +### `ver` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +The unique version of the document. +The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id) + +#### Validation + +The document version must always be >= the document ID. + +### `ref` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Reference](../metadata.md#document-reference) | +| Valid References | [Proposal](proposal.md) | + +Reference to a Linked Document or Documents. +This is the primary hierarchical reference to a related document. + +This is an Array of the format: + `[[DocumentID, DocumentVer, DocumentHash],...]` + +* `DocumentID` is the [UUIDv7][RFC9562-V7] ID of the Document being referenced. +* `DocumentVer` is the [UUIDv7][RFC9562-V7] Version of the Document being referenced. +* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload. + It ensures that the intended referenced document is the one used, and there has been no substitution. + Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one. + +#### Validation + +Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document. +The calculated Hash of the Referenced Document **MUST** match the Hash in the reference. + +### `template` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Reference](../metadata.md#document-reference) | +| Valid References | [Proposal Comment Template](proposal_comment_template.md) | + +Reference to the template used to create and/or validate this document. + +#### Validation + +In addition to the validation performed for `ref`, +The document payload is not valid if it does not validate completely against the referenced template. + +### `reply` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](../metadata.md#document-reference) | +| Valid References | [Proposal Comment](proposal_comment.md) | + +Reference to a Comment document type being referred to. + +#### Validation + +In addition to the validation performed for `ref`, +The [`ref`](../metadata.md#ref) of the [`reply`](../metadata.md#reply) document must be the same as +the original comment document. + +### `section` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Section Reference](../metadata.md#section-reference) | + +A Reference to the original document, or the comment being replied to. + +#### Validation + +For a non-reply this must be a valid section reference into the referenced document. +For a reply, this must be a valid section reference into the comment being replied to. + +### `category_id` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](../metadata.md#document-reference) | +| Valid References | [Category Parameters](category_parameters.md) | +| Exclusive | brand_id | +| | campaign_id | + +A reference to the Category Parameters Document this document lies under. + +#### Validation + +In addition to the validation performed for `ref`, +Any referenced document that includes a [`category_id`](../metadata.md#category_id) must match the +[`category_id`](../metadata.md#category_id) of the referencing document. +It is also valid for the referenced document to not include this field, if it is +optional for the referenced document. + +## Payload + +[JSON][RFC8259] Document which must validate against the referenced template. + +## Signers + +The following user roles may sign documents of this type: + +* Registered + +New versions of this document may be published by: + +* author + +## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7 +[RFC8259]: https://www.rfc-editor.org/rfc/rfc8259.html diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_meta_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_meta_template.md new file mode 100644 index 0000000000..9a373c6a4f --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_meta_template.md @@ -0,0 +1,148 @@ +# Proposal Comment Meta Template + +## Description + +## Proposal Comment Meta Template Document + +A Proposal Comment Meta Template is used to enforce functional requirements +are met in any Proposal Comment Template. + +The payload of a proposal comment template is controlled by its meta template. + +```d2 layout="elk" +"Proposal Comment Meta Template": { + shape: sql_table + "content type": application/schema+json + "type [0]": 0ce8ab38-9258-4fbc-a62e-7faa6e58318f + "type [1]": 0ce8ab38-9258-4fbc-a62e-7faa6e58318f + "type [2]": b679ded3-0e7c-41ba-89f8-da62a17898ea + "type [3]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "id": UUIDv7 + "ver": UUIDv7 + "category_id": Category Parameters (Optional) + +} + +"Proposal Comment Meta Template"."category_id"->"Category Parameters": Optional +``` + +### Validation + +TODO + +### Business Logic + +#### Front End + +TODO + +#### Back End + +TODO + +## [COSE Header Parameters][RFC9052-HeaderParameters] + +* [content type](../spec.md#content-type) = `application/schema+json` +* [content-encoding](../spec.md#content-encoding) = `[br]` + +## Metadata + +### `type` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Type](../metadata.md#document-type) | +| Type | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f`,
`0ce8ab38-9258-4fbc-a62e-7faa6e58318f`,
`b679ded3-0e7c-41ba-89f8-da62a17898ea`,
`7808d2ba-d511-40af-84e8-c0d1625fdfdc` | + +The document TYPE. + +#### Validation + +**MUST** be a known document type. + +### `id` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +Document ID, created the first time the document is created. +This must be a properly created [UUIDv7][RFC9562-V7] which contains the +timestamp of when the document was created. + +#### Validation + +IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with +[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist. + +### `ver` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +The unique version of the document. +The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id) + +#### Validation + +The document version must always be >= the document ID. + +### `category_id` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](../metadata.md#document-reference) | +| Valid References | [Category Parameters](category_parameters.md) | +| Exclusive | brand_id | +| | campaign_id | + +A reference to the Category Parameters Document this document lies under. + +#### Validation + +In addition to the validation performed for `ref`, +Any referenced document that includes a [`category_id`](../metadata.md#category_id) must match the +[`category_id`](../metadata.md#category_id) of the referencing document. +It is also valid for the referenced document to not include this field, if it is +optional for the referenced document. + +## Payload + +[JSON Schema] document which ensures the minimum required functional requirements +of the Proposal Comment Template are met. + +This ensures that payloads can be reliably interpreted by business logic processes, +while allowing for flexibility to capture extended information. + +**Must be a valid [JSON Schema] Draft 7 document.** + +## Signers + +The following admin roles may sign documents of this type: + +* Root Admin +* Brand Admin + +New versions of this document may be published by: + +* author + +## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[JSON Schema]: https://json-schema.org/draft-07 +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7 diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_template.md new file mode 100644 index 0000000000..1f8a19e751 --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_comment_template.md @@ -0,0 +1,161 @@ +# Proposal Comment Template + +## Description + +## Proposal Comment Template Document + +A Proposal Comment Template defines the allowed payload contents of a +linked proposal comment. + +Proposal comments themselves are intentionally general, however they may be +linked to a brand/campaign or category via the template used by the proposal. + +The payload of a proposal comment is controlled by its template. + +```d2 layout="elk" +"Proposal Comment Template": { + shape: sql_table + "content type": application/schema+json + "type [0]": 0ce8ab38-9258-4fbc-a62e-7faa6e58318f + "type [1]": b679ded3-0e7c-41ba-89f8-da62a17898ea + "type [2]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "id": UUIDv7 + "ver": UUIDv7 + "template": Proposal Comment Meta Template (Optional) + "category_id": Category Parameters (Optional) + +} + +"Proposal Comment Template"."template"->"Proposal Comment Meta Template": Optional +"Proposal Comment Template"."category_id"->"Category Parameters": Optional +``` + +### Validation + +TODO + +### Business Logic + +#### Front End + +TODO + +#### Back End + +TODO + +## [COSE Header Parameters][RFC9052-HeaderParameters] + +* [content type](../spec.md#content-type) = `application/schema+json` +* [content-encoding](../spec.md#content-encoding) = `[br]` + +## Metadata + +### `type` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Type](../metadata.md#document-type) | +| Type | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f`,
`b679ded3-0e7c-41ba-89f8-da62a17898ea`,
`7808d2ba-d511-40af-84e8-c0d1625fdfdc` | + +The document TYPE. + +#### Validation + +**MUST** be a known document type. + +### `id` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +Document ID, created the first time the document is created. +This must be a properly created [UUIDv7][RFC9562-V7] which contains the +timestamp of when the document was created. + +#### Validation + +IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with +[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist. + +### `ver` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +The unique version of the document. +The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id) + +#### Validation + +The document version must always be >= the document ID. + +### `template` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](../metadata.md#document-reference) | +| Valid References | [Proposal Comment Meta Template](proposal_comment_meta_template.md) | + +Reference to the template used to create and/or validate this document. + +#### Validation + +In addition to the validation performed for `ref`, +The document payload is not valid if it does not validate completely against the referenced template. + +### `category_id` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](../metadata.md#document-reference) | +| Valid References | [Category Parameters](category_parameters.md) | +| Exclusive | brand_id | +| | campaign_id | + +A reference to the Category Parameters Document this document lies under. + +#### Validation + +In addition to the validation performed for `ref`, +Any referenced document that includes a [`category_id`](../metadata.md#category_id) must match the +[`category_id`](../metadata.md#category_id) of the referencing document. +It is also valid for the referenced document to not include this field, if it is +optional for the referenced document. + +## Payload + +[JSON Schema] document which defines the content of the Proposal Comments. + +## Signers + +The following admin roles may sign documents of this type: + +* Brand Admin +* Campaign Admin + +New versions of this document may be published by: + +* author + +## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[JSON Schema]: https://json-schema.org/draft-07 +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7 diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_meta_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_meta_template.md new file mode 100644 index 0000000000..8c9915a8c4 --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_meta_template.md @@ -0,0 +1,147 @@ +# Proposal Meta Template + +## Description + +## Proposal Meta Template Document + +A Proposal Meta Template is used to enforce functional requirements +are met in any Proposal Template. + +The payload of a proposal template is controlled by its meta template. + +```d2 layout="elk" +"Proposal Meta Template": { + shape: sql_table + "content type": application/schema+json + "type [0]": 0ce8ab38-9258-4fbc-a62e-7faa6e58318f + "type [1]": 0ce8ab38-9258-4fbc-a62e-7faa6e58318f + "type [2]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "id": UUIDv7 + "ver": UUIDv7 + "category_id": Category Parameters (Optional) + +} + +"Proposal Meta Template"."category_id"->"Category Parameters": Optional +``` + +### Validation + +TODO + +### Business Logic + +#### Front End + +TODO + +#### Back End + +TODO + +## [COSE Header Parameters][RFC9052-HeaderParameters] + +* [content type](../spec.md#content-type) = `application/schema+json` +* [content-encoding](../spec.md#content-encoding) = `[br]` + +## Metadata + +### `type` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Type](../metadata.md#document-type) | +| Type | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f`,
`0ce8ab38-9258-4fbc-a62e-7faa6e58318f`,
`7808d2ba-d511-40af-84e8-c0d1625fdfdc` | + +The document TYPE. + +#### Validation + +**MUST** be a known document type. + +### `id` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +Document ID, created the first time the document is created. +This must be a properly created [UUIDv7][RFC9562-V7] which contains the +timestamp of when the document was created. + +#### Validation + +IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with +[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist. + +### `ver` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +The unique version of the document. +The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id) + +#### Validation + +The document version must always be >= the document ID. + +### `category_id` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](../metadata.md#document-reference) | +| Valid References | [Category Parameters](category_parameters.md) | +| Exclusive | brand_id | +| | campaign_id | + +A reference to the Category Parameters Document this document lies under. + +#### Validation + +In addition to the validation performed for `ref`, +Any referenced document that includes a [`category_id`](../metadata.md#category_id) must match the +[`category_id`](../metadata.md#category_id) of the referencing document. +It is also valid for the referenced document to not include this field, if it is +optional for the referenced document. + +## Payload + +[JSON Schema] document which ensures the minimum required functional requirements +of the Proposal Template are met. + +This ensures that payloads can be reliably interpreted by business logic processes, +while allowing for flexibility to capture extended information. + +**Must be a valid [JSON Schema] Draft 7 document.** + +## Signers + +The following admin roles may sign documents of this type: + +* Root Admin +* Brand Admin + +New versions of this document may be published by: + +* author + +## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[JSON Schema]: https://json-schema.org/draft-07 +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7 diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_moderation_action.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_moderation_action.md new file mode 100644 index 0000000000..7aca07eecf --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_moderation_action.md @@ -0,0 +1,111 @@ +# Proposal Moderation Action + +## Description + +TODO + +```d2 layout="elk" +"Proposal Moderation Action": { + shape: sql_table + "content type": application/json + "type [0]": 5e60e623-ad02-4a1b-a1ac-406db978ee48 + "type [1]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "type [2]": a5d232b8-5e03-4117-9afd-be32b878fcdd + "id": UUIDv7 + "ver": UUIDv7 + +} +``` + +### Validation + +TODO + +### Business Logic + +#### Front End + +TODO + +#### Back End + +TODO + +## [COSE Header Parameters][RFC9052-HeaderParameters] + +* [content type](../spec.md#content-type) = `application/json` +* [content-encoding](../spec.md#content-encoding) = `[br]` + +## Metadata + +### `type` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Type](../metadata.md#document-type) | +| Type | `5e60e623-ad02-4a1b-a1ac-406db978ee48`,
`7808d2ba-d511-40af-84e8-c0d1625fdfdc`,
`a5d232b8-5e03-4117-9afd-be32b878fcdd` | + +The document TYPE. + +#### Validation + +**MUST** be a known document type. + +### `id` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +Document ID, created the first time the document is created. +This must be a properly created [UUIDv7][RFC9562-V7] which contains the +timestamp of when the document was created. + +#### Validation + +IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with +[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist. + +### `ver` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +The unique version of the document. +The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id) + +#### Validation + +The document version must always be >= the document ID. + +## Payload + +TODO + +## Signers + +The following user roles may sign documents of this type: + +* Registered + +New versions of this document may be published by: + +* author + +## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7 diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_submission_action.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_submission_action.md new file mode 100644 index 0000000000..f05b8dfbda --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_submission_action.md @@ -0,0 +1,230 @@ +# Proposal Submission Action + +## Description + +## Proposal Submission Action + +A Proposal Submission Action is a document which can attempt to either submit a +particular version of a proposal into a campaign, or withdraw it. + +The last action on the document ts the action which takes effect at the deadline. + +For multiple collaborators, multiple submission actions can be posted independently, +but none of them will take effect until ALL collaborators have posted equivalent actions. + +For example, three collaborators Alice/Bob/Claire can each post one submission action +for the same document. +Unless they all submit the same version of the proposal +the proposal will not be seen as submitted. + +The payload is a fixed format. + +```d2 layout="elk" +"Proposal Submission Action": { + shape: sql_table + "content type": application/json + "type [0]": 5e60e623-ad02-4a1b-a1ac-406db978ee48 + "type [1]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "type [2]": 78927329-cfd9-4ea1-9c71-0e019b126a65 + "id": UUIDv7 + "ver": UUIDv7 + "ref": Proposal + "category_id": Category Parameters + +} + +"Proposal Submission Action"."ref"->"Proposal" +"Proposal Submission Action"."category_id"->"Category Parameters" +``` + +### Validation + +TODO + +### Business Logic + +#### Front End + +TODO + +#### Back End + +TODO + +## [COSE Header Parameters][RFC9052-HeaderParameters] + +* [content type](../spec.md#content-type) = `application/json` +* [content-encoding](../spec.md#content-encoding) = `[br]` + +## Metadata + +### `type` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Type](../metadata.md#document-type) | +| Type | `5e60e623-ad02-4a1b-a1ac-406db978ee48`,
`7808d2ba-d511-40af-84e8-c0d1625fdfdc`,
`78927329-cfd9-4ea1-9c71-0e019b126a65` | + +The document TYPE. + +#### Validation + +**MUST** be a known document type. + +### `id` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +Document ID, created the first time the document is created. +This must be a properly created [UUIDv7][RFC9562-V7] which contains the +timestamp of when the document was created. + +#### Validation + +IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with +[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist. + +### `ver` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +The unique version of the document. +The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id) + +#### Validation + +The document version must always be >= the document ID. + +### `ref` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Reference](../metadata.md#document-reference) | +| Multiple References | True | +| Valid References | [Proposal](proposal.md) | + +Reference to a Linked Document or Documents. +This is the primary hierarchical reference to a related document. + +This is an Array of the format: + `[[DocumentID, DocumentVer, DocumentHash],...]` + +* `DocumentID` is the [UUIDv7][RFC9562-V7] ID of the Document being referenced. +* `DocumentVer` is the [UUIDv7][RFC9562-V7] Version of the Document being referenced. +* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload. + It ensures that the intended referenced document is the one used, and there has been no substitution. + Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one. + +#### Validation + +Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document. +The calculated Hash of the Referenced Document **MUST** match the Hash in the reference. + +### `category_id` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Reference](../metadata.md#document-reference) | +| Valid References | [Category Parameters](category_parameters.md) | +| Exclusive | brand_id | +| | campaign_id | + +A reference to the Category Parameters Document this document lies under. + +#### Validation + +In addition to the validation performed for `ref`, +Any referenced document that includes a [`category_id`](../metadata.md#category_id) must match the +[`category_id`](../metadata.md#category_id) of the referencing document. +It is also valid for the referenced document to not include this field, if it is +optional for the referenced document. + +## Payload + +The kind of action is controlled by this payload. +The Payload is a [JSON][RFC8259] Document, and must conform to this schema. + +States: + +* `final` : All collaborators must publish a `final` status for the proposal to be `final`. +* `draft` : Reverses the previous `final` state for a signer. +* `hide` : Requests the proposal be hidden (not final, but a hidden draft). + `hide` is only actioned if sent by the author, for a collaborator its synonymous with `draft`. + +Schema : + +```json +{ + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "definitions": { + "action": { + "description": "The action being performed on the Proposal.", + "enum": [ + "final", + "draft", + "hide" + ], + "type": "string" + } + }, + "description": "Structure of the payload of a Proposal Submission Action.", + "maintainers": [ + { + "name": "Catalyst Team", + "url": "https://projectcatalyst.io/" + } + ], + "properties": { + "action": { + "$ref": "#/definitions/action" + } + }, + "required": [ + "action" + ], + "title": "Proposal Submission Action Payload Schema", + "x-changelog": { + "2025-03-01": [ + "First Version Created." + ] + } +} +``` + + +## Signers + +The following user roles may sign documents of this type: + +* Proposer + +New versions of this document may be published by: + +* author +* collaborators + +## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7 +[RFC8259]: https://www.rfc-editor.org/rfc/rfc8259.html diff --git a/docs/src/architecture/08_concepts/signed_doc/docs/proposal_template.md b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_template.md new file mode 100644 index 0000000000..4886c1c58b --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/docs/proposal_template.md @@ -0,0 +1,160 @@ +# Proposal Template + +## Description + +## Proposal Template Document + +A Proposal Template defines the allowed payload contents of a +linked proposal. + +Proposals themselves are intentionally general, however they may be +linked to a brand/campaign or category via the template used by the proposal. + +The payload of a proposal is controlled by its template. + +```d2 layout="elk" +"Proposal Template": { + shape: sql_table + "content type": application/schema+json + "type [0]": 0ce8ab38-9258-4fbc-a62e-7faa6e58318f + "type [1]": 7808d2ba-d511-40af-84e8-c0d1625fdfdc + "id": UUIDv7 + "ver": UUIDv7 + "template": Proposal Meta Template (Optional) + "category_id": Category Parameters (Optional) + +} + +"Proposal Template"."template"->"Proposal Meta Template": Optional +"Proposal Template"."category_id"->"Category Parameters": Optional +``` + +### Validation + +TODO + +### Business Logic + +#### Front End + +TODO + +#### Back End + +TODO + +## [COSE Header Parameters][RFC9052-HeaderParameters] + +* [content type](../spec.md#content-type) = `application/schema+json` +* [content-encoding](../spec.md#content-encoding) = `[br]` + +## Metadata + +### `type` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Type](../metadata.md#document-type) | +| Type | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f`,
`7808d2ba-d511-40af-84e8-c0d1625fdfdc` | + +The document TYPE. + +#### Validation + +**MUST** be a known document type. + +### `id` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +Document ID, created the first time the document is created. +This must be a properly created [UUIDv7][RFC9562-V7] which contains the +timestamp of when the document was created. + +#### Validation + +IF [`ver`](../metadata.md#ver) does not == [`id`](../metadata.md#id) then a document with +[`id`](../metadata.md#id) and [`ver`](../metadata.md#ver) being equal *MUST* exist. + +### `ver` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](../metadata.md#uuidv7) | + +The unique version of the document. +The first version of the document must set [`ver`](../metadata.md#ver) == [`id`](../metadata.md#id) + +#### Validation + +The document version must always be >= the document ID. + +### `template` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](../metadata.md#document-reference) | +| Valid References | [Proposal Meta Template](proposal_meta_template.md) | + +Reference to the template used to create and/or validate this document. + +#### Validation + +In addition to the validation performed for `ref`, +The document payload is not valid if it does not validate completely against the referenced template. + +### `category_id` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](../metadata.md#document-reference) | +| Valid References | [Category Parameters](category_parameters.md) | +| Exclusive | brand_id | +| | campaign_id | + +A reference to the Category Parameters Document this document lies under. + +#### Validation + +In addition to the validation performed for `ref`, +Any referenced document that includes a [`category_id`](../metadata.md#category_id) must match the +[`category_id`](../metadata.md#category_id) of the referencing document. +It is also valid for the referenced document to not include this field, if it is +optional for the referenced document. + +## Payload + +[JSON Schema] document which defines the valid contents of a proposal document. + +## Signers + +The following admin roles may sign documents of this type: + +* Brand Admin +* Campaign Admin + +New versions of this document may be published by: + +* author + +## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[JSON Schema]: https://json-schema.org/draft-07 +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7 diff --git a/docs/src/architecture/08_concepts/signed_doc/meta.md b/docs/src/architecture/08_concepts/signed_doc/meta.md deleted file mode 100644 index 1344b2f8be..0000000000 --- a/docs/src/architecture/08_concepts/signed_doc/meta.md +++ /dev/null @@ -1,119 +0,0 @@ -# Metadata Fields List - - -??? note "Additional Metadata fields: `additional_meta.cddl`" - - ```CDDL - {{ include_file('src/architecture/08_concepts/signed_doc/cddl/additional_meta.cddl', indent=4) }} - ``` - - -* [Metadata Fields List](#metadata-fields-list) - * [`ref` Document Reference](#ref-document-reference) - * [`ref_hash` Secured Document Reference](#ref_hash-secured-document-reference) - * [`template` Template Reference](#template-template-reference) - * [`reply` Reply Reference](#reply-reply-reference) - * [`section` Section Reference](#section-section-reference) - * [`collabs` Authorized Collaborators](#collabs-authorized-collaborators) - * [`brand_id`](#brand_id) - * [`campaign_id`](#campaign_id) - * [`election_id`](#election_id) - * [`category_id`](#category_id) - -## `ref` Document Reference - -This is a reference to another document. -The purpose of the `ref` will vary depending on the document [`type`](./spec.md#type). - -The `ref` can be either a single [UUID] or a [CBOR] Array of Two [UUID]. - -If the `ref` is a single [UUID] v7, it is a reference to the document of that [`id`](./spec.md#id). -If the `ref` is a [CBOR] array, it has the form `[,]` where: - -* `` - the [UUID] v7 of the referenced documents [`id`](./spec.md#id). -* `` - the [UUID] v7 of the referenced documents [`ver`](./spec.md#ver). - -## `ref_hash` Secured Document Reference - -This is a cryptographically secured reference to another document. - -It consists of two fields: - -* [`ref`](#ref-document-reference) - simple reference to the document. -* `hash` - hash of the referenced document [CBOR] bytes. - -## `template` Template Reference - -If the document was formed from a template, this is a reference to that template document. -The format is the same as the [CBOR] Array form of [`ref`](#ref-document-reference). - -It is invalid not to reference the template that formed a document. -If this is missing from such documents, the document will itself be considered invalid. - -Template references must explicitly reference both the Template Document ID, and Version. - -## `reply` Reply Reference - -This is a reply to another document. -The format is the same as the [CBOR] Array form of [`ref`](#ref-document-reference). - -`reply` is always referencing a document of the same type, and that document must `ref` reference the same document `id`. -However, depending on the document type, it may reference a different `ver` of that `id`. - -## `section` Section Reference - -This is a reference to a section of a document. -It is a CBOR String, and contains a [JSON Path] identifying the section in question. - -Because this metadata field uses [JSON Path], it can only be used to reference a document whose payload is [JSON]. - -## `collabs` Authorized Collaborators - -This is a list of entities other than the original author that may also publish versions of this document. -This may be updated by the original author, or any collaborator that is given "author" privileges. - -The latest `collabs` list in the latest version, published by an authorized author is the definitive -list of allowed collaborators after that point. - -The `collabs` list is a [CBOR] Array. -The contents of the array are TBD. - -However, they will contain enough information such that each collaborator can be uniquely identified and validated. - -*Note: An Author can unilaterally set the `collabs` list to any list of collaborators. -It does NOT mean that the listed collaborators have agreed to collaborate, only that the Author -gives them permission to.* - -This list can impact actions that can be performed by the `Proposal Action Document`. - -## `brand_id` - -This is a reply to another document. -The format is the same as the [CBOR] Array form of [`ref`](#ref-document-reference). - -`brand_id` represents a "brand" who is running the voting, e.g. Catalyst, Midnight. - -## `campaign_id` - -This is a reply to another document. -The format is the same as the [CBOR] Array form of [`ref`](#ref-document-reference). - -`campaign_id` defines a "campaign" of voting, e.g. "treasury campaign". - -## `election_id` - -Unique identifier [UUID] v4, which defines an election, -e.g. "Catalyst Fund 1", "Catalyst Fund 2". - -## `category_id` - -This is a reply to another document. -The format is the same as the [CBOR] Array form of [`ref`](#ref-document-reference). - -`campaign_id` defines a voting category as a collection of proposals, -e.g. "Development & Infrastructure", "Products & Integrations". - -[UUID]: https://www.rfc-editor.org/rfc/rfc9562.html -[CBOR]: https://datatracker.ietf.org/doc/rfc8949/ -[JSON]: https://datatracker.ietf.org/doc/html/rfc7159 -[JSON Path]: https://datatracker.ietf.org/doc/html/rfc9535 diff --git a/docs/src/architecture/08_concepts/signed_doc/metadata.md b/docs/src/architecture/08_concepts/signed_doc/metadata.md new file mode 100644 index 0000000000..b088993e4f --- /dev/null +++ b/docs/src/architecture/08_concepts/signed_doc/metadata.md @@ -0,0 +1,319 @@ +# Metadata Fields + +## Metadata Types + +The following types of metadata have been defined. +All Metadata fields use one of these types. + +### Collaborators Reference List + +A list of collaborators who can participate in drafting and submitting a document + +#### [CDDL][RFC8610] Specification + +```cddl +catalyst_id = text +collaborators = [ * catalyst_id ] +``` + +### Document Reference + +A document reference identifier + +#### [CDDL][RFC8610] Specification + +```cddl +uuid_v7 = 6.37(bytes .size 16) +document_id = uuid_v7 +document_ver = uuid_v7 +blake2b_256 = bytes .size 32 +document_hash = blake2b_256 +document_ref = [ 1* [ document_id, document_ver, document_hash ] ] +``` + +### Document Type + +A document type identifier + +#### [CDDL][RFC8610] Specification + +```cddl +uuid_v4 = 6.37(bytes .size 16) +document_type = [ 1* uuid_v4 ] +``` + +### Section Reference + +A document section reference identifier + +#### [CDDL][RFC8610] Specification + +```cddl +json_pointer = text +section_ref = json_pointer +``` + +### [UUIDv4][RFC9562-V4] + +Version 4 formatted [UUID][RFC9562] + +#### [CDDL][RFC8610] Specification + +```cddl +uuid_v4 = 6.37(bytes .size 16) +``` + +### [UUIDv7][RFC9562-V7] + +Version 7 formatted [UUID][RFC9562] + +#### [CDDL][RFC8610] Specification + +```cddl +uuid_v7 = 6.37(bytes .size 16) +``` + +## Individual Metadata field definitions + +### `type` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [Document Type](metadata.md#document-type) | + +The document TYPE. + +#### Validation + +**MUST** be a known document type. + +### `id` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](metadata.md#uuidv7) | + +Document ID, created the first time the document is created. +This must be a properly created [UUIDv7][RFC9562-V7] which contains the +timestamp of when the document was created. + +#### Validation + +IF [`ver`](metadata.md#ver) does not == [`id`](metadata.md#id) then a document with +[`id`](metadata.md#id) and [`ver`](metadata.md#ver) being equal *MUST* exist. + +### `ver` + +| Parameter | Value | +| --- | --- | +| Required | yes | +| Format | [UUIDv7](metadata.md#uuidv7) | + +The unique version of the document. +The first version of the document must set [`ver`](metadata.md#ver) == [`id`](metadata.md#id) + +#### Validation + +The document version must always be >= the document ID. + +### `ref` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](metadata.md#document-reference) | +| Valid References | [Proposal Meta Template](./docs/proposal_meta_template.md) | +| | [Proposal Template](./docs/proposal_template.md) | +| | [Proposal](./docs/proposal.md) | +| | [Proposal Comment Meta Template](./docs/proposal_comment_meta_template.md) | +| | [Proposal Comment Template](./docs/proposal_comment_template.md) | +| | [Proposal Comment](./docs/proposal_comment.md) | +| | [Proposal Submission Action](./docs/proposal_submission_action.md) | +| | [Proposal Moderation Action](./docs/proposal_moderation_action.md) | +| | [Comment Action Document](./docs/comment_action_document.md) | +| | [Brand Parameters](./docs/brand_parameters.md) | +| | [Campaign Parameters](./docs/campaign_parameters.md) | +| | [Category Parameters](./docs/category_parameters.md) | +| | [Election Parameters](./docs/election_parameters.md) | + +Reference to a Linked Document or Documents. +This is the primary hierarchical reference to a related document. + +This is an Array of the format: + `[[DocumentID, DocumentVer, DocumentHash],...]` + +* `DocumentID` is the [UUIDv7][RFC9562-V7] ID of the Document being referenced. +* `DocumentVer` is the [UUIDv7][RFC9562-V7] Version of the Document being referenced. +* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload. + It ensures that the intended referenced document is the one used, and there has been no substitution. + Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one. + +#### Validation + +Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document. +The calculated Hash of the Referenced Document **MUST** match the Hash in the reference. + +### `template` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](metadata.md#document-reference) | +| Valid References | [Proposal Meta Template](./docs/proposal_meta_template.md) | +| | [Proposal Template](./docs/proposal_template.md) | +| | [Proposal Comment Meta Template](./docs/proposal_comment_meta_template.md) | +| | [Proposal Comment Template](./docs/proposal_comment_template.md) | + +Reference to the template used to create and/or validate this document. + +#### Validation + +In addition to the validation performed for `ref`, +The document payload is not valid if it does not validate completely against the referenced template. + +### `reply` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](metadata.md#document-reference) | +| Valid References | [Proposal Comment](./docs/proposal_comment.md) | + +Reference to a Comment document type being referred to. + +#### Validation + +In addition to the validation performed for `ref`, +The [`ref`](metadata.md#ref) of the [`reply`](metadata.md#reply) document must be the same as +the original comment document. + +### `section` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Section Reference](metadata.md#section-reference) | + +A Reference to the original document, or the comment being replied to. + +#### Validation + +For a non-reply this must be a valid section reference into the referenced document. +For a reply, this must be a valid section reference into the comment being replied to. + +### `collaborators` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Collaborators Reference List](metadata.md#collaborators-reference-list) | + +A list of collaborators who may also publish updates to versions of this document. +This should include all parties who have not signed this document directly. + +Every subsequent version can amend the collaborators list. +However, the initial Author can never be removed from being able to +publish a new version of the document. + +#### Validation + +This list does not imply these collaborators have consented to collaborate, only that the author/s +are permitting these potential collaborators to participate in the drafting and submission process. +However, any document submission referencing a proposal MUST be signed by all collaborators in +addition to the author. + +### `brand_id` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](metadata.md#document-reference) | +| Valid References | [Brand Parameters](./docs/brand_parameters.md) | +| Exclusive | campaign_id | +| | category_id | + +A reference to the Brand Parameters Document this document lies under. + +#### Validation + +In addition to the validation performed for `ref`, +Any referenced document that includes a [`brand_id`](metadata.md#brand_id) must match the [`brand_id`](metadata.md#brand_id) +of the referencing document. +It is also valid for the referenced document to not include this field, if it is +optional for the referenced document. + +### `campaign_id` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](metadata.md#document-reference) | +| Valid References | [Campaign Parameters](./docs/campaign_parameters.md) | +| Exclusive | brand_id | +| | category_id | + +A reference to the Campaign Parameters Document this document lies under. + +#### Validation + +In addition to the validation performed for `ref`, +Any referenced document that includes a [`campaign_id`](metadata.md#campaign_id) must match the +[`campaign_id`](metadata.md#campaign_id) of the referencing document. +It is also valid for the referenced document to not include this field, if it is +optional for the referenced document. + +### `category_id` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](metadata.md#document-reference) | +| Valid References | [Category Parameters](./docs/category_parameters.md) | +| Exclusive | brand_id | +| | campaign_id | + +A reference to the Category Parameters Document this document lies under. + +#### Validation + +In addition to the validation performed for `ref`, +Any referenced document that includes a [`category_id`](metadata.md#category_id) must match the +[`category_id`](metadata.md#category_id) of the referencing document. +It is also valid for the referenced document to not include this field, if it is +optional for the referenced document. + +### `election_id` + +| Parameter | Value | +| --- | --- | +| Required | optional | +| Format | [Document Reference](metadata.md#document-reference) | +| Valid References | [Election Parameters](./docs/election_parameters.md) | + +A reference to the Election Parameters Document this document lies under. + +#### Validation + +In addition to the validation performed for `ref`, +Any referenced document that includes a [`election_id`](metadata.md#election_id) must match the +[`election_id`](metadata.md#election_id) of the referencing document. +It is also valid for the referenced document to not include this field, if it is +optional for the referenced document. + +## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC9562-V4]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-4 +[RFC9562-V7]: https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7 +[RFC8610]: https://www.rfc-editor.org/rfc/rfc8610 +[RFC9562]: https://www.rfc-editor.org/rfc/rfc9562.html diff --git a/docs/src/architecture/08_concepts/signed_doc/spec.md b/docs/src/architecture/08_concepts/signed_doc/spec.md index 8537962b0e..7444f19ecb 100644 --- a/docs/src/architecture/08_concepts/signed_doc/spec.md +++ b/docs/src/architecture/08_concepts/signed_doc/spec.md @@ -1,176 +1,115 @@ ---- -Title: Catalyst Signed Document -Category: Catalyst -Status: Proposed -Authors: - - Steven Johnson - - Alex Pozhylenkov -Implementors: - - Catalyst Fund 14 -Discussions: [] -Created: 2024-12-27 -License: CC-BY-4.0 ---- - -* [Abstract](#abstract) -* [Motivation: why is this CIP necessary?](#motivation-why-is-this-cip-necessary) -* [Specification](#specification) - * [Catalyst Signed Document metadata fields](#catalyst-signed-document-metadata-fields) - * [`type`](#type) - * [`id`](#id) - * [`ver`](#ver) - * [`alg`](#alg) - * [`content type`](#content-type) - * [`content encoding` (optional)](#content-encoding-optional) - * [Catalyst Signed Document content](#catalyst-signed-document-content) - * [COSE signature protected header](#cose-signature-protected-header) -* [Copyright](#copyright) +# Catalyst Signed Document Specification ## Abstract -Project Catalyst both produces and consumes a lot of different data objects, -in different places of the system. -To ensure the data object is authoritative, it must be signed. -In addition to the data object content and the signature, metadata is also included -to describe different kind of Catalyst Signed Document properties. +Project Catalyst requires a verifiable data format for the publication and validation of +large volumes of off chain information. -## Motivation: why is this CIP necessary? +The Catalyst Signed Documents Specification is based on [COSE][RFC9052] +and provides the basis of this document specification. -As we decentralize project catalyst, it will be required to unambiguously identify who produced some -data object, and the purpose of it. +## Motivation -## Specification - -Catalyst Signed Document is [COSE] based structure, particularly `COSE Signed Data Object` [COSE] type. -It fully inherits an original [COSE] design and specifies the details of different [COSE] header's fields. - -### Catalyst Signed Document metadata fields - -To uniquely specify a Catalyst Signed Document `id`, `type`, `version` etc., -a list of different metadata fields is specified. - -Also as you can see from the specification, -it is allowed to add any number of additional metadata fields, which could be specified for each `type` of document. - -[A full list of considered additional metadata fields](./meta.md). - -All these fields will be encoded as the [COSE] `protected` header - - -??? note "Catalyst Signed Document metadata fields: `signed_doc_meta.cddl`" - - ```CDDL - {{ include_file('src/architecture/08_concepts/signed_doc/cddl/signed_doc_meta.cddl', indent=4) }} - ``` - - -#### `type` - -Each Catalyst Signed Document will have a type identifier called `type`. - -The `type` is a [UUID] v4. - -[A full list of Catalyst supported document types](./types.md) +As Project Catalyst decentralizes via both on-chain and off-chain mechanisms, a reliable, +standardized process for authenticating documents and their relationships is required. -#### `id` - -Every Catalyst Signed Document will have a unique ID. -All Catalyst Signed Document with the same `id` are considered different versions of the same Catalyst Signed Document -(read about [`ver`](#ver)). -However, `id` uniqueness is only guaranteed on first use. - -If the same `id` is used, by unauthorized publishers, the Catalyst Signed Document is invalid. - -The `id` is a [UUID] v7. - -The first time a Catalyst Signed Document is created, it will be assigned by the creator a new `id` which must -be well constructed. - -* The time must be the time the Catalyst Signed Document was first created. -* The random value must be truly random. - -Creating `id` this way ensures there are no collisions, and they can be independently created without central co-ordination. - -*Note: All Catalyst Signed Documents are signed, -the first creation of an `id` assigns that `id` to the creator and any assigned collaborators. -A Catalyst Signed Document that is not signed by the creator, or an assigned collaborator, is invalid. -There is no reasonable way an `id` can collide accidentally. -Therefore, detection of invalid `id`s published by unauthorized publishers, could result in anti-spam -or system integrity mitigations being triggered. -This could result in all actions in the system being blocked by the offending publisher, -including all otherwise legitimate publications by the same author being marked as fraudulent.* - -#### `ver` - -Every Catalyst Signed Document in the system will be versioned. -There can, and probably will, exist multiple versions of the same document. - -The `ver` is a [UUID] v7. - -The initial `ver` assigned the first time a Catalyst Signed Document is published **MUST** be identical to the [`id`](#id). -Subsequent versions will retain the same [`id`](#id) and will create a new `ver`, -following best practice for creating a new [UUID] v7. +## Specification -#### `alg` +Project Catalyst generates a large volume of off chain information. +This information requires similar guarantees as on-chain data. +It needs to be verifiably published and also immutable. +However, we also require the ability to publish new versions of documents, +and for documents to be able to securely reference one another. -This is an original [COSE] header field, -which indicates the cryptography algorithm used for the security processing. +Catalyst Signed Documents are based on [COSE][RFC9052]. +Specifically, the [COSE Sign][RFC9052-CoseSign] format is used. +This allows one or more signatures to be attached to the same document. - -!!! warning "" +### [COSE Header Parameters][RFC9052-HeaderParameters] - It must be equal to `EdDSA` value - +[COSE][RFC9052] documents define a set of standard [COSE header parameters][RFC9052-HeaderParameters]. +All [COSE Header Parameters][RFC9052-HeaderParameters] are protected and +*MUST* appear in the protected headers section of the document. +The [COSE header parameters][RFC9052-HeaderParameters] defined and used by Catalyst Signed Documents are as follows: -Only `ed25119` considered at this moment as the only option to be supported for signed objects. +#### content type -#### [`content type`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) +IANA Media Type/s allowed in the Payload -This is an original [COSE] header field, -which indicates the [`content type`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Type) -of the [content](#catalyst-signed-document-content) ([COSE] `payload`) data. +* Required : yes +* [Cose][RFC9052] Label : 3 +* Format : IANA Media Type + * Supported Values: + * [application/json] : [JSON][RFC8259] Document + * [application/schema+json] : [JSON Schema] Draft 7 Document; Note: + * This is currently an unofficial media type. + * Draft 7 is used because of its wide support by tooling. + * [application/cbor] : [RFC8949] Binary [CBOR][RFC8949] Encoded Document + * application/cddl : [CDDL][RFC8610] Document; Note: + * This is an unofficial media type + * [RFC9165] Additional Control Operators for [CDDL][RFC8610] are supported. + * Must not have Modules, schema must be self-contained. -#### [`content encoding`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding) (optional) +#### content-encoding -This field is used to indicate the [`content encoding`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding) -algorithm of the [content](#catalyst-signed-document-content) data. +Supported HTTP Encodings of the Payload. +If no compression or encoding is used, then this field must not be present. -Supported encodings: +* Required : optional +* [Cose][RFC9052] Label : content-encoding ***Custom Header*** +* Format : HTTP Content Encoding + * Supported Values: + * [br] : [BROTLI][RFC7932] Compression -* `br` - [Brotli] compressed data. +### Metadata -### Catalyst Signed Document content +Catalyst Signed Documents extend the Header Parameters with a series of Metadata fields. +These fields are defined [here](./metadata.md). -The Catalyst Signed Document content data is encoded (and could be additionally compressed, -read [`content encoding`](#content-encoding-optional)) as [COSE] `payload`. +### Signing Catalyst Signed Documents -### [COSE] signature protected header +Catalyst Signed Documents are based on the [COSE Sign][RFC9052-CoseSign] format. +This allows one or more signatures to be attached to the same document. +A catalyst signed document *MUST* have at least one valid signature attached. +Multiple signatures may also be attached to the same document, where that is required. -As it mentioned earlier, Catalyst Signed Document utilizes `COSE Signed Data Object` format, -which allows to provide multi-signature functionality. -In that regard, -each Catalyst Signed Document [COSE] signature **must** include the following `protected` header field: +Each signature is contained in an array of signatures attached to the document. +The signatures contain protected headers, and the signature itself. +The headers currently defined for the signatures are: - -```CDDL -; All encoders/decoders of this specification must follow deterministic cbor encoding rules -; https://datatracker.ietf.org/doc/html/draft-ietf-cbor-cde-06 +#### `kid` -signature_protected_header = { - 4 => bytes ; "kid", UTF-8 encoded URI string -} -``` - +The kid is a [UTF-8][RFC3629] encoded Catalyst ID. +Any `kid` format which conforms to the Catalyst ID specification may be used. +The Catalyst ID unambiguously defines both the signing keys and signing algorithm +used to sign the protected portion of the document. -* `kid`: A unique identifier of the signer. - A [UTF-8] encoded [URI] string. +* Required: yes +* [Cose][RFC9052] Label: 4 +* Format: [UTF-8][RFC3629] encoded Catalyst ID ## Copyright -This document is licensed under [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/legalcode). - -[Brotli]: https://datatracker.ietf.org/doc/html/rfc7932 -[UTF-8]: https://datatracker.ietf.org/doc/html/rfc3629 -[URI]: https://datatracker.ietf.org/doc/html/rfc3986 -[COSE]: https://datatracker.ietf.org/doc/html/rfc9052 -[UUID]: https://www.rfc-editor.org/rfc/rfc9562.html +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[application/schema+json]: https://datatracker.ietf.org/doc/draft-bhutton-json-schema/ +[RFC9052-HeaderParameters]: https://www.rfc-editor.org/rfc/rfc8152#section-3.1 +[application/cbor]: https://www.iana.org/assignments/media-types/application/cbor +[application/json]: https://www.iana.org/assignments/media-types/application/json +[JSON Schema]: https://json-schema.org/draft-07 +[RFC9052-CoseSign]: https://datatracker.ietf.org/doc/html/rfc9052#name-signing-with-one-or-more-si +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC8949]: https://www.rfc-editor.org/rfc/rfc8949.html +[RFC9165]: https://www.rfc-editor.org/rfc/rfc9165 +[RFC7932]: https://www.rfc-editor.org/rfc/rfc7932 +[RFC3629]: https://datatracker.ietf.org/doc/html/rfc3629 +[RFC8610]: https://www.rfc-editor.org/rfc/rfc8610 +[RFC9052]: https://datatracker.ietf.org/doc/html/rfc9052 +[RFC8259]: https://www.rfc-editor.org/rfc/rfc8259.html +[br]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding#br diff --git a/docs/src/architecture/08_concepts/signed_doc/types.md b/docs/src/architecture/08_concepts/signed_doc/types.md index eb3469f241..20ff6ba1db 100644 --- a/docs/src/architecture/08_concepts/signed_doc/types.md +++ b/docs/src/architecture/08_concepts/signed_doc/types.md @@ -1,26 +1,58 @@ # Document Types Table -| [UUID] | [CBOR] | Type Description | Payload Type | Specification Link | -| ------------------------------------ | ----------------------------------------- | ---------------------------- | --------------------------------- | ------------------------------------------------------------------------------ | -| 7808d2ba-d511-40af-84e8-c0d1625fdfdc | `37(h'7808d2bad51140af84e8c0d1625fdfdc')` | Proposal Document | [Brotli] Compressed [JSON] | [Proposal Spec](./../catalyst_docs/proposal.md#proposal-document) | -| 0ce8ab38-9258-4fbc-a62e-7faa6e58318f | `37(h'0ce8ab3892584fbca62e7faa6e58318f')` | Proposal Template | [Brotli] Compressed [JSON Schema] | [Proposal Template Spec](./../catalyst_docs/proposal.md#proposal-template) | -| b679ded3-0e7c-41ba-89f8-da62a17898ea | `37(h'b679ded30e7c41ba89f8da62a17898ea')` | Comment Document | [Brotli] Compressed [JSON] | [Comment Spec](./../catalyst_docs/comment.md#comment-document) | -| 0b8424d4-ebfd-46e3-9577-1775a69d290c | `37(h'0b8424d4ebfd46e395771775a69d290c')` | Comment Template | [Brotli] Compressed [JSON Schema] | [Comment Template Spec](./../catalyst_docs/comment.md#comment-template) | -| e4caf5f0-098b-45fd-94f3-0702a4573db5 | `37(h'e4caf5f0098b45fd94f30702a4573db5')` | Review Document | [Brotli] Compressed [JSON] | [Review Spec](./../catalyst_docs/review.md#review-document) | -| ebe5d0bf-5d86-4577-af4d-008fddbe2edc | `37(h'ebe5d0bf5d864577af4d008fddbe2edc')` | Review Template | [Brotli] Compressed [JSON Schema] | [Review Template Spec](./../catalyst_docs/review.md#review-template) | -| 48c20109-362a-4d32-9bba-e0a9cf8b45be | `37(h'48c20109362a4d329bbae0a9cf8b45be')` | Category Parameters Document | [Brotli] Compressed [JSON] | *TBD* | -| 65b1e8b0-51f1-46a5-9970-72cdf26884be | `37(h'65b1e8b051f146a5997072cdf26884be')` | Category Parameters Template | [Brotli] Compressed [JSON Schema] | *TBD* | -| 0110ea96-a555-47ce-8408-36efe6ed6f7c | `37(h'0110ea96a55547ce840836efe6ed6f7c')` | Campaign Parameters Document | [Brotli] Compressed [JSON] | *TBD* | -| 7e8f5fa2-44ce-49c8-bfd5-02af42c179a3 | `37(h'7e8f5fa244ce49c8bfd502af42c179a3')` | Campaign Parameters Template | [Brotli] Compressed [JSON Schema] | *TBD* | -| 3e4808cc-c86e-467b-9702-d60baa9d1fca | `37(h'3e4808ccc86e467b9702d60baa9d1fca')` | Brand Parameters Document | [Brotli] Compressed [JSON] | *TBD* | -| fd3c1735-80b1-4eea-8d63-5f436d97ea31 | `37(h'fd3c173580b14eea8d635f436d97ea31')` | Brand Parameters Template | [Brotli] Compressed [JSON Schema] | *TBD* | -| 5e60e623-ad02-4a1b-a1ac-406db978ee48 | `37(h'5e60e623ad024a1ba1ac406db978ee48')` | Proposal Action Document | *TBD* | *TBD* | -| 8de5586c-e998-4b95-8742-7be3c8592803 | `37(h'8DE5586CE9984B9587427BE3C8592803')` | Public Vote Tx V2 | [Brotli] Compressed [CBOR] | [Public Vote Tx V2 Spec](./../catalyst_voting/v2.md#public-vote) | -| e78ee18d-f380-44c1-a852-80aa6ecb07fe | `37(h'E78EE18DF38044C1A85280AA6ECB07FE')` | Private Vote Tx V2 | [Brotli] Compressed [CBOR] | [Private Vote Tx V2 Spec](./../catalyst_voting/v2.md#private-vote) | -| d9e7e6ce-2401-4d7d-9492-f4f7c64241c3 | `37(h'D9E7E6CE24014D7D9492F4F7C64241C3')` | Immutable Ledger Block | [Brotli] Compressed [CBOR] | [Immutable Ledger Block Spec](./../immutable_ledger/ledger.md#block-structure) | - -[JSON Schema]: https://json-schema.org/draft-07 -[JSON]: https://datatracker.ietf.org/doc/html/rfc7159 -[Brotli]: https://datatracker.ietf.org/doc/html/rfc7932 -[CBOR]: https://datatracker.ietf.org/doc/html/rfc8610 -[UUID]: https://www.rfc-editor.org/rfc/rfc9562.html +## Document Base Types + +All Document Types are defined by composing these base document types: + +| Base Type | [UUID][RFC9562] | [CBOR][RFC8949] | +| :--- | :--- | :--- | +| Action | `5e60e623-ad02-4a1b-a1ac-406db978ee48` | `37(h'5e60e623ad024a1ba1ac406db978ee48')` | +| Brand | `ebcabeeb-5bc5-4f95-91e8-cab8ca724172` | `37(h'ebcabeeb5bc54f9591e8cab8ca724172')` | +| Campaign | `5ef32d5d-f240-462c-a7a4-ba4af221fa23` | `37(h'5ef32d5df240462ca7a4ba4af221fa23')` | +| Category | `818938c3-3139-4daa-afe6-974c78488e95` | `37(h'818938c331394daaafe6974c78488e95')` | +| Comment | `b679ded3-0e7c-41ba-89f8-da62a17898ea` | `37(h'b679ded30e7c41ba89f8da62a17898ea')` | +| Election | `788ff4c6-d65a-451f-bb33-575fe056b411` | `37(h'788ff4c6d65a451fbb33575fe056b411')` | +| ModerationAction | `a5d232b8-5e03-4117-9afd-be32b878fcdd` | `37(h'a5d232b85e0341179afdbe32b878fcdd')` | +| Proposal | `7808d2ba-d511-40af-84e8-c0d1625fdfdc` | `37(h'7808d2bad51140af84e8c0d1625fdfdc')` | +| SubmissionAction | `78927329-cfd9-4ea1-9c71-0e019b126a65` | `37(h'78927329cfd94ea19c710e019b126a65')` | +| Template | `0ce8ab38-9258-4fbc-a62e-7faa6e58318f` | `37(h'0ce8ab3892584fbca62e7faa6e58318f')` | + +## Document Types + +All Defined Document Types + + +| Document Type | Base Types | [CBOR][RFC8949] | +| :--- | :--- | :--- | +| [Brand Parameters](./docs/brand_parameters.md) | Brand | [37(h'ebcabeeb5bc54f9591e8cab8ca724172')] | +| [Campaign Parameters](./docs/campaign_parameters.md) | Campaign | [37(h'5ef32d5df240462ca7a4ba4af221fa23')] | +| [Category Parameters](./docs/category_parameters.md) | Category | [37(h'818938c331394daaafe6974c78488e95')] | +| [Comment Action Document](./docs/comment_action_document.md) | Action/Comment/ModerationAction | [37(h'5e60e623ad024a1ba1ac406db978ee48'),
37(h'b679ded30e7c41ba89f8da62a17898ea'),
37(h'a5d232b85e0341179afdbe32b878fcdd')] | +| [Election Parameters](./docs/election_parameters.md) | Election | [37(h'788ff4c6d65a451fbb33575fe056b411')] | +| [Proposal](./docs/proposal.md) | Proposal | [37(h'7808d2bad51140af84e8c0d1625fdfdc')] | +| [Proposal Comment](./docs/proposal_comment.md) | Comment/Proposal | [37(h'b679ded30e7c41ba89f8da62a17898ea'),
37(h'7808d2bad51140af84e8c0d1625fdfdc')] | +| [Proposal Comment Meta Template](./docs/proposal_comment_meta_template.md) | Template/Template/Comment/Proposal | [37(h'0ce8ab3892584fbca62e7faa6e58318f'),
37(h'0ce8ab3892584fbca62e7faa6e58318f'),
37(h'b679ded30e7c41ba89f8da62a17898ea'),
37(h'7808d2bad51140af84e8c0d1625fdfdc')] | +| [Proposal Comment Template](./docs/proposal_comment_template.md) | Template/Comment/Proposal | [37(h'0ce8ab3892584fbca62e7faa6e58318f'),
37(h'b679ded30e7c41ba89f8da62a17898ea'),
37(h'7808d2bad51140af84e8c0d1625fdfdc')] | +| [Proposal Meta Template](./docs/proposal_meta_template.md) | Template/Template/Proposal | [37(h'0ce8ab3892584fbca62e7faa6e58318f'),
37(h'0ce8ab3892584fbca62e7faa6e58318f'),
37(h'7808d2bad51140af84e8c0d1625fdfdc')] | +| [Proposal Moderation Action](./docs/proposal_moderation_action.md) | Action/Proposal/ModerationAction | [37(h'5e60e623ad024a1ba1ac406db978ee48'),
37(h'7808d2bad51140af84e8c0d1625fdfdc'),
37(h'a5d232b85e0341179afdbe32b878fcdd')] | +| [Proposal Submission Action](./docs/proposal_submission_action.md) | Action/Proposal/SubmissionAction | [37(h'5e60e623ad024a1ba1ac406db978ee48'),
37(h'7808d2bad51140af84e8c0d1625fdfdc'),
37(h'78927329cfd94ea19c710e019b126a65')] | +| [Proposal Template](./docs/proposal_template.md) | Template/Proposal | [37(h'0ce8ab3892584fbca62e7faa6e58318f'),
37(h'7808d2bad51140af84e8c0d1625fdfdc')] | + + +## Document Relationship Hierarchy + +![Document Relationship Hierarchy](doc_relationships.svg) + +## Copyright + +| Copyright | :copyright: 2024-2025 IOG Singapore, All Rights Reserved | +| --- | --- | +| License | This document is licensed under [CC-BY-4.0] | +| Created | 2024-12-27 | +| Modified | 2025-04-04 | +| Authors | Alex Pozhylenkov | +| | Steven Johnson | + +[CC-BY-4.0]: https://creativecommons.org/licenses/by/4.0/legalcode +[RFC8949]: https://www.rfc-editor.org/rfc/rfc8949.html +[RFC9562]: https://www.rfc-editor.org/rfc/rfc9562.html diff --git a/specs/Earthfile b/specs/Earthfile new file mode 100644 index 0000000000..b396d9d92a --- /dev/null +++ b/specs/Earthfile @@ -0,0 +1,37 @@ +VERSION 0.8 + +# cspell: words cuelang + +# Get cue binary +cue-bin: + FROM cuelang/cue:0.12.0 + SAVE ARTIFACT /usr/bin/cue + + +# builder - debian plus cue binary +builder: + FROM debian:stable-20250203-slim + COPY +cue-bin/cue /usr/bin/cue + +# Copy all the source we need to build the docs +src: + FROM +builder + + WORKDIR /src + COPY . . + ENV CUE_EXPERIMENT="embed" + + SAVE ARTIFACT signed_doc.json + + +check: + FROM +src + RUN cue fmt --check --files . + RUN cue vet ./signed_docs/docs:signed_docs signed_doc.json + +# Regenerate - using the builder +regenerate: + FROM +src + + RUN cue export -f -s ./signed_docs/docs:signed_docs --out json --outfile signed_doc.json + SAVE ARTIFACT --keep-ts signed_doc.json AS LOCAL . \ No newline at end of file diff --git a/specs/Justfile b/specs/Justfile new file mode 100644 index 0000000000..d9982359eb --- /dev/null +++ b/specs/Justfile @@ -0,0 +1,45 @@ +# use with https://github.com/casey/just +# +# Developer convenience functions + +# required to get cuelang to enable file embedding +export CUE_EXPERIMENT := "embed" +default: + @just --list --unsorted + +# Fiz (where possible) and format cue files +format: + cue fix ./signed_docs/docs:signed_docs + cue fmt --files . + +# Check the signed document cue files are valid. +check: format + cue vet ./signed_docs/docs:signed_docs -c + +# Fix and Check Markdown files +regenerate: check + # Make sure keys are sorted so its both reproducible, AND diffs easily. + cue export -f -s ./signed_docs/docs:signed_docs --out json | jq -S > signed_doc.json + # Generate the markdown docs from the specification. + cd gen_docs; ./generate_docs.py -g -o "../../docs/src/architecture/08_concepts/signed_doc" ../signed_doc.json + # Check our validation code actually works properly + cd gen_docs; ./generate_docs.py -o "../../docs/src/architecture/08_concepts/signed_doc" ../signed_doc.json + # Generate an .svg from the d2 diagram + d2 "../docs/src/architecture/08_concepts/signed_doc/doc_relationships.d2" + + +# Validate the generated signed_docs.json is correct against the cue schema. +validate: + cue vet ./signed_docs/docs:signed_docs signed_doc.json + +# Pre Push Checks - intended to be run by a git pre-push hook. +pre-push: format-python-code lint-python regenerate validate + +# Fix and Check Markdown files +format-python-code: + ruff check --select I --fix . + ruff format . + +# Fix and Check Markdown files +lint-python: + ruff check . \ No newline at end of file diff --git a/specs/blueprint.cue b/specs/blueprint.cue new file mode 100644 index 0000000000..2d96c1be9e --- /dev/null +++ b/specs/blueprint.cue @@ -0,0 +1,2 @@ +version: "1.0.0" +project: name: "catalyst-data-specifications" diff --git a/specs/cue.mod/module.cue b/specs/cue.mod/module.cue new file mode 100644 index 0000000000..aad96b47e7 --- /dev/null +++ b/specs/cue.mod/module.cue @@ -0,0 +1,4 @@ +module: "github.com/input-output-hk/catalyst-libs/specs" +language: { + version: "v0.11.2" +} diff --git a/specs/gen_docs/__init__.py b/specs/gen_docs/__init__.py new file mode 100644 index 0000000000..52e577c30a --- /dev/null +++ b/specs/gen_docs/__init__.py @@ -0,0 +1 @@ +# Intentionally Empty diff --git a/specs/gen_docs/common.py b/specs/gen_docs/common.py new file mode 100644 index 0000000000..63549797ee --- /dev/null +++ b/specs/gen_docs/common.py @@ -0,0 +1,170 @@ +# Common documentation generation functions +import glob +import os +from datetime import datetime + + +def get_latest_file_change(directory): + # Use glob to find all files ending with .cue in the directory + cue_files = glob.glob(os.path.join(directory, "*.cue")) + + if not cue_files: + return "????-??-??" + + latest_file = max(cue_files, key=os.path.getmtime) + file_mod_time = os.path.getmtime(latest_file) + mod_date = datetime.fromtimestamp(file_mod_time).strftime("%Y-%m-%d") + + return mod_date + + +def insert_copyright(doc_data, document_name=None): + """ + Generate a copyright notice into the given document data. + + document_name: Name of the signed document we also get copyright info from. + """ + authors = doc_data["authors"] + copyright = doc_data["copyright"] + global_last_modified = get_latest_file_change("../signed_docs") + + copyright_year = copyright["created"][:4] + last_modified_year = global_last_modified[:4] + if last_modified_year != copyright_year: + copyright_year = f"{copyright_year}-{last_modified_year}" + + copyright_notice = ( + f""" +## Copyright + +| Copyright | :copyright: {copyright_year} {copyright["copyright"]} | +| --- | --- | +| License | This document is licensed under {copyright["license"]} | +| Created | {copyright["created"]} | +| Modified | {global_last_modified} | +""".strip() + + "\n" + ) + + author_title = " Authors " + for author in authors: + copyright_notice += f"|{author_title}| {author} <{authors[author]}> |\n" + author_title = " " + + return copyright_notice + + +def metadata_format_link(name: str, depth: int = 0): + """ + Metadata Format link. + """ + link = f"metadata.md#{name.lower().replace(' ', '-')}" + + while depth > 0: + link = f"../{link}" + depth -= 1 + + return f"[{name}]({link})" + + +def doc_ref_link(name: str, depth: int = 0): + """ + Metadata Document Reference link. + """ + link = name.lower().replace(" ", "_") + ".md" + + if depth == 0: + link = f"./docs/{link}" + else: + while depth > 1: + link = f"../{link}" + depth -= 1 + + return f"[{name}]({link})" + + +def metadata_field_link(name: str, depth: int = 0): + """ + Metadata Field link. + """ + link = f"metadata.md#{name.lower().replace('`', '')}" + + while depth > 0: + link = f"../{link}" + depth -= 1 + + return f"[`{name}`]({link})" + + +def metadata_fields(doc_data: dict, doc_name: str = None, depth: int = 0): + """ + Display Metadata fields for the default set, or a specific document. + """ + field_title_level = "###" + if doc_name is not None: + fields = doc_data["docs"][doc_name]["metadata"] + else: + fields = doc_data["metadata"] + + order = doc_data["metadata_order"] + + # make sure every field is listed in the ordering + for field_name in fields: + if field_name not in order: + order += field_name + + field_display = "" + for field_name in order: + field = fields[field_name] + # Don't display excluded fields in the docs for individual doc pages + if doc_name is not None: + if field["required"] == "excluded": + continue + + field_display += f""" +{field_title_level} `{field_name}` + +| Parameter | Value | +| --- | --- | +| Required | {field["required"]} | +""" + if field["required"] == "excluded": + continue + + field_display += ( + f"| Format | {metadata_format_link(field['format'], depth)} |\n" + ) + + if doc_name is not None: + if field_name == "type": + # Display the actual documents type values + monospace_types = [] + for type in doc_data["docs"][doc_name]["type"]: + monospace_types.append(f"`{type}`") + field_display += f"| Type | {',
'.join(monospace_types)} |\n" + + if field.get("multiple", False): + field_display += f"| Multiple References | {field['multiple']} |\n" + if "type" in field: + ref_heading = "Valid References" + ref_doc_names = field["type"] + if isinstance(ref_doc_names, str): + ref_doc_names = [ref_doc_names] + for ref_doc in ref_doc_names: + field_display += f"| {ref_heading} | {doc_ref_link(ref_doc, depth)} |\n" + ref_heading = "" + exclusive = field.get("exclusive", None) + if exclusive is not None: + exclusive_title = "Exclusive" + for ref in exclusive: + field_display += f"| {exclusive_title} | {ref} |\n" + exclusive_title = "" + + field_display += f""" +{field["description"]} + +{field_title_level}# Validation + +{field["validation"]} +""" + return field_display.strip() diff --git a/specs/gen_docs/gen_docs_page_md.py b/specs/gen_docs/gen_docs_page_md.py new file mode 100644 index 0000000000..71056eeece --- /dev/null +++ b/specs/gen_docs/gen_docs_page_md.py @@ -0,0 +1,141 @@ +# Generate the spec.md file +import json +from urllib.parse import urlparse + +from common import insert_copyright, metadata_fields +from gen_docs_relationship_diagram_d2 import gen_doc_d2 + + +def header_parameter_summary(name, doc_defs: dict) -> str: + """ + Generate concrete Cose header parameter settings for a specific document. + """ + headers = doc_defs["docs"][name]["headers"] + header_docs = "" + for header in headers: + value = headers[header]["value"] + if isinstance(value, list): + value = f"[{','.join(value)}]" + link = f"../spec.md#{header.replace(' ', '-')}" + header_docs += f"* [{header}]({link}) = `{value}`\n" + return header_docs.strip() + + +def metadata_summary(name, doc_defs: dict) -> str: + """ + Generate concrete Metadata summary for a specific document. + """ + return metadata_fields(doc_defs, name, depth=1) + + +def uri_validator(uri: str): + try: + result = urlparse(uri) + return all([result.scheme in ["http", "https"], result.netloc]) + except Exception as _e: + return False + + +def document_payload(name: str, doc_defs: dict) -> str: + """ + Generate Payload Documentation + """ + if "payload" not in doc_defs["docs"][name]: + return "TODO" + + payload = doc_defs["docs"][name]["payload"] + + payload_docs = payload["description"] + "\n" + + if "schema" in payload: + schema = payload["schema"] + if uri_validator(schema): + if schema == "https://json-schema.org/draft-07/schema": + payload_docs += "\n**Must be a valid JSON Schema Draft 7 document.**" + else: + payload_docs += f"\nMust be a valid according to <{schema}>." + else: + payload_docs += f"""\nSchema : + +```json +{json.dumps(schema, indent=2, sort_keys=True)} +``` + +""" + + return payload_docs.strip() + + +def document_signers(name: str, doc_defs: dict) -> str: + """ + Generate documentation about who may sign this document.s + """ + signers = doc_defs["docs"][name]["signers"] + signers_doc = "" + + for role_group in signers["roles"]: + roles = signers["roles"][role_group] + if roles: + signers_doc += f"\nThe following {role_group} roles may sign documents of this type:\n\n" + for role in roles: + signers_doc += f"* {role}\n" + + signers_doc = signers_doc.strip() + + signers_doc += "\n\nNew versions of this document may be published by:\n\n" + for updater in signers["update"]: + if signers["update"][updater]: + signers_doc += f"* {updater}\n" + + return signers_doc.strip() + + +def gen_docs_page_md(name: str, doc_defs: dict) -> str: + """ + Generate an individual Documents Specification Page file from the definitions. + """ + + doc_d2 = gen_doc_d2(name, doc_defs, depth=1, stand_alone=True).strip() + return f""" +# {name} + +## Description + +{doc_defs["docs"][name].get("description", "TODO")} + +```d2 layout="elk" +{doc_d2} +``` + +### Validation + +{doc_defs["docs"][name].get("validation", "TODO")} + +### Business Logic + +#### Front End + +{doc_defs["docs"][name].get("business_logic", {}).get("front_end", "TODO")} + +#### Back End + +{doc_defs["docs"][name].get("business_logic", {}).get("back_end", "TODO")} + +## COSE Header Parameters + +{header_parameter_summary(name, doc_defs)} + +## Metadata + +{metadata_summary(name, doc_defs)} + +## Payload + +{document_payload(name, doc_defs)} + +## Signers + +{document_signers(name, doc_defs)} + +{insert_copyright(doc_defs)} +""" diff --git a/specs/gen_docs/gen_docs_relationship_diagram_d2.py b/specs/gen_docs/gen_docs_relationship_diagram_d2.py new file mode 100644 index 0000000000..6f32c59937 --- /dev/null +++ b/specs/gen_docs/gen_docs_relationship_diagram_d2.py @@ -0,0 +1,100 @@ +# Generate the spec.md file +# from common import doc_ref_link, insert_copyright +from common import insert_copyright + +doc_config = """ +vars: { + d2-config: { + layout-engine: elk + theme-id: 4 + pad: 100 + center: true + } +} +""" + +title = """ +title: |~md + # Signed Document Relationship Hierarchy +~| {near: top-center} +""" + + +def gen_doc_d2(doc: str, doc_defs: dict, depth=0, stand_alone=False) -> str: + """ + Generate an individual d2 table for an individual document. + """ + ref_links = "" + + doc_data = doc_defs["docs"][doc] + doc_metadata = doc_data["metadata"] + doc_type = doc_data["type"] + + metadata_rows = "" + + for meta in doc_defs["metadata_order"]: + if meta in doc_metadata and doc_metadata[meta]["required"] != "excluded": + if meta == "type": + type_count = 0 + for uuid in doc_type: + metadata_rows += f' "type [{type_count}]": {uuid}\n' + type_count += 1 + elif doc_metadata[meta]["format"] == "Document Reference": + ref_doc = doc_metadata[meta].get("type", "Unspecified") + if doc_metadata[meta]["required"] == "optional": + metadata_rows += f' "{meta}": {ref_doc} (Optional)\n' + if ref_doc == doc: + ref_links += ( + f'"{doc}"."{meta}"->"{ref_doc}": <{meta}> Optional\n' + ) + else: + ref_links += f'"{doc}"."{meta}"->"{ref_doc}": Optional\n' + else: + metadata_rows += f' "{meta}": {ref_doc}\n' + if ref_doc == doc: + ref_links += f'"{doc}"."{meta}"->"{ref_doc}": <{meta}>n' + else: + ref_links += f'"{doc}"."{meta}"->"{ref_doc}"\n' + # if stand_alone: + # if ref_doc != doc: + # ref_links += f'"{ref_doc}".shape=document\n' + # ref_links += f'"{ref_doc}".link={doc_ref_link(ref_doc, depth)}\n' + else: + metadata_rows += f' "{meta}": {doc_metadata[meta]["format"]}\n' + + return f""" +"{doc}": {{ + shape: sql_table + "content type": {doc_defs["docs"][doc]["headers"]["content type"]["value"]} +{metadata_rows} +}} + +{ref_links} +""" + + +def gen_doc_diagram(doc, doc_defs: dict) -> str: + """ + Generate a D2 Relationship diagram for a single document. + """ + doc_table = gen_doc_d2(doc, doc_defs) + + return doc_config + doc_table + + +def gen_docs_relationship_diagram(doc_defs: dict) -> str: + """ + Generate a D2 Relationship diagram for all documents and their references. + """ + + copyright = f""" +copyright: |~md + {insert_copyright(doc_defs)} +~| {{near: bottom-right}} +""" + + doc_tables = "" + for doc in doc_defs["docs"]: + doc_tables += gen_doc_d2(doc, doc_defs) + + return doc_config + title + copyright + doc_tables diff --git a/specs/gen_docs/gen_metadata_md.py b/specs/gen_docs/gen_metadata_md.py new file mode 100644 index 0000000000..98cc1aa0aa --- /dev/null +++ b/specs/gen_docs/gen_metadata_md.py @@ -0,0 +1,68 @@ +# Generate the spec.md file +from common import insert_copyright, metadata_fields + + +def get_cddl(name, defs, found=[]): + """ + Get the CDDL for a metadatum. + """ + this_cddl = "" + # Add required definitions to this one (recursive) + for requires in defs[name]["requires"]: + if requires not in found: + next_cddl, found = get_cddl(requires, defs, found) + found.append(requires) + this_cddl += next_cddl + this_cddl += f"{name} = {defs[name]['def']}\n" + + return this_cddl, found + + +def metadata_types(doc_defs): + """ + Generate the metadata types documentation. + """ + metadata = doc_defs["metadataFormats"] + cddl = doc_defs["cddlDefinitions"] + + metadata_types = "" + + for metadatum in metadata: + cddl_def, _ = get_cddl(metadata[metadatum]["cddl"], cddl) + cddl_def = cddl_def.strip() + # TODO: We could check if the `cddl_def` is actually valid CDDL here. + metadata_types += f""" +### {metadatum} + +{metadata[metadatum]["description"]} + +#### CDDL Specification + +```cddl +{cddl_def} +``` +""" + + return metadata_types.strip() + + +def gen_metadata_md(doc_defs): + """ + Generate a `metadata.md` file from the definitions. + """ + return f""" +# Metadata Fields + +## Metadata Types + +The following types of metadata have been defined. +All Metadata fields use one of these types. + +{metadata_types(doc_defs)} + +## Individual Metadata field definitions + +{metadata_fields(doc_defs)} + +{insert_copyright(doc_defs)} +""" diff --git a/specs/gen_docs/gen_spec_index.py b/specs/gen_docs/gen_spec_index.py new file mode 100644 index 0000000000..2e9afcc0bd --- /dev/null +++ b/specs/gen_docs/gen_spec_index.py @@ -0,0 +1,15 @@ +# Generate the spec.md file + + +def gen_spec_index(doc_defs): + """ + Generate a `.pages` file for the base specification files. + """ + return """ +title: Catalyst Signed Document +nav: + - Specification: spec.md + - Metadata Fields: metadata.md + - Document Types: types.md + - docs +""" diff --git a/specs/gen_docs/gen_spec_md.py b/specs/gen_docs/gen_spec_md.py new file mode 100644 index 0000000000..e0fcd65572 --- /dev/null +++ b/specs/gen_docs/gen_spec_md.py @@ -0,0 +1,135 @@ +# Generate the spec.md file +from common import insert_copyright + + +def header_parameter_doc(header, doc_data): + """ + Create documentation for a single cose header. + """ + options = doc_data["cose_headers"][header] + content_types = doc_data["contentTypes"] + encoding_types = doc_data["encodingTypes"] + label = options.get("coseLabel") + custom_header = "***Custom Header***" + if not isinstance(label, str): + custom_header = "" + header_format = options["format"] + header_value = options.get("value", None) + header_format_display = f"{header_format}" + if isinstance(header_value, list) and len(header_value) > 0: + header_format_display += "\n * Supported Values:" + for value in header_value: + value_entry = f"\n * {value}" + value_data = None + if header_format == "IANA Media Type" and value in content_types: + value_data = content_types[value] + if header_format == "HTTP Content Encoding" and value in encoding_types: + value_data = encoding_types[value] + + if value_data is not None: + value_entry += ( + f" : {value_data['description'].replace('\n', '\n ')}" + ) + + header_format_display += value_entry + + return f""" +#### {header} + +{options.get("description")} + +* Required : {options["required"]} +* Cose Label : {label} {custom_header} +* Format : {header_format_display} +""" + + +def cose_header_parameters(doc_data): + """ + Insert details about Cose header Parameters that are defined for use. + """ + headers = doc_data["cose_headers"] + header_order = doc_data["cose_headers_order"] + # Make sure unordered headers get included in the documentation. + for header in headers: + if header not in header_order: + header_order += header + + header_parameters_doc = "" + for header in header_order: + header_parameters_doc += header_parameter_doc(header, doc_data) + headers.pop(header) + + return header_parameters_doc.strip() + + +def gen_spec_md(doc_defs): + """ + Generate a `spec.md` file from the definitions. + """ + return f""" +# Catalyst Signed Document Specification + +## Abstract + +Project Catalyst requires a verifiable data format for the publication and validation of +large volumes of off chain information. + +The Catalyst Signed Documents Specification is based on COSE +and provides the basis of this document specification. + +## Motivation + +As Project Catalyst decentralizes via both on-chain and off-chain mechanisms, a reliable, +standardized process for authenticating documents and their relationships is required. + +## Specification + +Project Catalyst generates a large volume of off chain information. +This information requires similar guarantees as on-chain data. +It needs to be verifiably published and also immutable. +However, we also require the ability to publish new versions of documents, +and for documents to be able to securely reference one another. + +Catalyst Signed Documents are based on COSE. +Specifically, the COSE Sign format is used. +This allows one or more signatures to be attached to the same document. + +### COSE Header Parameters + +COSE documents define a set of standard COSE header parameters. +All COSE Header Parameters are protected and +*MUST* appear in the protected headers section of the document. +The COSE header parameters defined and used by Catalyst Signed Documents are as follows: + +{cose_header_parameters(doc_defs)} + +### Metadata + +Catalyst Signed Documents extend the Header Parameters with a series of Metadata fields. +These fields are defined [here](./metadata.md). + +### Signing Catalyst Signed Documents + +Catalyst Signed Documents are based on the COSE Sign format. +This allows one or more signatures to be attached to the same document. +A catalyst signed document *MUST* have at least one valid signature attached. +Multiple signatures may also be attached to the same document, where that is required. + +Each signature is contained in an array of signatures attached to the document. +The signatures contain protected headers, and the signature itself. +The headers currently defined for the signatures are: + +#### `kid` + +The kid is a UTF-8 encoded Catalyst ID. +Any `kid` format which conforms to the Catalyst ID specification may be used. +The Catalyst ID unambiguously defines both the signing keys and signing algorithm +used to sign the protected portion of the document. + +* Required: yes +* Cose Label: 4 +* Format: UTF-8 encoded Catalyst ID + +{insert_copyright(doc_defs)} +""" diff --git a/specs/gen_docs/gen_types_md.py b/specs/gen_docs/gen_types_md.py new file mode 100644 index 0000000000..b94fbd1699 --- /dev/null +++ b/specs/gen_docs/gen_types_md.py @@ -0,0 +1,110 @@ +# Generate the spec.md file +from common import insert_copyright + + +def uuid_as_cbor(uuid): + return f"37(h'{uuid.replace('-', '')}')" + + +def name_to_spec_link(name, ref=None): + """ + Create a link to a document type, and an optional ref inside the document. + """ + link = "./docs/" + name.lower().replace(" ", "_") + ".md" + if ref is not None: + link += f"#{ref}" + return link + + +def name_for_uuid(doc_types, uuid): + """ + Get the name for a document base type, given its uuid + """ + for k in doc_types: + if doc_types[k] == uuid: + return k + return "Unknown" + + +def base_types(docs, doc_types, name): + types = docs[name]["type"] + type_names = "" + for sub_type in types: + type_names += name_for_uuid(doc_types, sub_type) + "/" + return type_names[:-1] + + +def types_as_cbor(docs, name): + types = docs[name]["type"] + type_names = "[" + for sub_type in types: + type_names += uuid_as_cbor(sub_type) + ",
" + return type_names[:-6] + "]" + + +def doc_type_details(doc_data): + """ + Generate a Document Type Detailed Summary from the Document Specifications Data + """ + + doc_types = doc_data["base_types"] + docs = doc_data["docs"] + + doc_type_details = """ + +| Document Type | Base Types | CBOR | +| :--- | :--- | :--- | +""" + + for k in docs: + doc_type_details += f"| [{k}]({name_to_spec_link(k)}) | {base_types(docs, doc_types, k)} | {types_as_cbor(docs, k)} |\n" + + doc_type_details += "" + + return doc_type_details.strip() + + +def doc_type_summary(doc_data): + """ + Generate a Document Base Type Summary from the Document Specifications Data + """ + doc_types = doc_data["base_types"] + + doc_type_summary = """ +| Base Type | UUID | CBOR | +| :--- | :--- | :--- | +""" + + for k in doc_types: + doc_type_summary += ( + f"| {k} | `{doc_types[k]}` | `{uuid_as_cbor(doc_types[k])}` |\n" + ) + + return doc_type_summary.strip() + + +def gen_types_md(doc_defs): + """ + Generate a `types.md` file from the definitions. + """ + return f""" +# Document Types Table + +## Document Base Types + +All Document Types are defined by composing these base document types: + +{doc_type_summary(doc_defs)} + +## Document Types + +All Defined Document Types + +{doc_type_details(doc_defs)} + +## Document Relationship Hierarchy + +![Document Relationship Hierarchy](doc_relationships.svg) + +{insert_copyright(doc_defs)} +""" diff --git a/specs/gen_docs/generate_docs.py b/specs/gen_docs/generate_docs.py new file mode 100755 index 0000000000..f4aff5e0f2 --- /dev/null +++ b/specs/gen_docs/generate_docs.py @@ -0,0 +1,318 @@ +#!/usr/bin/env python + +# Autogenerate Documentation Pages from the formal specification + +import argparse +import json +import re +from pathlib import Path + +from common import doc_ref_link, metadata_field_link +from gen_docs_page_md import gen_docs_page_md +from gen_docs_relationship_diagram_d2 import gen_docs_relationship_diagram +from gen_metadata_md import gen_metadata_md +from gen_spec_index import gen_spec_index +from gen_spec_md import gen_spec_md +from gen_types_md import gen_types_md + +SIGNED_DOCS_SPECS = "../signed_doc.json" +SIGNED_DOCS_PAGES_DIR = "../../docs/src/architecture/08_concepts/catalyst_docs" + + +def get_signed_doc_data(spec_file: str) -> dict: + """ + Load the Signed Document Data from its json file. + """ + with open(spec_file, "r") as f: + return json.load(f) + + +def remove_tabs(text: str, tabstop: int = 4) -> str: + """ + Replace tabs in the input text with spaces so that the text aligns on tab stops. + + Args: + text (str): The input text containing tabs. + tabstop (int): The number of characters per tab stop. Default is 8. + + Returns: + str: Text with tabs replaced by spaces, aligned at each tab stop. + """ + # Create a regex pattern to match any tab character + pattern = "\t" + + def replace_tab(match): + # Calculate the number of spaces needed to reach the next tab stop + position = match.start() + return " " * (tabstop - (position % tabstop)) + + # Substitute tabs with spaces, using a custom replacement function + no_tabs_text = re.sub(pattern, replace_tab, text) + + return no_tabs_text + + +def strip_end_whitespace(s: str) -> str: + """ + Strip all whitespace from the end of any lines. + """ + lines = s.splitlines() + stripped_lines = [line.rstrip() for line in lines] + return "\n".join(stripped_lines).strip() + "\n" + + +def add_doc_ref_links(file_data: str, doc_data: dict, depth: int = 0) -> str: + """ + Add Individual Document Reference cross reference links to the document. + All Document References in text must be as `` or they will not be linked. + """ + lines = file_data.splitlines() + file_data = "" + for line in lines: + if not line.startswith("#"): + for field_name in doc_data["docs"]: + fieldNameRegex = f"(^|\\s)`{field_name}`(\\.|\\s|$)" + replacement = f"\\1{doc_ref_link(field_name, depth)}\\2" + line = re.sub( + fieldNameRegex, + replacement, + line, + flags=re.IGNORECASE | re.MULTILINE, + ) + file_data += f"{line}\n" + + return file_data + + +def add_metadata_links(file_data: str, doc_data: dict, depth: int = 0) -> str: + """ + Add metadata field documentation cross reference links to the document. + All metadata fields in text must be as `` or they will not be linked. + """ + lines = file_data.splitlines() + file_data = "" + for line in lines: + if not line.startswith("#"): + for field_name in doc_data["metadata"]: + fieldNameRegex = f"(^|\\s)`{field_name}`(\\.|\\s|$)" + replacement = f"\\1{metadata_field_link(field_name, depth)}\\2" + line = re.sub( + fieldNameRegex, + replacement, + line, + flags=re.IGNORECASE | re.MULTILINE, + ) + file_data += f"{line}\n" + + return file_data + + +def code_block_aware_re_subn( + linkNameRegex, replacement, file_data: str +) -> tuple[str, int]: + """ + Do a multiline regex replacement, but ignore anything inside a code block. + """ + lines = file_data.splitlines() + new_file_data = "" + cnt = 0 + in_code_block = False + for line in lines: + if line.strip().startswith("```"): + in_code_block = not in_code_block + + if in_code_block: + this_cnt = 0 + else: + (line, this_cnt) = re.subn( + linkNameRegex, + replacement, + line, + flags=re.IGNORECASE, + ) + cnt += this_cnt + new_file_data += line + "\n" + + return (new_file_data, cnt) + + +def add_reference_links(file_data, doc_data) -> str: + """ + Add Markdown reference links to the document. + Only Reference links found to be used by the document will be added. + """ + links = doc_data["documentationLinks"] + linkAka = doc_data["linkAKA"] + + file_data = strip_end_whitespace(file_data) + + allLinkNames = sorted( + list(linkAka.keys()) + list(links.keys()), key=lambda x: -len(x) + ) + + actualLinksUsed = {} + for linkName in allLinkNames: + escLinkName = re.escape(linkName) + linkNameRegex = f"(^|\\s)({escLinkName})(\\.|\\s|$)" + if linkName in linkAka: + replacement = f"\\1[\\2][{linkAka[linkName]}]\\3" + (file_data, cnt) = code_block_aware_re_subn( + linkNameRegex, + replacement, + file_data, + ) + if cnt > 0: + actualLinksUsed[linkAka[linkName]] = links[linkAka[linkName]] + else: + replacement = r"\1[\2]\3" + (file_data, cnt) = code_block_aware_re_subn( + linkNameRegex, + replacement, + file_data, + ) + if cnt > 0: + actualLinksUsed[linkName] = links[linkName] + + for link in actualLinksUsed: + file_data += f"\n[{link}]: {actualLinksUsed[link]}" + + return file_data + + +def save_or_validate( + file_name: str, + gen_func: callable, + args: argparse.Namespace, + doc_data: dict, + depth=0, +) -> bool: + """Save a file or Validate it, depending on whats required.""" + # Generate the document. + file_data = gen_func(doc_data) + # Remove any tabs from the file data. + file_data = remove_tabs(file_data) + # Add any links we find in the document. + if file_name.endswith(".md"): + file_data = add_reference_links(file_data, doc_data) + file_data = add_metadata_links(file_data, doc_data, depth) + file_data = add_doc_ref_links(file_data, doc_data, depth) + + # Remove any leading or trailing newlines and add a single newline at the end/ + # Helps make clean markdown files. + file_data = strip_end_whitespace(file_data) + md_file = Path(args.output).joinpath(file_name) + if args.generate: + print(f"Generating {file_name}") + if md_file.exists(): + old_contents = md_file.read_text() + if old_contents == file_data: + print(f"{file_name} is already up-to-date.") + return True + md_file.write_text(file_data) + else: + print(f"Validating {file_name}") + if not md_file.exists(): + print(f"Documentation file missing: {file_name}.") + return False + + current_file = md_file.read_text() + if current_file != file_data: + print(f"Documentation not generated correctly: {file_name}.") + return False + return True + + +def create_individual_doc_files(docs: dict, args: argparse.Namespace) -> bool: + """ + Create Individual markdown files for all document types. + """ + all_docs = docs["docs"] + + good = True + + for doc_name in all_docs: + file_name = "docs/" + doc_name.lower().replace(" ", "_") + ".md" + good &= save_or_validate( + file_name, + lambda docs: gen_docs_page_md(doc_name, docs), + args, + docs, + depth=1, + ) + + return good + + +def check_is_dir(base_path: Path) -> bool: + """ + Check if the path exists, and is a directory. + Otherwise try and make it. + Fails if it exists and is NOT a directory. + """ + # Check the base path exists and is a directory. + if not base_path.exists(): + base_path.mkdir(parents=True) + else: + if not base_path.is_dir(): + print("Base path is not a Directory") + return False + return True + + +def init_parser() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="Markdown Documentation Generator for the Signed Documentation Specifications" + ) + parser.add_argument("spec", help="Path to JSON Specification file") + parser.add_argument( + "-o", + "--output", + help="Where the docs are generated/located (directory)", + required=True, + ) + parser.add_argument( + "-g", + "--generate", + action="store_true", + help="Set to cause docs to be generated, otherwise they are validated", + ) + + args = parser.parse_args() + + # Check the base path exists and is a directory. + if not check_is_dir(Path(args.output)): + exit(1) + if not check_is_dir(Path(args.output, "docs")): + exit(1) + + return args + + +if __name__ == "__main__": + # Initialize parser + args = init_parser() + + # Get the compiled documentation json file + docs = get_signed_doc_data(args.spec) + + # We start out hoping everything is OK. + good = True + + # Generate each of the files. + good &= save_or_validate(".pages", gen_spec_index, args, docs) + good &= save_or_validate("spec.md", gen_spec_md, args, docs) + good &= save_or_validate("types.md", gen_types_md, args, docs) + good &= save_or_validate("metadata.md", gen_metadata_md, args, docs) + good &= create_individual_doc_files(docs, args) + good &= save_or_validate( + "doc_relationships.d2", gen_docs_relationship_diagram, args, docs + ) + + if not good: + print("File Comparisons Failed, Documentation is not current.") + exit(1) + + if args.generate: + print("Documentation Generated Successfully.") + else: + print("Documentation Validated Successfully.") diff --git a/specs/generic/optional.cue b/specs/generic/optional.cue new file mode 100644 index 0000000000..a6c84e4c89 --- /dev/null +++ b/specs/generic/optional.cue @@ -0,0 +1,7 @@ +package optional + +// Is a field Required, Optional or Excluded/Unused +#field: + "yes" | + "optional" | + *"excluded" diff --git a/specs/generic/uuid.cue b/specs/generic/uuid.cue new file mode 100644 index 0000000000..ac2bfa8a20 --- /dev/null +++ b/specs/generic/uuid.cue @@ -0,0 +1,8 @@ +// UUID Definitions +package uuid + +// A UUIDv4 formatted string regex +#v4: =~"^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$" + +// A uuidv7 formatted string regex +#v7: =~"^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{7}-4[0-9A-Fa-f]{3}-[89ABab][0-9A-Fa-f]{3}-[0-9A-Fa-f]{12}$" diff --git a/specs/signed_doc.json b/specs/signed_doc.json new file mode 100644 index 0000000000..66003aab8f --- /dev/null +++ b/specs/signed_doc.json @@ -0,0 +1,2143 @@ +{ + "authors": { + "Alex Pozhylenkov": "alex.pozhylenkov@iohk.io", + "Steven Johnson": "steven.johnson@iohk.io" + }, + "base_types": { + "Action": "5e60e623-ad02-4a1b-a1ac-406db978ee48", + "Brand": "ebcabeeb-5bc5-4f95-91e8-cab8ca724172", + "Campaign": "5ef32d5d-f240-462c-a7a4-ba4af221fa23", + "Category": "818938c3-3139-4daa-afe6-974c78488e95", + "Comment": "b679ded3-0e7c-41ba-89f8-da62a17898ea", + "Election": "788ff4c6-d65a-451f-bb33-575fe056b411", + "ModerationAction": "a5d232b8-5e03-4117-9afd-be32b878fcdd", + "Proposal": "7808d2ba-d511-40af-84e8-c0d1625fdfdc", + "SubmissionAction": "78927329-cfd9-4ea1-9c71-0e019b126a65", + "Template": "0ce8ab38-9258-4fbc-a62e-7faa6e58318f" + }, + "cddlDefinitions": { + "blake2b_256": { + "def": "bytes .size 32", + "requires": [] + }, + "catalyst_id": { + "def": "text", + "requires": [] + }, + "collaborators": { + "def": "[ * catalyst_id ]", + "requires": [ + "catalyst_id" + ] + }, + "document_hash": { + "def": "blake2b_256", + "requires": [ + "blake2b_256" + ] + }, + "document_id": { + "def": "uuid_v7", + "requires": [ + "uuid_v7" + ] + }, + "document_ref": { + "def": "[ 1* [ document_id, document_ver, document_hash ] ]", + "requires": [ + "document_id", + "document_ver", + "document_hash" + ] + }, + "document_type": { + "def": "[ 1* uuid_v4 ]", + "requires": [ + "uuid_v4" + ] + }, + "document_ver": { + "def": "uuid_v7", + "requires": [ + "uuid_v7" + ] + }, + "json_pointer": { + "def": "text", + "requires": [] + }, + "section_ref": { + "def": "json_pointer", + "requires": [ + "json_pointer" + ] + }, + "uuid_v4": { + "def": "6.37(bytes .size 16)", + "requires": [] + }, + "uuid_v7": { + "def": "6.37(bytes .size 16)", + "requires": [] + } + }, + "contentTypes": { + "application/cbor": { + "description": "RFC8949 Binary CBOR Encoded Document" + }, + "application/cddl": { + "description": "CDDL Document; Note: \n* This is an unofficial media type\n* RFC9165 Additional Control Operators for CDDL are supported. \n* Must not have Modules, schema must be self-contained." + }, + "application/json": { + "description": "JSON Document" + }, + "application/schema+json": { + "description": "JSON Schema Draft 7 Document; Note: \n* This is currently an unofficial media type.\n* Draft 7 is used because of its wide support by tooling." + } + }, + "copyright": { + "copyright": "IOG Singapore, All Rights Reserved", + "created": "2024-12-27", + "license": "CC-BY-4.0" + }, + "cose_headers": { + "content type": { + "coseLabel": 3, + "description": "IANA Media Type/s allowed in the Payload", + "format": "IANA Media Type", + "required": "yes", + "value": [ + "application/json", + "application/schema+json", + "application/cbor", + "application/cddl" + ] + }, + "content-encoding": { + "coseLabel": "content-encoding", + "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.", + "format": "HTTP Content Encoding", + "required": "optional", + "value": [ + "br" + ] + } + }, + "cose_headers_order": [ + "content type", + "content-encoding" + ], + "docs": { + "Brand Parameters": { + "authors": {}, + "headers": { + "content type": { + "coseLabel": 3, + "description": "IANA Media Type/s allowed in the Payload", + "format": "IANA Media Type", + "required": "yes", + "value": "application/json" + }, + "content-encoding": { + "coseLabel": "content-encoding", + "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.", + "format": "HTTP Content Encoding", + "required": "optional", + "value": [ + "br" + ] + } + }, + "metadata": { + "brand_id": { + "description": "A reference to the Brand Parameters Document this document lies under.", + "exclusive": [ + "campaign_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `brand_id` must match the `brand_id` \nof the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "campaign_id": { + "description": "A reference to the Campaign Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `campaign_id` must match the \n`campaign_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "category_id": { + "description": "A reference to the Category Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "campaign_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `category_id` must match the \n`category_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "collaborators": { + "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.", + "exclusive": null, + "format": "Collaborators Reference List", + "required": "excluded", + "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author." + }, + "election_id": { + "description": "A reference to the Election Parameters Document this document lies under.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `election_id` must match the \n`election_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "id": { + "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist." + }, + "ref": { + "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nThis is an Array of the format:\n\t`[[DocumentID, DocumentVer, DocumentHash],...]`\n\n* `DocumentID` is the UUIDv7 ID of the Document being referenced.\n* `DocumentVer` is the UUIDv7 Version of the Document being referenced.\n* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload.\n It ensures that the intended referenced document is the one used, and there has been no substitution.\n Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document.\nThe calculated Hash of the Referenced Document **MUST** match the Hash in the reference. " + }, + "reply": { + "description": "Reference to a Comment document type being referred to.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe `ref` of the `reply` document must be the same as\nthe original comment document." + }, + "section": { + "description": "A Reference to the original document, or the comment being replied to.", + "exclusive": null, + "format": "Section Reference", + "required": "excluded", + "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to." + }, + "template": { + "description": "Reference to the template used to create and/or validate this document.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe document payload is not valid if it does not validate completely against the referenced template." + }, + "type": { + "description": "The document TYPE.", + "exclusive": null, + "format": "Document Type", + "required": "yes", + "validation": "**MUST** be a known document type." + }, + "ver": { + "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "signers": { + "roles": { + "user": [ + "Registered" + ] + }, + "update": { + "author": true + } + }, + "type": [ + "ebcabeeb-5bc5-4f95-91e8-cab8ca724172" + ] + }, + "Campaign Parameters": { + "authors": {}, + "headers": { + "content type": { + "coseLabel": 3, + "description": "IANA Media Type/s allowed in the Payload", + "format": "IANA Media Type", + "required": "yes", + "value": "application/json" + }, + "content-encoding": { + "coseLabel": "content-encoding", + "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.", + "format": "HTTP Content Encoding", + "required": "optional", + "value": [ + "br" + ] + } + }, + "metadata": { + "brand_id": { + "description": "A reference to the Brand Parameters Document this document lies under.", + "exclusive": [ + "campaign_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `brand_id` must match the `brand_id` \nof the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "campaign_id": { + "description": "A reference to the Campaign Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `campaign_id` must match the \n`campaign_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "category_id": { + "description": "A reference to the Category Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "campaign_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `category_id` must match the \n`category_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "collaborators": { + "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.", + "exclusive": null, + "format": "Collaborators Reference List", + "required": "excluded", + "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author." + }, + "election_id": { + "description": "A reference to the Election Parameters Document this document lies under.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `election_id` must match the \n`election_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "id": { + "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist." + }, + "ref": { + "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nThis is an Array of the format:\n\t`[[DocumentID, DocumentVer, DocumentHash],...]`\n\n* `DocumentID` is the UUIDv7 ID of the Document being referenced.\n* `DocumentVer` is the UUIDv7 Version of the Document being referenced.\n* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload.\n It ensures that the intended referenced document is the one used, and there has been no substitution.\n Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document.\nThe calculated Hash of the Referenced Document **MUST** match the Hash in the reference. " + }, + "reply": { + "description": "Reference to a Comment document type being referred to.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe `ref` of the `reply` document must be the same as\nthe original comment document." + }, + "section": { + "description": "A Reference to the original document, or the comment being replied to.", + "exclusive": null, + "format": "Section Reference", + "required": "excluded", + "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to." + }, + "template": { + "description": "Reference to the template used to create and/or validate this document.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe document payload is not valid if it does not validate completely against the referenced template." + }, + "type": { + "description": "The document TYPE.", + "exclusive": null, + "format": "Document Type", + "required": "yes", + "validation": "**MUST** be a known document type." + }, + "ver": { + "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "signers": { + "roles": { + "user": [ + "Registered" + ] + }, + "update": { + "author": true + } + }, + "type": [ + "5ef32d5d-f240-462c-a7a4-ba4af221fa23" + ] + }, + "Category Parameters": { + "authors": {}, + "headers": { + "content type": { + "coseLabel": 3, + "description": "IANA Media Type/s allowed in the Payload", + "format": "IANA Media Type", + "required": "yes", + "value": "application/json" + }, + "content-encoding": { + "coseLabel": "content-encoding", + "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.", + "format": "HTTP Content Encoding", + "required": "optional", + "value": [ + "br" + ] + } + }, + "metadata": { + "brand_id": { + "description": "A reference to the Brand Parameters Document this document lies under.", + "exclusive": [ + "campaign_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `brand_id` must match the `brand_id` \nof the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "campaign_id": { + "description": "A reference to the Campaign Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `campaign_id` must match the \n`campaign_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "category_id": { + "description": "A reference to the Category Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "campaign_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `category_id` must match the \n`category_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "collaborators": { + "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.", + "exclusive": null, + "format": "Collaborators Reference List", + "required": "excluded", + "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author." + }, + "election_id": { + "description": "A reference to the Election Parameters Document this document lies under.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `election_id` must match the \n`election_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "id": { + "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist." + }, + "ref": { + "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nThis is an Array of the format:\n\t`[[DocumentID, DocumentVer, DocumentHash],...]`\n\n* `DocumentID` is the UUIDv7 ID of the Document being referenced.\n* `DocumentVer` is the UUIDv7 Version of the Document being referenced.\n* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload.\n It ensures that the intended referenced document is the one used, and there has been no substitution.\n Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document.\nThe calculated Hash of the Referenced Document **MUST** match the Hash in the reference. " + }, + "reply": { + "description": "Reference to a Comment document type being referred to.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe `ref` of the `reply` document must be the same as\nthe original comment document." + }, + "section": { + "description": "A Reference to the original document, or the comment being replied to.", + "exclusive": null, + "format": "Section Reference", + "required": "excluded", + "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to." + }, + "template": { + "description": "Reference to the template used to create and/or validate this document.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe document payload is not valid if it does not validate completely against the referenced template." + }, + "type": { + "description": "The document TYPE.", + "exclusive": null, + "format": "Document Type", + "required": "yes", + "validation": "**MUST** be a known document type." + }, + "ver": { + "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "signers": { + "roles": { + "user": [ + "Registered" + ] + }, + "update": { + "author": true + } + }, + "type": [ + "818938c3-3139-4daa-afe6-974c78488e95" + ] + }, + "Comment Action Document": { + "authors": {}, + "headers": { + "content type": { + "coseLabel": 3, + "description": "IANA Media Type/s allowed in the Payload", + "format": "IANA Media Type", + "required": "yes", + "value": "application/json" + }, + "content-encoding": { + "coseLabel": "content-encoding", + "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.", + "format": "HTTP Content Encoding", + "required": "optional", + "value": [ + "br" + ] + } + }, + "metadata": { + "brand_id": { + "description": "A reference to the Brand Parameters Document this document lies under.", + "exclusive": [ + "campaign_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `brand_id` must match the `brand_id` \nof the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "campaign_id": { + "description": "A reference to the Campaign Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `campaign_id` must match the \n`campaign_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "category_id": { + "description": "A reference to the Category Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "campaign_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `category_id` must match the \n`category_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "collaborators": { + "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.", + "exclusive": null, + "format": "Collaborators Reference List", + "required": "excluded", + "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author." + }, + "election_id": { + "description": "A reference to the Election Parameters Document this document lies under.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `election_id` must match the \n`election_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "id": { + "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist." + }, + "ref": { + "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nThis is an Array of the format:\n\t`[[DocumentID, DocumentVer, DocumentHash],...]`\n\n* `DocumentID` is the UUIDv7 ID of the Document being referenced.\n* `DocumentVer` is the UUIDv7 Version of the Document being referenced.\n* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload.\n It ensures that the intended referenced document is the one used, and there has been no substitution.\n Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document.\nThe calculated Hash of the Referenced Document **MUST** match the Hash in the reference. " + }, + "reply": { + "description": "Reference to a Comment document type being referred to.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe `ref` of the `reply` document must be the same as\nthe original comment document." + }, + "section": { + "description": "A Reference to the original document, or the comment being replied to.", + "exclusive": null, + "format": "Section Reference", + "required": "excluded", + "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to." + }, + "template": { + "description": "Reference to the template used to create and/or validate this document.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe document payload is not valid if it does not validate completely against the referenced template." + }, + "type": { + "description": "The document TYPE.", + "exclusive": null, + "format": "Document Type", + "required": "yes", + "validation": "**MUST** be a known document type." + }, + "ver": { + "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "signers": { + "roles": { + "user": [ + "Registered" + ] + }, + "update": { + "author": true + } + }, + "type": [ + "5e60e623-ad02-4a1b-a1ac-406db978ee48", + "b679ded3-0e7c-41ba-89f8-da62a17898ea", + "a5d232b8-5e03-4117-9afd-be32b878fcdd" + ] + }, + "Election Parameters": { + "authors": {}, + "headers": { + "content type": { + "coseLabel": 3, + "description": "IANA Media Type/s allowed in the Payload", + "format": "IANA Media Type", + "required": "yes", + "value": "application/json" + }, + "content-encoding": { + "coseLabel": "content-encoding", + "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.", + "format": "HTTP Content Encoding", + "required": "optional", + "value": [ + "br" + ] + } + }, + "metadata": { + "brand_id": { + "description": "A reference to the Brand Parameters Document this document lies under.", + "exclusive": [ + "campaign_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `brand_id` must match the `brand_id` \nof the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "campaign_id": { + "description": "A reference to the Campaign Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `campaign_id` must match the \n`campaign_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "category_id": { + "description": "A reference to the Category Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "campaign_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `category_id` must match the \n`category_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "collaborators": { + "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.", + "exclusive": null, + "format": "Collaborators Reference List", + "required": "excluded", + "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author." + }, + "election_id": { + "description": "A reference to the Election Parameters Document this document lies under.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `election_id` must match the \n`election_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "id": { + "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist." + }, + "ref": { + "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nThis is an Array of the format:\n\t`[[DocumentID, DocumentVer, DocumentHash],...]`\n\n* `DocumentID` is the UUIDv7 ID of the Document being referenced.\n* `DocumentVer` is the UUIDv7 Version of the Document being referenced.\n* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload.\n It ensures that the intended referenced document is the one used, and there has been no substitution.\n Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document.\nThe calculated Hash of the Referenced Document **MUST** match the Hash in the reference. " + }, + "reply": { + "description": "Reference to a Comment document type being referred to.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe `ref` of the `reply` document must be the same as\nthe original comment document." + }, + "section": { + "description": "A Reference to the original document, or the comment being replied to.", + "exclusive": null, + "format": "Section Reference", + "required": "excluded", + "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to." + }, + "template": { + "description": "Reference to the template used to create and/or validate this document.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe document payload is not valid if it does not validate completely against the referenced template." + }, + "type": { + "description": "The document TYPE.", + "exclusive": null, + "format": "Document Type", + "required": "yes", + "validation": "**MUST** be a known document type." + }, + "ver": { + "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "signers": { + "roles": { + "user": [ + "Registered" + ] + }, + "update": { + "author": true + } + }, + "type": [ + "788ff4c6-d65a-451f-bb33-575fe056b411" + ] + }, + "Proposal": { + "authors": { + "Steven Johnson": "steven.johnson@iohk.io" + }, + "description": "A Proposal is a document which describes a proposed solution or project to\naddress the criteria of a category within a campaign.\n\nThe proposal itself is a draft document, it is not submitted for consideration\nunless a `Proposal Submission Action` is submitted which references it.\n\nProposals themselves are intentionally general, however they may be\nlinked to a brand/campaign or category via the template used by the proposal.\n\nThe payload of a proposal is controlled by its template.", + "headers": { + "content type": { + "coseLabel": 3, + "description": "IANA Media Type/s allowed in the Payload", + "format": "IANA Media Type", + "required": "yes", + "value": "application/json" + }, + "content-encoding": { + "coseLabel": "content-encoding", + "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.", + "format": "HTTP Content Encoding", + "required": "optional", + "value": [ + "br" + ] + } + }, + "metadata": { + "brand_id": { + "description": "A reference to the Brand Parameters Document this document lies under.", + "exclusive": [ + "campaign_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `brand_id` must match the `brand_id` \nof the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "campaign_id": { + "description": "A reference to the Campaign Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `campaign_id` must match the \n`campaign_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "category_id": { + "description": "A reference to the Category Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "campaign_id" + ], + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": "Category Parameters", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `category_id` must match the \n`category_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "collaborators": { + "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.", + "exclusive": null, + "format": "Collaborators Reference List", + "required": "optional", + "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author." + }, + "election_id": { + "description": "A reference to the Election Parameters Document this document lies under.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `election_id` must match the \n`election_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "id": { + "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist." + }, + "ref": { + "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nThis is an Array of the format:\n\t`[[DocumentID, DocumentVer, DocumentHash],...]`\n\n* `DocumentID` is the UUIDv7 ID of the Document being referenced.\n* `DocumentVer` is the UUIDv7 Version of the Document being referenced.\n* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload.\n It ensures that the intended referenced document is the one used, and there has been no substitution.\n Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document.\nThe calculated Hash of the Referenced Document **MUST** match the Hash in the reference. " + }, + "reply": { + "description": "Reference to a Comment document type being referred to.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe `ref` of the `reply` document must be the same as\nthe original comment document." + }, + "section": { + "description": "A Reference to the original document, or the comment being replied to.", + "exclusive": null, + "format": "Section Reference", + "required": "excluded", + "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to." + }, + "template": { + "description": "Reference to the template used to create and/or validate this document.", + "exclusive": null, + "format": "Document Reference", + "multiple": false, + "required": "yes", + "type": "Proposal Template", + "validation": "In addition to the validation performed for `ref`, \nThe document payload is not valid if it does not validate completely against the referenced template." + }, + "type": { + "description": "The document TYPE.", + "exclusive": null, + "format": "Document Type", + "required": "yes", + "validation": "**MUST** be a known document type." + }, + "ver": { + "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "payload": { + "description": "Proposal Document drafted for submission to a category of a campaign.\n\nMust be valid according to the schema of the referenced Template." + }, + "signers": { + "roles": { + "user": [ + "Proposer" + ] + }, + "update": { + "author": true, + "collaborators": true + } + }, + "type": [ + "7808d2ba-d511-40af-84e8-c0d1625fdfdc" + ] + }, + "Proposal Comment": { + "authors": {}, + "description": "## Proposal Comment Document\n\nA Proposal Comment is a document which comments on a referenced Proposal document.\n\nProposal Comments themselves are intentionally general, however they may be\nlinked to a brand/campaign or category via the template used by the proposal.\n\nThe payload of a proposal comment is controlled by its template.", + "headers": { + "content type": { + "coseLabel": 3, + "description": "IANA Media Type/s allowed in the Payload", + "format": "IANA Media Type", + "required": "yes", + "value": "application/json" + }, + "content-encoding": { + "coseLabel": "content-encoding", + "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.", + "format": "HTTP Content Encoding", + "required": "optional", + "value": [ + "br" + ] + } + }, + "metadata": { + "brand_id": { + "description": "A reference to the Brand Parameters Document this document lies under.", + "exclusive": [ + "campaign_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `brand_id` must match the `brand_id` \nof the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "campaign_id": { + "description": "A reference to the Campaign Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `campaign_id` must match the \n`campaign_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "category_id": { + "description": "A reference to the Category Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "campaign_id" + ], + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": "Category Parameters", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `category_id` must match the \n`category_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "collaborators": { + "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.", + "exclusive": null, + "format": "Collaborators Reference List", + "required": "excluded", + "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author." + }, + "election_id": { + "description": "A reference to the Election Parameters Document this document lies under.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `election_id` must match the \n`election_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "id": { + "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist." + }, + "ref": { + "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nThis is an Array of the format:\n\t`[[DocumentID, DocumentVer, DocumentHash],...]`\n\n* `DocumentID` is the UUIDv7 ID of the Document being referenced.\n* `DocumentVer` is the UUIDv7 Version of the Document being referenced.\n* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload.\n It ensures that the intended referenced document is the one used, and there has been no substitution.\n Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one.", + "exclusive": null, + "format": "Document Reference", + "multiple": false, + "required": "yes", + "type": "Proposal", + "validation": "Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document.\nThe calculated Hash of the Referenced Document **MUST** match the Hash in the reference. " + }, + "reply": { + "description": "Reference to a Comment document type being referred to.", + "exclusive": null, + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": "Proposal Comment", + "validation": "In addition to the validation performed for `ref`, \nThe `ref` of the `reply` document must be the same as\nthe original comment document." + }, + "section": { + "description": "A Reference to the original document, or the comment being replied to.", + "exclusive": null, + "format": "Section Reference", + "required": "optional", + "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to." + }, + "template": { + "description": "Reference to the template used to create and/or validate this document.", + "exclusive": null, + "format": "Document Reference", + "multiple": false, + "required": "yes", + "type": "Proposal Comment Template", + "validation": "In addition to the validation performed for `ref`, \nThe document payload is not valid if it does not validate completely against the referenced template." + }, + "type": { + "description": "The document TYPE.", + "exclusive": null, + "format": "Document Type", + "required": "yes", + "validation": "**MUST** be a known document type." + }, + "ver": { + "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "payload": { + "description": "JSON Document which must validate against the referenced template." + }, + "signers": { + "roles": { + "user": [ + "Registered" + ] + }, + "update": { + "author": true + } + }, + "type": [ + "b679ded3-0e7c-41ba-89f8-da62a17898ea", + "7808d2ba-d511-40af-84e8-c0d1625fdfdc" + ] + }, + "Proposal Comment Meta Template": { + "authors": {}, + "description": "## Proposal Comment Meta Template Document\n\nA Proposal Comment Meta Template is used to enforce functional requirements\nare met in any Proposal Comment Template.\n\nThe payload of a proposal comment template is controlled by its meta template.", + "headers": { + "content type": { + "coseLabel": 3, + "description": "IANA Media Type/s allowed in the Payload", + "format": "IANA Media Type", + "required": "yes", + "value": "application/schema+json" + }, + "content-encoding": { + "coseLabel": "content-encoding", + "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.", + "format": "HTTP Content Encoding", + "required": "optional", + "value": [ + "br" + ] + } + }, + "metadata": { + "brand_id": { + "description": "A reference to the Brand Parameters Document this document lies under.", + "exclusive": [ + "campaign_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `brand_id` must match the `brand_id` \nof the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "campaign_id": { + "description": "A reference to the Campaign Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `campaign_id` must match the \n`campaign_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "category_id": { + "description": "A reference to the Category Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "campaign_id" + ], + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": "Category Parameters", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `category_id` must match the \n`category_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "collaborators": { + "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.", + "exclusive": null, + "format": "Collaborators Reference List", + "required": "excluded", + "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author." + }, + "election_id": { + "description": "A reference to the Election Parameters Document this document lies under.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `election_id` must match the \n`election_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "id": { + "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist." + }, + "ref": { + "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nThis is an Array of the format:\n\t`[[DocumentID, DocumentVer, DocumentHash],...]`\n\n* `DocumentID` is the UUIDv7 ID of the Document being referenced.\n* `DocumentVer` is the UUIDv7 Version of the Document being referenced.\n* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload.\n It ensures that the intended referenced document is the one used, and there has been no substitution.\n Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document.\nThe calculated Hash of the Referenced Document **MUST** match the Hash in the reference. " + }, + "reply": { + "description": "Reference to a Comment document type being referred to.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe `ref` of the `reply` document must be the same as\nthe original comment document." + }, + "section": { + "description": "A Reference to the original document, or the comment being replied to.", + "exclusive": null, + "format": "Section Reference", + "required": "excluded", + "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to." + }, + "template": { + "description": "Reference to the template used to create and/or validate this document.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe document payload is not valid if it does not validate completely against the referenced template." + }, + "type": { + "description": "The document TYPE.", + "exclusive": null, + "format": "Document Type", + "required": "yes", + "validation": "**MUST** be a known document type." + }, + "ver": { + "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "payload": { + "description": "JSON Schema document which ensures the minimum required functional requirements\nof the Proposal Comment Template are met.\n\nThis ensures that payloads can be reliably interpreted by business logic processes, \nwhile allowing for flexibility to capture extended information.", + "schema": "https://json-schema.org/draft-07/schema" + }, + "signers": { + "roles": { + "admin": [ + "Root Admin", + "Brand Admin" + ], + "user": [] + }, + "update": { + "author": true + } + }, + "type": [ + "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", + "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", + "b679ded3-0e7c-41ba-89f8-da62a17898ea", + "7808d2ba-d511-40af-84e8-c0d1625fdfdc" + ] + }, + "Proposal Comment Template": { + "authors": {}, + "description": "## Proposal Comment Template Document\n\nA Proposal Comment Template defines the allowed payload contents of a\nlinked proposal comment.\n\nProposal comments themselves are intentionally general, however they may be\nlinked to a brand/campaign or category via the template used by the proposal.\n\nThe payload of a proposal comment is controlled by its template.", + "headers": { + "content type": { + "coseLabel": 3, + "description": "IANA Media Type/s allowed in the Payload", + "format": "IANA Media Type", + "required": "yes", + "value": "application/schema+json" + }, + "content-encoding": { + "coseLabel": "content-encoding", + "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.", + "format": "HTTP Content Encoding", + "required": "optional", + "value": [ + "br" + ] + } + }, + "metadata": { + "brand_id": { + "description": "A reference to the Brand Parameters Document this document lies under.", + "exclusive": [ + "campaign_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `brand_id` must match the `brand_id` \nof the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "campaign_id": { + "description": "A reference to the Campaign Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `campaign_id` must match the \n`campaign_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "category_id": { + "description": "A reference to the Category Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "campaign_id" + ], + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": "Category Parameters", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `category_id` must match the \n`category_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "collaborators": { + "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.", + "exclusive": null, + "format": "Collaborators Reference List", + "required": "excluded", + "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author." + }, + "election_id": { + "description": "A reference to the Election Parameters Document this document lies under.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `election_id` must match the \n`election_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "id": { + "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist." + }, + "ref": { + "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nThis is an Array of the format:\n\t`[[DocumentID, DocumentVer, DocumentHash],...]`\n\n* `DocumentID` is the UUIDv7 ID of the Document being referenced.\n* `DocumentVer` is the UUIDv7 Version of the Document being referenced.\n* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload.\n It ensures that the intended referenced document is the one used, and there has been no substitution.\n Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document.\nThe calculated Hash of the Referenced Document **MUST** match the Hash in the reference. " + }, + "reply": { + "description": "Reference to a Comment document type being referred to.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe `ref` of the `reply` document must be the same as\nthe original comment document." + }, + "section": { + "description": "A Reference to the original document, or the comment being replied to.", + "exclusive": null, + "format": "Section Reference", + "required": "excluded", + "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to." + }, + "template": { + "description": "Reference to the template used to create and/or validate this document.", + "exclusive": null, + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": "Proposal Comment Meta Template", + "validation": "In addition to the validation performed for `ref`, \nThe document payload is not valid if it does not validate completely against the referenced template." + }, + "type": { + "description": "The document TYPE.", + "exclusive": null, + "format": "Document Type", + "required": "yes", + "validation": "**MUST** be a known document type." + }, + "ver": { + "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "payload": { + "description": "JSON Schema document which defines the content of the Proposal Comments." + }, + "signers": { + "roles": { + "admin": [ + "Brand Admin", + "Campaign Admin" + ], + "user": [] + }, + "update": { + "author": true + } + }, + "type": [ + "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", + "b679ded3-0e7c-41ba-89f8-da62a17898ea", + "7808d2ba-d511-40af-84e8-c0d1625fdfdc" + ] + }, + "Proposal Meta Template": { + "authors": {}, + "description": "## Proposal Meta Template Document\n\nA Proposal Meta Template is used to enforce functional requirements\nare met in any Proposal Template.\n\nThe payload of a proposal template is controlled by its meta template.", + "headers": { + "content type": { + "coseLabel": 3, + "description": "IANA Media Type/s allowed in the Payload", + "format": "IANA Media Type", + "required": "yes", + "value": "application/schema+json" + }, + "content-encoding": { + "coseLabel": "content-encoding", + "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.", + "format": "HTTP Content Encoding", + "required": "optional", + "value": [ + "br" + ] + } + }, + "metadata": { + "brand_id": { + "description": "A reference to the Brand Parameters Document this document lies under.", + "exclusive": [ + "campaign_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `brand_id` must match the `brand_id` \nof the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "campaign_id": { + "description": "A reference to the Campaign Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `campaign_id` must match the \n`campaign_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "category_id": { + "description": "A reference to the Category Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "campaign_id" + ], + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": "Category Parameters", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `category_id` must match the \n`category_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "collaborators": { + "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.", + "exclusive": null, + "format": "Collaborators Reference List", + "required": "excluded", + "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author." + }, + "election_id": { + "description": "A reference to the Election Parameters Document this document lies under.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `election_id` must match the \n`election_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "id": { + "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist." + }, + "ref": { + "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nThis is an Array of the format:\n\t`[[DocumentID, DocumentVer, DocumentHash],...]`\n\n* `DocumentID` is the UUIDv7 ID of the Document being referenced.\n* `DocumentVer` is the UUIDv7 Version of the Document being referenced.\n* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload.\n It ensures that the intended referenced document is the one used, and there has been no substitution.\n Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document.\nThe calculated Hash of the Referenced Document **MUST** match the Hash in the reference. " + }, + "reply": { + "description": "Reference to a Comment document type being referred to.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe `ref` of the `reply` document must be the same as\nthe original comment document." + }, + "section": { + "description": "A Reference to the original document, or the comment being replied to.", + "exclusive": null, + "format": "Section Reference", + "required": "excluded", + "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to." + }, + "template": { + "description": "Reference to the template used to create and/or validate this document.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe document payload is not valid if it does not validate completely against the referenced template." + }, + "type": { + "description": "The document TYPE.", + "exclusive": null, + "format": "Document Type", + "required": "yes", + "validation": "**MUST** be a known document type." + }, + "ver": { + "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "payload": { + "description": "JSON Schema document which ensures the minimum required functional requirements\nof the Proposal Template are met.\n\nThis ensures that payloads can be reliably interpreted by business logic processes, \nwhile allowing for flexibility to capture extended information.", + "schema": "https://json-schema.org/draft-07/schema" + }, + "signers": { + "roles": { + "admin": [ + "Root Admin", + "Brand Admin" + ], + "user": [] + }, + "update": { + "author": true + } + }, + "type": [ + "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", + "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", + "7808d2ba-d511-40af-84e8-c0d1625fdfdc" + ] + }, + "Proposal Moderation Action": { + "authors": {}, + "headers": { + "content type": { + "coseLabel": 3, + "description": "IANA Media Type/s allowed in the Payload", + "format": "IANA Media Type", + "required": "yes", + "value": "application/json" + }, + "content-encoding": { + "coseLabel": "content-encoding", + "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.", + "format": "HTTP Content Encoding", + "required": "optional", + "value": [ + "br" + ] + } + }, + "metadata": { + "brand_id": { + "description": "A reference to the Brand Parameters Document this document lies under.", + "exclusive": [ + "campaign_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `brand_id` must match the `brand_id` \nof the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "campaign_id": { + "description": "A reference to the Campaign Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `campaign_id` must match the \n`campaign_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "category_id": { + "description": "A reference to the Category Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "campaign_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `category_id` must match the \n`category_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "collaborators": { + "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.", + "exclusive": null, + "format": "Collaborators Reference List", + "required": "excluded", + "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author." + }, + "election_id": { + "description": "A reference to the Election Parameters Document this document lies under.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `election_id` must match the \n`election_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "id": { + "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist." + }, + "ref": { + "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nThis is an Array of the format:\n\t`[[DocumentID, DocumentVer, DocumentHash],...]`\n\n* `DocumentID` is the UUIDv7 ID of the Document being referenced.\n* `DocumentVer` is the UUIDv7 Version of the Document being referenced.\n* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload.\n It ensures that the intended referenced document is the one used, and there has been no substitution.\n Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document.\nThe calculated Hash of the Referenced Document **MUST** match the Hash in the reference. " + }, + "reply": { + "description": "Reference to a Comment document type being referred to.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe `ref` of the `reply` document must be the same as\nthe original comment document." + }, + "section": { + "description": "A Reference to the original document, or the comment being replied to.", + "exclusive": null, + "format": "Section Reference", + "required": "excluded", + "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to." + }, + "template": { + "description": "Reference to the template used to create and/or validate this document.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe document payload is not valid if it does not validate completely against the referenced template." + }, + "type": { + "description": "The document TYPE.", + "exclusive": null, + "format": "Document Type", + "required": "yes", + "validation": "**MUST** be a known document type." + }, + "ver": { + "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "signers": { + "roles": { + "user": [ + "Registered" + ] + }, + "update": { + "author": true + } + }, + "type": [ + "5e60e623-ad02-4a1b-a1ac-406db978ee48", + "7808d2ba-d511-40af-84e8-c0d1625fdfdc", + "a5d232b8-5e03-4117-9afd-be32b878fcdd" + ] + }, + "Proposal Submission Action": { + "authors": {}, + "description": "## Proposal Submission Action\n\nA Proposal Submission Action is a document which can attempt to either submit a \nparticular version of a proposal into a campaign, or withdraw it.\n\nThe last action on the document ts the action which takes effect at the deadline.\n\nFor multiple collaborators, multiple submission actions can be posted independently, \nbut none of them will take effect until ALL collaborators have posted equivalent actions.\n\nFor example, three collaborators Alice/Bob/Claire can each post one submission action\nfor the same document. \nUnless they all submit the same version of the proposal\nthe proposal will not be seen as submitted.\n\nThe payload is a fixed format.", + "headers": { + "content type": { + "coseLabel": 3, + "description": "IANA Media Type/s allowed in the Payload", + "format": "IANA Media Type", + "required": "yes", + "value": "application/json" + }, + "content-encoding": { + "coseLabel": "content-encoding", + "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.", + "format": "HTTP Content Encoding", + "required": "optional", + "value": [ + "br" + ] + } + }, + "metadata": { + "brand_id": { + "description": "A reference to the Brand Parameters Document this document lies under.", + "exclusive": [ + "campaign_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `brand_id` must match the `brand_id` \nof the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "campaign_id": { + "description": "A reference to the Campaign Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `campaign_id` must match the \n`campaign_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "category_id": { + "description": "A reference to the Category Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "campaign_id" + ], + "format": "Document Reference", + "multiple": false, + "required": "yes", + "type": "Category Parameters", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `category_id` must match the \n`category_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "collaborators": { + "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.", + "exclusive": null, + "format": "Collaborators Reference List", + "required": "excluded", + "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author." + }, + "election_id": { + "description": "A reference to the Election Parameters Document this document lies under.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `election_id` must match the \n`election_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "id": { + "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist." + }, + "ref": { + "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nThis is an Array of the format:\n\t`[[DocumentID, DocumentVer, DocumentHash],...]`\n\n* `DocumentID` is the UUIDv7 ID of the Document being referenced.\n* `DocumentVer` is the UUIDv7 Version of the Document being referenced.\n* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload.\n It ensures that the intended referenced document is the one used, and there has been no substitution.\n Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one.", + "exclusive": null, + "format": "Document Reference", + "multiple": true, + "required": "yes", + "type": "Proposal", + "validation": "Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document.\nThe calculated Hash of the Referenced Document **MUST** match the Hash in the reference. " + }, + "reply": { + "description": "Reference to a Comment document type being referred to.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe `ref` of the `reply` document must be the same as\nthe original comment document." + }, + "section": { + "description": "A Reference to the original document, or the comment being replied to.", + "exclusive": null, + "format": "Section Reference", + "required": "excluded", + "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to." + }, + "template": { + "description": "Reference to the template used to create and/or validate this document.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe document payload is not valid if it does not validate completely against the referenced template." + }, + "type": { + "description": "The document TYPE.", + "exclusive": null, + "format": "Document Type", + "required": "yes", + "validation": "**MUST** be a known document type." + }, + "ver": { + "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "payload": { + "description": "The kind of action is controlled by this payload.\nThe Payload is a JSON Document, and must conform to this schema.\n\nStates:\n\n* `final` : All collaborators must publish a `final` status for the proposal to be `final`.\n* `draft` : Reverses the previous `final` state for a signer. \n* `hide` : Requests the proposal be hidden (not final, but a hidden draft). \n\t\t\t`hide` is only actioned if sent by the author, for a collaborator its synonymous with `draft`.", + "schema": { + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "definitions": { + "action": { + "description": "The action being performed on the Proposal.", + "enum": [ + "final", + "draft", + "hide" + ], + "type": "string" + } + }, + "description": "Structure of the payload of a Proposal Submission Action.", + "maintainers": [ + { + "name": "Catalyst Team", + "url": "https://projectcatalyst.io/" + } + ], + "properties": { + "action": { + "$ref": "#/definitions/action" + } + }, + "required": [ + "action" + ], + "title": "Proposal Submission Action Payload Schema", + "x-changelog": { + "2025-03-01": [ + "First Version Created." + ] + } + } + }, + "signers": { + "referenced": true, + "roles": { + "user": [ + "Proposer" + ] + }, + "update": { + "author": true, + "collaborators": true + } + }, + "type": [ + "5e60e623-ad02-4a1b-a1ac-406db978ee48", + "7808d2ba-d511-40af-84e8-c0d1625fdfdc", + "78927329-cfd9-4ea1-9c71-0e019b126a65" + ] + }, + "Proposal Template": { + "authors": {}, + "description": "## Proposal Template Document\n\nA Proposal Template defines the allowed payload contents of a\nlinked proposal.\n\nProposals themselves are intentionally general, however they may be\nlinked to a brand/campaign or category via the template used by the proposal.\n\nThe payload of a proposal is controlled by its template.", + "headers": { + "content type": { + "coseLabel": 3, + "description": "IANA Media Type/s allowed in the Payload", + "format": "IANA Media Type", + "required": "yes", + "value": "application/schema+json" + }, + "content-encoding": { + "coseLabel": "content-encoding", + "description": "Supported HTTP Encodings of the Payload.\nIf no compression or encoding is used, then this field must not be present.", + "format": "HTTP Content Encoding", + "required": "optional", + "value": [ + "br" + ] + } + }, + "metadata": { + "brand_id": { + "description": "A reference to the Brand Parameters Document this document lies under.", + "exclusive": [ + "campaign_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `brand_id` must match the `brand_id` \nof the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "campaign_id": { + "description": "A reference to the Campaign Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "category_id" + ], + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `campaign_id` must match the \n`campaign_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "category_id": { + "description": "A reference to the Category Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "campaign_id" + ], + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": "Category Parameters", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `category_id` must match the \n`category_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "collaborators": { + "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.", + "exclusive": null, + "format": "Collaborators Reference List", + "required": "excluded", + "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author." + }, + "election_id": { + "description": "A reference to the Election Parameters Document this document lies under.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `election_id` must match the \n`election_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "id": { + "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist." + }, + "ref": { + "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nThis is an Array of the format:\n\t`[[DocumentID, DocumentVer, DocumentHash],...]`\n\n* `DocumentID` is the UUIDv7 ID of the Document being referenced.\n* `DocumentVer` is the UUIDv7 Version of the Document being referenced.\n* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload.\n It ensures that the intended referenced document is the one used, and there has been no substitution.\n Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document.\nThe calculated Hash of the Referenced Document **MUST** match the Hash in the reference. " + }, + "reply": { + "description": "Reference to a Comment document type being referred to.", + "exclusive": null, + "format": "Document Reference", + "required": "excluded", + "validation": "In addition to the validation performed for `ref`, \nThe `ref` of the `reply` document must be the same as\nthe original comment document." + }, + "section": { + "description": "A Reference to the original document, or the comment being replied to.", + "exclusive": null, + "format": "Section Reference", + "required": "excluded", + "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to." + }, + "template": { + "description": "Reference to the template used to create and/or validate this document.", + "exclusive": null, + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": "Proposal Meta Template", + "validation": "In addition to the validation performed for `ref`, \nThe document payload is not valid if it does not validate completely against the referenced template." + }, + "type": { + "description": "The document TYPE.", + "exclusive": null, + "format": "Document Type", + "required": "yes", + "validation": "**MUST** be a known document type." + }, + "ver": { + "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "payload": { + "description": "JSON Schema document which defines the valid contents of a proposal document." + }, + "signers": { + "roles": { + "admin": [ + "Brand Admin", + "Campaign Admin" + ], + "user": [] + }, + "update": { + "author": true + } + }, + "type": [ + "0ce8ab38-9258-4fbc-a62e-7faa6e58318f", + "7808d2ba-d511-40af-84e8-c0d1625fdfdc" + ] + } + }, + "documentationLinks": { + "CC-BY-4.0": "https://creativecommons.org/licenses/by/4.0/legalcode", + "JSON Schema": "https://json-schema.org/draft-07", + "RFC3629": "https://datatracker.ietf.org/doc/html/rfc3629", + "RFC3986": "https://datatracker.ietf.org/doc/html/rfc3986", + "RFC7932": "https://www.rfc-editor.org/rfc/rfc7932", + "RFC8259": "https://www.rfc-editor.org/rfc/rfc8259.html", + "RFC8610": "https://www.rfc-editor.org/rfc/rfc8610", + "RFC8949": "https://www.rfc-editor.org/rfc/rfc8949.html", + "RFC9052": "https://datatracker.ietf.org/doc/html/rfc9052", + "RFC9052-CoseSign": "https://datatracker.ietf.org/doc/html/rfc9052#name-signing-with-one-or-more-si", + "RFC9052-HeaderParameters": "https://www.rfc-editor.org/rfc/rfc8152#section-3.1", + "RFC9165": "https://www.rfc-editor.org/rfc/rfc9165", + "RFC9562": "https://www.rfc-editor.org/rfc/rfc9562.html", + "RFC9562-V4": "https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-4", + "RFC9562-V7": "https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7", + "application/cbor": "https://www.iana.org/assignments/media-types/application/cbor", + "application/json": "https://www.iana.org/assignments/media-types/application/json", + "application/schema+json": "https://datatracker.ietf.org/doc/draft-bhutton-json-schema/", + "br": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding#br" + }, + "encodingTypes": { + "br": { + "description": "BROTLI Compression" + } + }, + "linkAKA": { + "BROTLI": "RFC7932", + "CBOR": "RFC8949", + "CDDL": "RFC8610", + "COSE": "RFC9052", + "COSE Header Parameters": "RFC9052-HeaderParameters", + "COSE Sign": "RFC9052-CoseSign", + "JSON": "RFC8259", + "RFC9165 - CDDL Additional Controls": "RFC9165", + "URI": "RFC3986", + "UTF-8": "RFC3629", + "UUID": "RFC9562", + "UUIDv4": "RFC9562-V4", + "UUIDv7": "RFC9562-V7" + }, + "metadata": { + "brand_id": { + "description": "A reference to the Brand Parameters Document this document lies under.", + "exclusive": [ + "campaign_id", + "category_id" + ], + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": "Brand Parameters", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `brand_id` must match the `brand_id` \nof the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "campaign_id": { + "description": "A reference to the Campaign Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "category_id" + ], + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": "Campaign Parameters", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `campaign_id` must match the \n`campaign_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "category_id": { + "description": "A reference to the Category Parameters Document this document lies under.", + "exclusive": [ + "brand_id", + "campaign_id" + ], + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": "Category Parameters", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `category_id` must match the \n`category_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "collaborators": { + "description": "A list of collaborators who may also publish updates to versions of this document.\nThis should include all parties who have not signed this document directly.\n\nEvery subsequent version can amend the collaborators list.\nHowever, the initial Author can never be removed from being able to\npublish a new version of the document.", + "exclusive": null, + "format": "Collaborators Reference List", + "required": "optional", + "validation": "This list does not imply these collaborators have consented to collaborate, only that the author/s\nare permitting these potential collaborators to participate in the drafting and submission process.\nHowever, any document submission referencing a proposal MUST be signed by all collaborators in\naddition to the author." + }, + "election_id": { + "description": "A reference to the Election Parameters Document this document lies under.", + "exclusive": null, + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": "Election Parameters", + "validation": "In addition to the validation performed for `ref`, \nAny referenced document that includes a `election_id` must match the \n`election_id` of the referencing document.\nIt is also valid for the referenced document to not include this field, if it is \noptional for the referenced document." + }, + "id": { + "description": "Document ID, created the first time the document is created.\nThis must be a properly created UUIDv7 which contains the \ntimestamp of when the document was created.", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "IF `ver` does not == `id` then a document with \n`id` and `ver` being equal *MUST* exist." + }, + "ref": { + "description": "Reference to a Linked Document or Documents. \nThis is the primary hierarchical reference to a related document.\t\t\t\n\nThis is an Array of the format:\n\t`[[DocumentID, DocumentVer, DocumentHash],...]`\n\n* `DocumentID` is the UUIDv7 ID of the Document being referenced.\n* `DocumentVer` is the UUIDv7 Version of the Document being referenced.\n* `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload.\n It ensures that the intended referenced document is the one used, and there has been no substitution.\n Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one.", + "exclusive": null, + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": [ + "Proposal Meta Template", + "Proposal Template", + "Proposal", + "Proposal Comment Meta Template", + "Proposal Comment Template", + "Proposal Comment", + "Proposal Submission Action", + "Proposal Moderation Action", + "Comment Action Document", + "Brand Parameters", + "Campaign Parameters", + "Category Parameters", + "Election Parameters" + ], + "validation": "Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document.\nThe calculated Hash of the Referenced Document **MUST** match the Hash in the reference. " + }, + "reply": { + "description": "Reference to a Comment document type being referred to.", + "exclusive": null, + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": [ + "Proposal Comment" + ], + "validation": "In addition to the validation performed for `ref`, \nThe `ref` of the `reply` document must be the same as\nthe original comment document." + }, + "section": { + "description": "A Reference to the original document, or the comment being replied to.", + "exclusive": null, + "format": "Section Reference", + "required": "optional", + "validation": "For a non-reply this must be a valid section reference into the referenced document.\nFor a reply, this must be a valid section reference into the comment being replied to." + }, + "template": { + "description": "Reference to the template used to create and/or validate this document.", + "exclusive": null, + "format": "Document Reference", + "multiple": false, + "required": "optional", + "type": [ + "Proposal Meta Template", + "Proposal Template", + "Proposal Comment Meta Template", + "Proposal Comment Template" + ], + "validation": "In addition to the validation performed for `ref`, \nThe document payload is not valid if it does not validate completely against the referenced template." + }, + "type": { + "description": "The document TYPE.", + "exclusive": null, + "format": "Document Type", + "required": "yes", + "validation": "**MUST** be a known document type." + }, + "ver": { + "description": "The unique version of the document.\nThe first version of the document must set `ver` == `id`", + "exclusive": null, + "format": "UUIDv7", + "required": "yes", + "validation": "The document version must always be >= the document ID." + } + }, + "metadataFormats": { + "Collaborators Reference List": { + "cddl": "collaborators", + "description": "A list of collaborators who can participate in drafting and submitting a document" + }, + "Document Reference": { + "cddl": "document_ref", + "description": "A document reference identifier" + }, + "Document Type": { + "cddl": "document_type", + "description": "A document type identifier" + }, + "Section Reference": { + "cddl": "section_ref", + "description": "A document section reference identifier" + }, + "UUIDv4": { + "cddl": "uuid_v4", + "description": "Version 4 formatted UUID" + }, + "UUIDv7": { + "cddl": "uuid_v7", + "description": "Version 7 formatted UUID" + } + }, + "metadata_order": [ + "type", + "id", + "ver", + "ref", + "template", + "reply", + "section", + "collaborators", + "brand_id", + "campaign_id", + "category_id", + "election_id" + ] +} diff --git a/specs/signed_docs/authors_copyright.cue b/specs/signed_docs/authors_copyright.cue new file mode 100644 index 0000000000..e202dabc8b --- /dev/null +++ b/specs/signed_docs/authors_copyright.cue @@ -0,0 +1,28 @@ +// Signed Document Definitions +// +// COSE Headers and Constraints +package signed_docs + +// List of authors, name: email +#authorList: { + [string]: string +} + +// +#authorMinConstraint: {} + +// General Authors List +authors: #authorList & { + "Steven Johnson": "steven.johnson@iohk.io" + "Alex Pozhylenkov": "alex.pozhylenkov@iohk.io" +} + +#copyrightNotice: { + created: string // YYYY-MM-DD + license: "CC-BY-4.0" + copyright: "IOG Singapore, All Rights Reserved" +} + +copyright: #copyrightNotice & { + created: "2024-12-27" +} diff --git a/specs/signed_docs/cddl_defs.cue b/specs/signed_docs/cddl_defs.cue new file mode 100644 index 0000000000..4a98360152 --- /dev/null +++ b/specs/signed_docs/cddl_defs.cue @@ -0,0 +1,64 @@ +// Signed Document Definitions +// +// CDDL Definitions +package signed_docs + +// List of cddl definitions, cddl_type_name: cddl_definition +#cddlDefinitions: { + [string]: { + def: string + requires: [...#cddlTypesConstraint] | *[] + } +} + +cddlDefinitions: #cddlDefinitions & { + "uuid_v7": { + def: "6.37(bytes .size 16)" + } + "uuid_v4": { + def: "6.37(bytes .size 16)" + } + "document_type": { + def: "[ 1* uuid_v4 ]" + requires: ["uuid_v4"] + } + "blake2b_256": { + def: "bytes .size 32" + } + "document_id": { + def: "uuid_v7" + requires: ["uuid_v7"] + } + "document_ver": { + def: "uuid_v7" + requires: ["uuid_v7"] + } + "document_hash": { + def: "blake2b_256" + requires: ["blake2b_256"] + } + "document_ref": { + def: "[ 1* [ document_id, document_ver, document_hash ] ]" + requires: ["document_id", "document_ver", "document_hash"] + } + "json_pointer": { + def: "text" + } + "section_ref": { + def: "json_pointer" + requires: ["json_pointer"] + } + "catalyst_id": { + def: "text" + } + "collaborators": { + def: "[ * catalyst_id ]" + requires: ["catalyst_id"] + } +} + +#cddlTypes: [ + for k, _ in cddlDefinitions {k}, +] + +#cddlTypesConstraint: or(#cddlTypes) diff --git a/specs/signed_docs/cose_headers.cue b/specs/signed_docs/cose_headers.cue new file mode 100644 index 0000000000..5c0f32f43f --- /dev/null +++ b/specs/signed_docs/cose_headers.cue @@ -0,0 +1,173 @@ +// Signed Document Definitions +// +// COSE Headers and Constraints +package signed_docs + +import ( + "list" + "github.com/input-output-hk/catalyst-libs/specs/generic:optional" + +) + +// Content Type name : Description +_contentTypes: { + [string]: { + description: string // description of the content type + } +} +_contentTypes: { + "application/json": { + description: "JSON Document" + } + "application/schema+json": { + description: """ + JSON Schema Draft 7 Document; Note: + * This is currently an unofficial media type. + * Draft 7 is used because of its wide support by tooling. + """ + } + "application/cbor": { + description: "RFC8949 Binary CBOR Encoded Document" + } + "application/cddl": { + description: """ + CDDL Document; Note: + * This is an unofficial media type + * RFC9165 Additional Control Operators for CDDL are supported. + * Must not have Modules, schema must be self-contained. + """ + } +} + +contentTypes: _contentTypes + +// Content Encoding Type name : Description +_encodingTypes: { + [string]: { + description: string // description of the content type + } +} +_encodingTypes: { + "br": { + description: "BROTLI Compression" + } +} + +encodingTypes: _encodingTypes + +documentationLinks: { + "application/json": "https://www.iana.org/assignments/media-types/application/json" + "application/schema+json": "https://datatracker.ietf.org/doc/draft-bhutton-json-schema/" + "application/cbor": "https://www.iana.org/assignments/media-types/application/cbor" + "br": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Encoding#br" + "JSON Schema": "https://json-schema.org/draft-07" + "RFC7932": "https://www.rfc-editor.org/rfc/rfc7932" // Brotli + "RFC8259": "https://www.rfc-editor.org/rfc/rfc8259.html" // JSON + "RFC8610": "https://www.rfc-editor.org/rfc/rfc8610" // CDDL + "RFC8949": "https://www.rfc-editor.org/rfc/rfc8949.html" // CBOR + "RFC9052": "https://datatracker.ietf.org/doc/html/rfc9052" // COSE + "RFC9052-CoseSign": "https://datatracker.ietf.org/doc/html/rfc9052#name-signing-with-one-or-more-si" // COSE Multiple Signers + "RFC9052-HeaderParameters": "https://www.rfc-editor.org/rfc/rfc8152#section-3.1" // COSE Header Parameters + "RFC9165": "https://www.rfc-editor.org/rfc/rfc9165" // CDDL Additional Controls +} + +// Known aliases for links. Lets us automatically create [Named Link][Reference Link] +linkAKA: { + "BROTLI": "RFC7932" + "JSON": "RFC8259" + "CDDL": "RFC8610" + "CBOR": "RFC8949" + "COSE": "RFC9052" + "COSE Sign": "RFC9052-CoseSign" + "COSE Header Parameters": "RFC9052-HeaderParameters" + "RFC9165 - CDDL Additional Controls": "RFC9165" +} + +#allContentTypes: [ + for k, _ in _contentTypes {k}, +] + +#contentTypesConstraint: or(#allContentTypes) + +// Supported Content Types (list of values) +//#contentType: #allContentTypes | *"application/json" +#contentType: #contentTypesConstraint | *#allContentTypes[0] + +// Supported content encodings (list of values) +// All documents support content encoding, this defines the supported encoding types. +// Documents may also not encode data, and will omit this field. +#contentEncoding: ["br"] + +#contentEncodings: [...#contentEncoding] + +// Canonical List of COSE header names +_coseHeaderNames: list.UniqueItems +_coseHeaderNames: [ + "alg", + "crit", + "content type", + "content-encoding", // Not strictly a true Cose Header, but we include it because of its relationship to `content type` + "kid", + "IV", + "Partial IV", + "counter signature", +] + +_allCoseHeaderNames: or([ + for k in _coseHeaderNames {k}, +]) + +#coseHeaderFormat: + "COSE Algorithm" | + "IANA Media Type" | + "HTTP Content Encoding" + +#coseField: { + coseLabel: int | string + description: string + required: optional.#field | *"yes" + format: #coseHeaderFormat + if format == "IANA Media Type" { + "value": #contentType | [...#contentType] + } + + if format == "HTTP Content Encoding" { + "value": #contentEncoding + } +} + +// Metadata Fields that are required for every signed document +#coseHeaders: { + [_allCoseHeaderNames]: #coseField +} +_coseHeaders: #coseHeaders & { + // Documents content type + "content type": #coseField & { + coseLabel: 3 + format: "IANA Media Type" + description: "IANA Media Type/s allowed in the Payload" + } + // Allowed content encodings + "content-encoding": #coseField & { + coseLabel: "content-encoding" + format: "HTTP Content Encoding" + required: "optional" + description: """ + Supported HTTP Encodings of the Payload. + If no compression or encoding is used, then this field must not be present. + """ + } +} + +cose_headers: _coseHeaders +cose_headers: + "content type": + value: #allContentTypes + +// Preferred display order of cose header fields. +// if header not listed, display after the listed fields, in alphabetical order. +cose_headers_order: list.UniqueItems +cose_headers_order: [ + "content type", + "content-encoding", +] diff --git a/specs/signed_docs/docs/all.cue b/specs/signed_docs/docs/all.cue new file mode 100644 index 0000000000..9b68904981 --- /dev/null +++ b/specs/signed_docs/docs/all.cue @@ -0,0 +1,78 @@ +// Master list of all document types. +package signed_docs + +// Named Type UUIDs for easier definitions/references +_allDocTypes: { + "Template": "0ce8ab38-9258-4fbc-a62e-7faa6e58318f" + "Proposal": "7808d2ba-d511-40af-84e8-c0d1625fdfdc" + "Comment": "b679ded3-0e7c-41ba-89f8-da62a17898ea" + "Action": "5e60e623-ad02-4a1b-a1ac-406db978ee48" + "SubmissionAction": "78927329-cfd9-4ea1-9c71-0e019b126a65" + "ModerationAction": "a5d232b8-5e03-4117-9afd-be32b878fcdd" + "Brand": "ebcabeeb-5bc5-4f95-91e8-cab8ca724172" + "Campaign": "5ef32d5d-f240-462c-a7a4-ba4af221fa23" + "Category": "818938c3-3139-4daa-afe6-974c78488e95" + "Election": "788ff4c6-d65a-451f-bb33-575fe056b411" +} + +// Source of truth for ALL Document Types and their matching UUID's. +// Format is : : +_allDocs: { + "Proposal Meta Template": [ + _allDocTypes["Template"], // Template + _allDocTypes["Template"], // For Templates + _allDocTypes["Proposal"], // On Proposals + ] + "Proposal Template": [ + _allDocTypes["Template"], // Template + _allDocTypes["Proposal"], // For Proposals + ] + "Proposal": [ + _allDocTypes["Proposal"], + ] + "Proposal Comment Meta Template": [ + _allDocTypes["Template"], // Template + _allDocTypes["Template"], // For Templates + _allDocTypes["Comment"], // On Comment + _allDocTypes["Proposal"], // On Proposals + ] + "Proposal Comment Template": [ + _allDocTypes["Template"], // Template + _allDocTypes["Comment"], // For Comments + _allDocTypes["Proposal"], // On Proposals + ] + "Proposal Comment": [ + _allDocTypes["Comment"], // Comment + _allDocTypes["Proposal"], // For Proposals + ] + "Proposal Submission Action": + [ + _allDocTypes["Action"], // Action + _allDocTypes["Proposal"], // For Proposal + _allDocTypes["SubmissionAction"], // On Submission + ] + "Proposal Moderation Action": + [ + _allDocTypes["Action"], // Action + _allDocTypes["Proposal"], // For Proposal + _allDocTypes["ModerationAction"], // On Moderation + ] + "Comment Action Document": [ + _allDocTypes["Action"], // Action + _allDocTypes["Comment"], // For Comment + _allDocTypes["ModerationAction"], // On Moderation + ] + "Brand Parameters": [ + _allDocTypes["Brand"], + ] + "Campaign Parameters": [ + _allDocTypes["Campaign"], + ] + "Category Parameters": [ + _allDocTypes["Category"], + ] + "Election Parameters": [ + _allDocTypes["Election"], + ] + +} diff --git a/specs/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json b/specs/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json new file mode 100644 index 0000000000..07b369012b --- /dev/null +++ b/specs/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json @@ -0,0 +1,37 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://raw.githubusercontent.com/input-output-hk/catalyst-libs/refs/heads/main/specs/signed_docs/docs/payload_schemas/proposal_submission_action.schema.json", + "title": "Proposal Submission Action Payload Schema", + "description": "Structure of the payload of a Proposal Submission Action.", + "maintainers": [ + { + "name": "Catalyst Team", + "url": "https://projectcatalyst.io/" + } + ], + "x-changelog": { + "2025-03-01": [ + "First Version Created." + ] + }, + "additionalProperties": false, + "definitions": { + "action": { + "type": "string", + "description": "The action being performed on the Proposal.", + "enum": [ + "final", + "draft", + "hide" + ] + } + }, + "properties": { + "action": { + "$ref": "#/definitions/action" + } + }, + "required": [ + "action" + ] +} \ No newline at end of file diff --git a/specs/signed_docs/docs/proposal.cue b/specs/signed_docs/docs/proposal.cue new file mode 100644 index 0000000000..7531260e15 --- /dev/null +++ b/specs/signed_docs/docs/proposal.cue @@ -0,0 +1,60 @@ +package signed_docs + +// Proposal Document Definition + +docs: #DocumentDefinitions & { + "Proposal": { + description: """ + A Proposal is a document which describes a proposed solution or project to + address the criteria of a category within a campaign. + + The proposal itself is a draft document, it is not submitted for consideration + unless a `Proposal Submission Action` is submitted which references it. + + Proposals themselves are intentionally general, however they may be + linked to a brand/campaign or category via the template used by the proposal. + + The payload of a proposal is controlled by its template. + """ + + metadata: { + template: { + required: "yes" + type: "Proposal Template" + } + + collaborators: { + required: "optional" + } + + category_id: { + required: "optional" + type: "Category Parameters" + } + } + + payload: { + description: """ + Proposal Document drafted for submission to a category of a campaign. + + Must be valid according to the schema of the referenced Template. + """ + } + + signers: { + roles: { + user: [ + "Proposer", + ] + } + + update: { + "collaborators": true + } + } + + authors: { + "Steven Johnson": "steven.johnson@iohk.io" + } + } +} diff --git a/specs/signed_docs/docs/proposal_comment.cue b/specs/signed_docs/docs/proposal_comment.cue new file mode 100644 index 0000000000..7ab941fda7 --- /dev/null +++ b/specs/signed_docs/docs/proposal_comment.cue @@ -0,0 +1,51 @@ +package signed_docs + +// Proposal Document Definition + +docs: #DocumentDefinitions & { + "Proposal Comment": { + description: """ + ## Proposal Comment Document + + A Proposal Comment is a document which comments on a referenced Proposal document. + + Proposal Comments themselves are intentionally general, however they may be + linked to a brand/campaign or category via the template used by the proposal. + + The payload of a proposal comment is controlled by its template. + """ + + metadata: { + ref: { + required: "yes" + type: "Proposal" + } + + reply: { + required: "optional" + type: "Proposal Comment" + } + + section: { + required: "optional" + } + + template: { + required: "yes" + type: "Proposal Comment Template" + } + + category_id: { + required: "optional" + type: "Category Parameters" + } + } + + payload: { + description: """ + JSON Document which must validate against the referenced template. + """ + } + + } +} diff --git a/specs/signed_docs/docs/proposal_comment_meta_template.cue b/specs/signed_docs/docs/proposal_comment_meta_template.cue new file mode 100644 index 0000000000..fab54297f7 --- /dev/null +++ b/specs/signed_docs/docs/proposal_comment_meta_template.cue @@ -0,0 +1,54 @@ +package signed_docs + +// Proposal Document Definition + +docs: #DocumentDefinitions & { + "Proposal Comment Meta Template": { + description: """ + ## Proposal Comment Meta Template Document + + A Proposal Comment Meta Template is used to enforce functional requirements + are met in any Proposal Comment Template. + + The payload of a proposal comment template is controlled by its meta template. + """ + + headers: { + "content type": { + value: "application/schema+json" + } + } + + metadata: { + category_id: { + required: "optional" + type: "Category Parameters" + } + } + + payload: { + description: """ + JSON Schema document which ensures the minimum required functional requirements + of the Proposal Comment Template are met. + + This ensures that payloads can be reliably interpreted by business logic processes, + while allowing for flexibility to capture extended information. + """ + + schema: "https://json-schema.org/draft-07/schema" + } + + "signers": { + roles: { + // No User Role may publish this document. + user: [] + + // Root Admin and brand Admin may publish this document. + admin: [ + "Root Admin", + "Brand Admin", + ] + } + } + } +} diff --git a/specs/signed_docs/docs/proposal_comment_template.cue b/specs/signed_docs/docs/proposal_comment_template.cue new file mode 100644 index 0000000000..1015e4eabe --- /dev/null +++ b/specs/signed_docs/docs/proposal_comment_template.cue @@ -0,0 +1,56 @@ +package signed_docs + +// Proposal Document Definition + +docs: #DocumentDefinitions & { + "Proposal Comment Template": { + description: """ + ## Proposal Comment Template Document + + A Proposal Comment Template defines the allowed payload contents of a + linked proposal comment. + + Proposal comments themselves are intentionally general, however they may be + linked to a brand/campaign or category via the template used by the proposal. + + The payload of a proposal comment is controlled by its template. + """ + + headers: { + "content type": { + value: "application/schema+json" + } + } + + metadata: { + template: { + required: "optional" + type: "Proposal Comment Meta Template" + } + + category_id: { + required: "optional" + type: "Category Parameters" + } + } + + payload: { + description: """ + JSON Schema document which defines the content of the Proposal Comments. + """ + } + + signers: { + roles: { + // No User Role may publish this document. + user: [] + + // Brand Admin and Lower may publish this document. + admin: [ + "Brand Admin", + "Campaign Admin", + ] + } + } + } +} diff --git a/specs/signed_docs/docs/proposal_meta_template.cue b/specs/signed_docs/docs/proposal_meta_template.cue new file mode 100644 index 0000000000..e90ade9f5e --- /dev/null +++ b/specs/signed_docs/docs/proposal_meta_template.cue @@ -0,0 +1,55 @@ +package signed_docs + +// Proposal Document Definition + +docs: #DocumentDefinitions & { + "Proposal Meta Template": { + description: """ + ## Proposal Meta Template Document + + A Proposal Meta Template is used to enforce functional requirements + are met in any Proposal Template. + + The payload of a proposal template is controlled by its meta template. + """ + + headers: { + "content type": { + value: "application/schema+json" + } + } + + metadata: { + category_id: { + required: "optional" + type: "Category Parameters" + } + } + + payload: { + description: """ + JSON Schema document which ensures the minimum required functional requirements + of the Proposal Template are met. + + This ensures that payloads can be reliably interpreted by business logic processes, + while allowing for flexibility to capture extended information. + """ + + schema: "https://json-schema.org/draft-07/schema" + } + + "signers": { + roles: { + // No User Role may publish this document. + user: [] + + // Root Admin and brand Admin may publish this document. + admin: [ + "Root Admin", + "Brand Admin", + ] + } + } + + } +} diff --git a/specs/signed_docs/docs/proposal_submission_action.cue b/specs/signed_docs/docs/proposal_submission_action.cue new file mode 100644 index 0000000000..71354ce5ec --- /dev/null +++ b/specs/signed_docs/docs/proposal_submission_action.cue @@ -0,0 +1,71 @@ +@extern(embed) + +package signed_docs + +// Proposal Submission Action +docs: #DocumentDefinitions & { + "Proposal Submission Action": { + description: """ + ## Proposal Submission Action + + A Proposal Submission Action is a document which can attempt to either submit a + particular version of a proposal into a campaign, or withdraw it. + + The last action on the document ts the action which takes effect at the deadline. + + For multiple collaborators, multiple submission actions can be posted independently, + but none of them will take effect until ALL collaborators have posted equivalent actions. + + For example, three collaborators Alice/Bob/Claire can each post one submission action + for the same document. + Unless they all submit the same version of the proposal + the proposal will not be seen as submitted. + + The payload is a fixed format. + """ + + metadata: { + ref: { + type: "Proposal" + required: "yes" + multiple: true + } + + category_id: { + required: "yes" + type: "Category Parameters" + } + } + + payload: { + description: """ + The kind of action is controlled by this payload. + The Payload is a JSON Document, and must conform to this schema. + + States: + + * `final` : All collaborators must publish a `final` status for the proposal to be `final`. + * `draft` : Reverses the previous `final` state for a signer. + * `hide` : Requests the proposal be hidden (not final, but a hidden draft). + `hide` is only actioned if sent by the author, for a collaborator its synonymous with `draft`. + """ + schema: _ @embed(file="payload_schemas/proposal_submission_action.schema.json") + } + + "signers": { + roles: { + // Proposers may publish this document. + user: [ + "Proposer", + ] + } + + referenced: true + + update: { + collaborators: true + } + } + + } +} diff --git a/specs/signed_docs/docs/proposal_template.cue b/specs/signed_docs/docs/proposal_template.cue new file mode 100644 index 0000000000..2b854cd441 --- /dev/null +++ b/specs/signed_docs/docs/proposal_template.cue @@ -0,0 +1,57 @@ +package signed_docs + +// Proposal Document Definition + +docs: #DocumentDefinitions & { + "Proposal Template": { + description: """ + ## Proposal Template Document + + A Proposal Template defines the allowed payload contents of a + linked proposal. + + Proposals themselves are intentionally general, however they may be + linked to a brand/campaign or category via the template used by the proposal. + + The payload of a proposal is controlled by its template. + """ + + headers: { + "content type": { + value: "application/schema+json" + } + } + + metadata: { + template: { + required: "optional" + type: "Proposal Meta Template" + } + + category_id: { + required: "optional" + type: "Category Parameters" + } + } + + payload: { + description: """ + JSON Schema document which defines the valid contents of a proposal document. + """ + } + + signers: { + roles: { + // No User Role may publish this document. + user: [] + + // Brand Admin and Lower may publish this document. + admin: [ + "Brand Admin", + "Campaign Admin", + ] + } + } + + } +} diff --git a/specs/signed_docs/documentation_links.cue b/specs/signed_docs/documentation_links.cue new file mode 100644 index 0000000000..18c4469a4c --- /dev/null +++ b/specs/signed_docs/documentation_links.cue @@ -0,0 +1,50 @@ +// Links to external documentation + +package signed_docs + +import ( + "list" +) + +// A named Link to an external document, this would be encoded into markdown as: +// [name]: url +#metadataStruct: { + [_allMetadataNames]: #metadataField +} + +#namedLink: { + [string]: string +} + +// Constrains the URLs being linked to be unique +#uniqueLinkValues: list.UniqueItems +#uniqueLinkValues: [...string] & [ + for _, v in documentationLinks {v}, +] + +documentationLinks: #namedLink +documentationLinks: { + "RFC3629": "https://datatracker.ietf.org/doc/html/rfc3629" // UTF-8 + "RFC3986": "https://datatracker.ietf.org/doc/html/rfc3986" // URI + "RFC9562": "https://www.rfc-editor.org/rfc/rfc9562.html" // UUID + "RFC9562-V4": "https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-4" // UUID V4 + "RFC9562-V7": "https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7" // UUID V7 + "CC-BY-4.0": "https://creativecommons.org/licenses/by/4.0/legalcode" // CC BY 4.0 +} + +#allLinkNames: or([ + for k, _ in documentationLinks {k}, +]) + +linkAKA: { + [string]: #allLinkNames +} + +// Known aliases for links. Lets us automatically create [Named Link][Reference Link] +linkAKA: { + "UUIDv7": "RFC9562-V7" + "UUIDv4": "RFC9562-V4" + "UUID": "RFC9562" + "URI": "RFC3986" + "UTF-8": "RFC3629" +} diff --git a/specs/signed_docs/metadata.cue b/specs/signed_docs/metadata.cue new file mode 100644 index 0000000000..e37c29cfd8 --- /dev/null +++ b/specs/signed_docs/metadata.cue @@ -0,0 +1,309 @@ +// Signed Document Definitions +// +// Metadata Types and Constraints +package signed_docs + +import ( + "list" + "github.com/input-output-hk/catalyst-libs/specs/generic:optional" + +) + +// Metadata Formats. +// format_name : cddl definition +#metadataFormats: { + [string]: { + description: string + cddl: #cddlTypesConstraint + } +} + +metadataFormats: #metadataFormats & { + "Document Reference": { + description: "A document reference identifier" + cddl: "document_ref" + } + "UUIDv7": { + description: "Version 7 formatted UUID" + cddl: "uuid_v7" + } + "UUIDv4": { + description: "Version 4 formatted UUID" + cddl: "uuid_v4" + } + "Document Type": { + description: "A document type identifier" + cddl: "document_type" + } + "Section Reference": { + description: "A document section reference identifier" + cddl: "section_ref" + } + "Collaborators Reference List": { + description: "A list of collaborators who can participate in drafting and submitting a document" + cddl: "collaborators" + } +} + +// Types of a Metadata Fields +#metadataTypes: [ + for k, _ in metadataFormats {k}, +] + +// Constraint of Types of Metadata Fields +#metadataTypesConstraint: or(#metadataTypes) + +// Format of a Metadata Field +//#metadataFormat: +// "UUIDv7" | +// "Document Type" | +// *"Document Reference" | +// "Section Reference" | +// "Collaborators Reference List" + +// Canonical List of all valid metadata names +_metadataNames: list.UniqueItems +_metadataNames: [ + "type", + "id", + "ver", + "ref", + "template", + "reply", + "section", + "collaborators", + "brand_id", + "campaign_id", + "election_id", + "category_id", +] + +_allMetadataNames: or([ + for k in _metadataNames {k}, +]) +// Definition of a metadata field. +#metadataField: { + // Is the field required to be present. + required: optional.#field + + // Format of the field. + format: #metadataTypesConstraint | *#metadataTypes[0] + if format == "Document Reference" && required != "excluded" { + type: #DocumentName | [...#DocumentName] + multiple: bool | *false + } + + // Markdown description of the field. + description: string | *"" + // Optional notes about validating the field. + validation: string | *null + + // Is the field exclusive of another field (ie can not exist with that other field in the same document) + exclusive: [..._allMetadataNames] | *null +} + +// Metadata fields that are optional +#metadataStruct: { + [_allMetadataNames]: #metadataField +} +_metadata: #metadataStruct & { + // Document Type + type: { + required: "yes" + format: "Document Type" + description: "The document TYPE." + validation: """ + **MUST** be a known document type. + """ + } + // Document ID + id: { + required: "yes" + format: "UUIDv7" + description: """ + Document ID, created the first time the document is created. + This must be a properly created UUIDv7 which contains the + timestamp of when the document was created. + """ + validation: """ + IF `ver` does not == `id` then a document with + `id` and `ver` being equal *MUST* exist. + """ + } + // Document Version + ver: { + required: "yes" + format: "UUIDv7" + description: """ + The unique version of the document. + The first version of the document must set `ver` == `id` + """ + + validation: """ + The document version must always be >= the document ID. + """ + } + + ref: { + description: """ + Reference to a Linked Document or Documents. + This is the primary hierarchical reference to a related document. + + This is an Array of the format: + `[[DocumentID, DocumentVer, DocumentHash],...]` + + * `DocumentID` is the UUIDv7 ID of the Document being referenced. + * `DocumentVer` is the UUIDv7 Version of the Document being referenced. + * `DocumentHash` is the Blake2b-256 Hash of the entire document being referenced, not just its payload. + It ensures that the intended referenced document is the one used, and there has been no substitution. + Prevents substitutions where a new document with the same Document ID and Ver might be published over an existing one. + """ + validation: """ + Every Reference Document **MUST** Exist, and **MUST** be a valid reference to the document. + The calculated Hash of the Referenced Document **MUST** match the Hash in the reference. + """ + } + + template: { + description: "Reference to the template used to create and/or validate this document." + validation: """ + In addition to the validation performed for `ref`, + The document payload is not valid if it does not validate completely against the referenced template. + """ + } + + reply: { + description: """ + Reference to a Comment document type being referred to. + """ + validation: """ + In addition to the validation performed for `ref`, + The `ref` of the `reply` document must be the same as + the original comment document. + """ + } + + section: { + format: "Section Reference" + description: """ + A Reference to the original document, or the comment being replied to. + """ + validation: """ + For a non-reply this must be a valid section reference into the referenced document. + For a reply, this must be a valid section reference into the comment being replied to. + """ + } + + collaborators: { + format: "Collaborators Reference List" + description: """ + A list of collaborators who may also publish updates to versions of this document. + This should include all parties who have not signed this document directly. + + Every subsequent version can amend the collaborators list. + However, the initial Author can never be removed from being able to + publish a new version of the document. + """ + validation: """ + This list does not imply these collaborators have consented to collaborate, only that the author/s + are permitting these potential collaborators to participate in the drafting and submission process. + However, any document submission referencing a proposal MUST be signed by all collaborators in + addition to the author. + """ + } + + brand_id: { + description: "A reference to the Brand Parameters Document this document lies under." + validation: """ + In addition to the validation performed for `ref`, + Any referenced document that includes a `brand_id` must match the `brand_id` + of the referencing document. + It is also valid for the referenced document to not include this field, if it is + optional for the referenced document. + """ + exclusive: [ + "campaign_id", + "category_id", + ] + } + + campaign_id: { + description: "A reference to the Campaign Parameters Document this document lies under." + validation: """ + In addition to the validation performed for `ref`, + Any referenced document that includes a `campaign_id` must match the + `campaign_id` of the referencing document. + It is also valid for the referenced document to not include this field, if it is + optional for the referenced document. + """ + exclusive: [ + "brand_id", + "category_id", + ] + } + + election_id: { + description: "A reference to the Election Parameters Document this document lies under." + validation: """ + In addition to the validation performed for `ref`, + Any referenced document that includes a `election_id` must match the + `election_id` of the referencing document. + It is also valid for the referenced document to not include this field, if it is + optional for the referenced document. + """ + } + + category_id: { + description: "A reference to the Category Parameters Document this document lies under." + validation: """ + In addition to the validation performed for `ref`, + Any referenced document that includes a `category_id` must match the + `category_id` of the referencing document. + It is also valid for the referenced document to not include this field, if it is + optional for the referenced document. + """ + exclusive: [ + "brand_id", + "campaign_id", + ] + } +} + +// Note: we make all normally excluded fields optional at the global level, because they are globally optional +metadata: _metadata +metadata: { + ref: required: "optional" + ref: type: _allDocNamesList + template: required: "optional" + template: type: #templateDocNamesList + reply: required: "optional" + reply: type: #commentDocNamesList + section: required: "optional" + collaborators: required: "optional" + brand_id: required: "optional" + brand_id: type: "Brand Parameters" + campaign_id: required: "optional" + campaign_id: type: "Campaign Parameters" + election_id: required: "optional" + election_id: type: "Election Parameters" + category_id: required: "optional" + category_id: type: "Category Parameters" +} + +// Preferred display order +// If metadata field not listed, then list them after the explicit ones, in alphabetical order. +metadata_order: list.UniqueItems +metadata_order: [..._allMetadataNames] & [ + "type", + "id", + "ver", + "ref", + "template", + "reply", + "section", + "collaborators", + "brand_id", + "campaign_id", + "category_id", + "election_id", +] diff --git a/specs/signed_docs/payload.cue b/specs/signed_docs/payload.cue new file mode 100644 index 0000000000..f2dcbec41c --- /dev/null +++ b/specs/signed_docs/payload.cue @@ -0,0 +1,10 @@ +package signed_docs + +// Payload definition +_payload: { + // Description of the payload + description: string + // Optional fixed schema for the payload. + // A URI or inline JSON Schema that the payload must validate against. + schema?: _ +} diff --git a/specs/signed_docs/signed_doc.cue b/specs/signed_docs/signed_doc.cue new file mode 100644 index 0000000000..f6465e1eff --- /dev/null +++ b/specs/signed_docs/signed_doc.cue @@ -0,0 +1,106 @@ +// Signed Document Definitions +// +// Base Types and Constraints +package signed_docs + +import ( + "list" + "strings" + "github.com/input-output-hk/catalyst-libs/specs/generic:uuid" +) + +// Document Type must be a valid UUIDv4 +#docType: [...uuid.#v4] + +// Document ID or Version must be a valid UUIDv7 +#docIdOrVer: uuid.#v7 + +// Individual Signed Document Definition +#signedDocument: { + // The Document Type Identifier + type!: #docType + + // The description of this document. Markdown Supported. + description?: string + + // The description of this document. Markdown Supported. + validation?: string + + // The business logic related to this document. Markdown Supported. + business_logic?: { + front_end?: string + back_end?: string + } + + // Fixed headers in every document + headers: _coseHeaders + + // The Metadata fields in this document (non cose standard) + metadata: _metadata + + // Requirements for the document payload. + payload?: _payload + + // Required/Allowed Signers of a document + signers: _allowedSigners + + authors: #authorList +} + +// We can only define known documents in the document definitions object +#DocumentDefinitions: { + [_allDocNames]: #signedDocument +} + +// Default Definitions for all documents. +// Customize each document type in its own `.cue` file. +docs: #DocumentDefinitions & { + for k, v in _allDocs { + (k): { + type: v + } + } +} + +// base Document Types to help with automated processing of the document schema information. +base_types: _allDocTypes + +// Ensure that all Document Type IDs are Unique. +// See: all_docs.cue for a list of all known document types. +#allDocTypeIDs: list.UniqueItems + +#allDocTypeIDs: [...uuid.#v4] & [ + for _, v in _allDocTypes {v}, +] + +// Ensure that all Document IDs are Unique. +// See: all_docs.cue for a list of all known document types. +_allTypes: list.UniqueItems +_allTypes: [...#docType] & [ + for _, v in _allDocs {v}, +] + +_allDocNamesList: [...string] & [ + for k, _ in _allDocs {k}, +] + +// List of all Comment Docs (not templates or actions) +#commentDocNamesList: [...string] & [ + for k, _ in _allDocs + if strings.Contains(k, "Comment") && + !strings.Contains(k, "Template") && + !strings.Contains(k, "Action") {k}, +] + +// List of all Template Docs (not actions) +#templateDocNamesList: [...string] & [ + for k, _ in _allDocs + if strings.Contains(k, "Template") && + !strings.Contains(k, "Action") {k}, +] + +// List of all the document names we have defined. +_allDocNames: or(_allDocNamesList) + +// Individual Valid Document Name constraint. +#DocumentName: _allDocNames diff --git a/specs/signed_docs/signers.cue b/specs/signed_docs/signers.cue new file mode 100644 index 0000000000..fc476c30e9 --- /dev/null +++ b/specs/signed_docs/signers.cue @@ -0,0 +1,76 @@ +// Signed Document Definitions +// +// Metadata Types and Constraints +package signed_docs + +import "list" + +// TODO: Get Roles from RBAC definition configuration package instead. +// Named User Roles +_allUserRolesList: list.UniqueItems +_allUserRolesList: [ + "Registered", // Role 0 - A registered User / Voter - Base Role + "Proposer", // Registered for posting proposals + "Representative", // Registered as a rep for voting purposes. +] +_allUserRoles: or(_allUserRolesList) + +// Individual Valid User Role Constraint +#UserRoles: _allUserRoles +#allowedUserRoles: [...#UserRoles] + +// TODO: Get roles from RBAC definition configuration package instead +// Named Admin Roles +_allAdminRolesList: list.UniqueItems +_allAdminRolesList: [ + "Root CA", + "Brand CA", + "Campaign CA", + "Category CA", + "Root Admin", + "Brand Admin", + "Campaign Admin", + "Category Admin", + "Moderator", +] +_allAdminRoles: or(_allAdminRolesList) + +// Individual Valid Admin Role Constraint +#AdminRoles: _allAdminRoles +#allowedAdminRoles: [...#AdminRoles] + +// The roles which are allowed to publish this document +#allowedRoles: { + // User roles allowed to publish this document + user: #allowedUserRoles + + // Admin roles allowed to publish this document + admin?: #allowedAdminRoles +} + +#allowedUpdaters: { + collaborators?: bool | *false // Listed collaborators can post updated versions + author: bool | *true // The original author can post updated versions + any?: bool | *false // Anyone with the correct role can post updated versions +} + +#allowedSigners: { + // Who is allowed to sign a new document + // TODO: Import roles from a role definition configuration. + roles: #allowedRoles + + // Limited to the same signer as the document referenced + referenced?: bool | *false + + // Who is allowed to sign an update to an existing document. + update: #allowedUpdaters +} + +_allowedSigners: #allowedSigners & { + roles: #allowedRoles & { + user: #allowedUserRoles & _ | *[ + _allUserRolesList[0], + ] + } + update: #allowedUpdaters +} diff --git a/utilities/docs-preview/.gitignore b/utilities/docs-preview/.gitignore new file mode 100644 index 0000000000..799bc6ef79 --- /dev/null +++ b/utilities/docs-preview/.gitignore @@ -0,0 +1 @@ +local.py \ No newline at end of file diff --git a/utilities/docs-preview/Earthfile b/utilities/docs-preview/Earthfile new file mode 100644 index 0000000000..9bbe251605 --- /dev/null +++ b/utilities/docs-preview/Earthfile @@ -0,0 +1,8 @@ +VERSION 0.8 + +IMPORT github.com/input-output-hk/catalyst-ci/earthly/docs:v3.3.0 AS docs-ci + + +# update-docs-dev-script: get the latest docs dev script from CI. +update-docs-dev-script: + DO docs-ci+SYNC_LOCAL_DOCS \ No newline at end of file diff --git a/utilities/docs-preview/justfile b/utilities/docs-preview/justfile new file mode 100644 index 0000000000..fa99575bc1 --- /dev/null +++ b/utilities/docs-preview/justfile @@ -0,0 +1,20 @@ +# use with https://github.com/casey/just +# +# Catalyst Voices Documentation Local Preview Build + +# cspell: words prereqs, commitlog + +default: + @just --list --unsorted + +# Ensure we have the latest version of the dev docs script locally. +update-docs-dev-script: + earthly +update-docs-dev-script + +# Live rebuilds and deploys the documentation locally. +# +# See root Justfile for full documentation. +preview-docs: update-docs-dev-script + echo "Requires Python Installed. Version >= 3.11" + python --version + ./local.py --target "../../docs+local" --exposed-port 8280 catalyst-libs-docs:latest