diff --git a/.gitignore b/.gitignore
index 496ee2c..e05e2e7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,161 @@
-.DS_Store
\ No newline at end of file
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
+.DS_Store
diff --git a/README.md b/README.md
index 8272150..f80cf4a 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,65 @@
-# Consent Building Block
+
+ Consent Building Block (Govstack)
+
-This hosts the consent BB repos as part of GovStack. Each building block repo has a structure outlined below.
+
+
+
+
+
+
+
+
+ About •
+ Release Status •
+ Core Team •
+ Contributing •
+ Licensing
+
+
+## About
+
+Consent BB defines the principles, functions and architecture of an information system that enables services for individuals to approve the use of her/his personal data and for information system operators that process personal data of individuals to know the will of the individual and legitimately process such personal data.
+
+It is a process-oriented GovStack BB facilitating auditable bilateral agreement within a multi-agent environment, that integrates with most other BBs.
+
+This repository contains the deliverables from Consent BB team, as part of the Govstack project.
+
+## Core Team
+
+* Ain Aaviksoo ([ain.aaviksoo@guardtime.com](ain.aaviksoo@guardtime.com))
+* Benjamin Balder Bach ([balder@overtag.dk](balder@overtag.dk))
+* Philippe Page ([philippe.page@humancolossus.org](philippe.page@humancolossus.org))
+* Lal Chandran ([lal@igrant.io](lal@igrant.io))
+
+Working Group Representative: Ramkumar ([psramkumar2@gmail.com](psramkumar2@gmail.com))
+
+## Deliverables
+
+The key deliverables are as summarised below:
+
+1. [Consent BB definition 0.9.0RC2](https://docs.google.com/document/d/1LR2PRhhE2YMUqnIpIKAu4IprYXXPmsMG/edit?usp=drive_web&ouid=100253799258087784406&rtpof=true)
+1. Use case specifications (see Consent BB Definition)
+1. Functional and technical requirements (see Consent BB Definition)
+1. OpenAPI specs - Latest version: [0.9.0rc1](https://app.swaggerhub.com/apis/GovStack/consent-management-bb/)
+1. Rendered diagrams and diagram sources (maintained in Git)
+
+## Release Status
+
+All diagrams and API specifications contained here are subject to ongoing changes by an internal GovStack Working Group, following this roadmap:
+
+* Wave 2, Internal Review (July 14th, 2022)
+* Release certification (Deadline TBA)
+* Limited publication (Deadline TBA)
+* Community-wide publication (~August 2022)
+
+## Contributing
+
+Feel free to improve the plugin and send us a pull request. If you found any problems, please create an issue in this repo.
+
+## Licensing
+
+Licensing is under [GNU General Public License 3.0](https://github.com/lalc/BuildingBlockAPI/blob/main/LICENSE)
## Consent specs in Gitbook
diff --git a/api/GovStack Consent BB API endpoints - endpoints.csv b/api/GovStack Consent BB API endpoints - endpoints.csv
new file mode 100644
index 0000000..76c41b2
--- /dev/null
+++ b/api/GovStack Consent BB API endpoints - endpoints.csv
@@ -0,0 +1,63 @@
+Endpoint slug,Type,Use case,Scenario,Arguments,Returns,Description,Data sensitivity,summary,operationId,responseOK,security
+API tag: org,,,,,,,,,,,
+CRUDL for Policy object,,,,,,,,,,,
+/org/policy/,GET,"UC-C-PIC-A-001, UC-C-PIC-A-002",,PolicyFilter,Policy,LIST - Fetches list of readable Policy objects,FALSE,Returns a list of readable Policy objects,orgListPolicy,A list of Policy objects readable for the current session's credentials.,admin
+/org/policy/,POST,UC-C-PIC-A-001,,Policy,"Policy, Revision",CREATE - Creates a new Policy object and returns the new object and a PolicyRevision,FALSE,,orgCreatePolicy,"A set consisting of the new Policy object created, together with the initial Revision object.",org
+/org/policy/{id}/,GET,UC-C-PIC-A-003,,PolicyFilter,"Policy, Revision","READ - get a Policy object + latest Revision. If a PolicyFilter is supplied and contains a revision_id, then this specific revision is returned.",FALSE,,orgReadPolicy,,org
+/org/policy/{id}/revisions/,GET,UC-C-PIC-A-003,,,"Policy, Revision",LIST - returns a Policy object with a list of all Revisions,FALSE,,orgListPolicyRevisions,,org
+/org/policy/{id}/,PUT,UC-C-PIC-A-002,,Policy,"Policy, Revision","UPDATE - Updates an existing Policy object, returning the updated version and a new revision. Updating a Policy does not affect existing references in Agreement, the new revision should be specified for Agreement.",FALSE,,orgUpdatePolicy,,org
+/org/policy/{id}/,DELETE,UC-C-PIC-A-004,,,Revision,"DELETE - Deletes an existing Policy object, returning the updated version and a new revision. Deleting a Policy is not possible if it's associated with active Agreement.",FALSE,,orgDeletePolicy,,org
+CRUDL for Agreement object,,,,,,,FALSE,,,,org
+/org/agreement/,GET,UC-C-PIC-A-003,,AgreementFilter,Agreement,,FALSE,,orgListAgreement,,org
+/org/agreement/{id}/,GET,UC-C-PIC-A-003,,,"Agreement, Revision",READ - fetches the latest version of an Agreement,FALSE,,orgReadAgreement,,org
+/org/agreement/,POST,UC-C-PIC-A-001,,Agreement,"Agreement, Revision",CREATE - A new Agreement object is created and returned together with AgreementRevision,FALSE,,orgCreateAgreement,,org
+/org/agreement/{id}/,PUT,UC-C-PIC-A-002,,Agreement,"Agreement, Revision",UPDATE - An existing Agreement object is created and returned together with AgreementRevision,FALSE,,orgUpdateAgreement,,org
+/org/agreement/,DELETE,UC-C-PIC-A-004,,,Revision,,FALSE,,orgDeleteAgreement,,org
+Limited ConsentRecord operations,,,,,,,,,,,org
+/org/record/{id}/,GET,,,,ConsentRecord,READ - fetches a ConsentRecord,TRUE,,orgReadConsentRecord,,org
+/org/record/{id}/withdraw/,PUT,,,,ConsentRecord,"UPDATE - invalidates/withdraws a ConsentRecord, for usage in unconventional withdrawal of consent, for instance if withdrawal happens through an email or phone call.",TRUE,,orgUpdateConsentRecord,,org
+"CRUD for ""Individual"" object",,,,,,,TRUE,,,,org
+/org/individual/,POST,,,RegistryReference,Individual,CREATE - Creates an Individual in the Consent system,TRUE,,orgIndividualCreate,,org
+/org/individual/{id}/,GET,,,,Individual,READ - Fetch an Individual in the Consent system,TRUE,,orgIndividualRead,,org
+/org/individual/{id}/,PUT,,,,Individual,UPDATE - Updates an Individual in the Consent system,TRUE,,orgIndividualUpdate,,org
+/org/individual/{id}/,DELETE,,,,Individual,DELETE - entirely removes an individual from the system and cascades necessary actions to related ConsentRecord objects,TRUE,,orgIndividualDelete,,org
+,,,,,,,,,,,
+,,,,,,,,,,,
+API tag: dataconsumer,,,,,,,,,,,
+/dataconsumer/config/agreement/,GET,,1.1,AgreementFilter,Agreement,LIST - Fetch agreements,FALSE,,,,consumer
+/dataconsumer/consent/,GET,,"3.1, 1.2",ConsentRecordFilter,ConsentRecord,"LIST - Fetch consent records. For a given Agreement and Individual, query if consent exists",TRUE,,,,consumer
+/dataconsumer/agreement/{id}/,GET,,1.2,,Agreement,READ - Fetch a specific agreement,FALSE,,,,consumer
+,,,,,,,,,,,consumer
+API tag: individual,,,,,,,,,,,
+/individual/{id}/agreement/{agreementId}/,POST,UC-C-PIC-I-002,1.2,"Individual, Agreement, Revision","ConsentRecord, Revision","CREATE - For a particular Individual and a particular Agreement, create a new Consent Record pointing to the current Revision of a given Agreement",TRUE,,,,individual
+/individual/{id}/consentrecord/{consentRecordId}/,PUT,UC-C-PIC-I-003,,"Individual, Agreement, Revision","ConsentRecord, Revision",UPDATE*,TRUE,,,,individual
+/individual/{id}/agreement/{agreementId}/withdraw/,PUT,UC-C-PIC-I-003,,Individual,"ConsentRecord, Revision",UPDATE*,TRUE,,,,individual
+/individual/{id}/agreement/,GET,UC-C-PIC-I-001,,,"ConsentRecord, Agreement",LIST,TRUE,,,,individual
+/individual/{id}/agreement/{agreementId}/,GET,UC-C-PIC-I-001,,,"ConsentRecord, Revision",LIST,TRUE,,,,individual
+/individual/{id}/,DELETE,,,,,"DELETE - Cascading delete operation for Right To Be Forgotten, deletes all Consent Records that shall not be retained and have a ""forgettable"" Agreement.",TRUE,,,,individual
+,,,,,,,,,,,
+API tag: auditor,,,,,,,,,,,
+/auditor/tracker/,GET,"UC-C-PIC-AT-001, UC-C-PIC-AT-002",,,AuditTracker,LIST - show available AuditTracker objects,,,,,
+/auditor/tracker/,POST,"UC-C-PIC-AT-001, UC-C-PIC-AT-002",,AuditTracker,AuditTracker,CREATE - A new AuditTracker is set up,,,,,
+/auditor/tracker/{id}/,GET,"UC-C-PIC-AT-001, UC-C-PIC-AT-002",,,AuditTracker,READ - get the details of an AuditTracker,,,,,
+/auditor/tracker/{id}/,PUT,"UC-C-PIC-AT-001, UC-C-PIC-AT-002",,AuditTracker,AuditTracker,UPDATE - get the details of an AuditTracker,,,,,
+/auditor/tracker/{id}/,DELETE,"UC-C-PIC-AT-001, UC-C-PIC-AT-002",,,AuditTracker,DELETE - removes an AuditTracker,,,,,
+/auditor/consentrecord/,GET,UC-C-PIC-AT-003,,ConsentRecordFilter,ConsentRecord,LIST - fetch ConsentRecord objects,,,,,
+/auditor/agreement/,GET,UC-C-PIC-AT-003,,AgreementFilter,Agreement,LIST - fetch configured Agreement objects,,,,,
+,,,,,,,,,,,
+API tag: notification,,,,,,,,,,,
+,,,,,,,,,,,
+API tag: callback,,,,,,,,,,,
+/callback/registrybb/revision/{id}/,,,,RegistryReference,,"For asynchronous flows, the Consenent Management BB will require a callback from the Registry BB when saving and updating records on an Individual.",FALSE,,,,
+,,,,,,,,,,,
+,,,,,,,,,,,
+Questions / notes,,,,,,,,,,,
+"Sensitive/Personal data - Make Individual ID stored as some kind of anonymous token in HTTP headers, session state or like-wise. We should avoid spilling over individually identifiable data in HTTP server logs etc.",,,,,,,,,,,
+"Right To Be Forgotten, all the rights actually...",,,,,,,,,,,
+List filters and pagination,,,,,,,,,,,
+"Should we have CRUD for ""Individual""?",,,,,,,,,,,
+"Is there a ""Registry BB"" (used in UC sequence diagrams) -- or just a Registration BB?",,,,,,,,,,,
+TODO,,,,,,,,,,,
+m2m fields: Policy <> Agreement,,,,,,,,,,,
+atomic endpoints: List of ConsentRecordChoice and Policy,,,,,,,,,,,
+"Return values, especially lists in return values",,,,,,,,,,,
\ No newline at end of file
diff --git a/api/GovStack Consent BB API endpoints - schema.csv b/api/GovStack Consent BB API endpoints - schema.csv
new file mode 100644
index 0000000..3609cab
--- /dev/null
+++ b/api/GovStack Consent BB API endpoints - schema.csv
@@ -0,0 +1,120 @@
+Name,Type,FK,Description,Required,Flagged for further discussion,Originating spec / analysis,ISO mapping
+Model: Individual,,,"Shallowly models an Individual which may reference some instance in an external system (registration system, functional ID, foundational ID etc). An Individual instance of this model is not to be mistaken with a unique natural individual. It is up to the system owner to decide if this record permits mapping to a natural individual and/or if a single Individual row can map to several consent agreements.",,,GovStack,
+id,string,,The unique ID of an Individual row.,TRUE,FALSE,,
+functional_id,string,,"Non-mandatory reference to a functional ID, which is likely PII",FALSE,TRUE,GovStack,
+foundational_id,string,,Non-mandatory (natural) ID and PII,FALSE,TRUE,GovStack,
+session_id,string,,An Individual may simply be mapped to a temporary session.,FALSE,TRUE,GovStack,
+,,,,,,,
+Model: Agreement,,,An agreement contains the specification of a single purpose that can be consented to. An Agreement is universal and can be consented to by *many* individuals through a ConsentRecord,,,ADA,
+id,string,,,TRUE,FALSE,,
+version,string,,The version of this specification to which a receipt conforms,TRUE,FALSE,ADA,
+controller,fk,Controller,Data controller (may be omitted if no data involved),FALSE,FALSE,ADA,
+policy,fk,Policy,Reference to the policy under which this Agreement shall be governed,TRUE,FALSE,ADA,
+purpose,fk,AgreementPurpose,Purpose of data processing or purpose of consent. Displayed to the user.,TRUE,FALSE,ADA,
+lawful_basis,string,,Lawful basis of the agreement - consent / legal_obligation / contract / vital_interest / public_task / legitimate_interest,TRUE,FALSE,ADA,
+data_use,string,,null/data-source/data-using-service,FALSE,FALSE,ADA,
+dpia,string,,Data Protection Impact Assessment,TRUE,FALSE,ADA,
+lifecycle,fk,AgreementLifecycle,Current Lifecycle state of the Agreement,TRUE,TRUE,GovStack,
+signature,fk,Signature,Signature of authorizing party of Agreement. Note: Signatures may be chained in case of multiple signatures.,FALSE,TRUE,GovStack,
+active,boolean,,Agreement is active and new ConsentRecords can be created.,FALSE,FALSE,GovStack,
+forgettable,boolean,,"Agreement may be deleted when consent is withdrawn, as its existence is not necessary for auditability.",FALSE,TRUE,GovStack,
+,,,,,,,
+Model: AgreementData,,,Agreement data contains specifications of exactly what is collected.,,,ADA*,
+id,string,,,TRUE,FALSE,,
+agreement,fk,Agreement,,TRUE,FALSE,ADA,
+name,string,,"Name of the attribute, for instance ""name"" or ""age""",TRUE,FALSE,ADA,
+sensitivity,string,,TBD: categories of sensitivity from som ISO,TRUE,FALSE,GovStack,
+category,string,,,TRUE,FALSE,ADA,
+hash,string,,"In order to sign an Agreement, this relation needs to have a cryptopgraphic hash to be included in the Signature of the Agreement.",TRUE,TRUE,GovStack,
+,,,,,,,
+Model: Policy,,,"A policy governs data and Agreement in the realm of an organisation that is refered to as ""data controller"" (GDPR) and owner of referencing Agreements.",,,ADA*,
+id,string,,,TRUE,FALSE,,
+name,string,,Name of the policy,TRUE,FALSE,ADA,
+version,string,,Version of the policy,TRUE,FALSE,ADA,
+url,string,,"Permanent URL at which this very version of the Policy can be read, should not be allowed to change over time.",TRUE,FALSE,ADA,
+jurisdiction,string,,,FALSE,FALSE,ADA,
+industry_sector,string,,,FALSE,FALSE,ADA,
+data_retention_period_days,integer,,,FALSE,FALSE,ADA,
+geographic_restriction,string,,,FALSE,FALSE,ADA,
+storage_location,string,,,FALSE,FALSE,ADA,
+,,,,,,,
+Model: ConsentRecord,,,A Consent Record expresses consent (as defined in this building block's specification) to a single Agreement.,,,GovStack,
+id,string,,,TRUE,FALSE,,
+agreement,fk,Agreement,The agreement to which consent has been given,TRUE,FALSE,GovStack,
+agreement_revision,fk,Revision,,TRUE,FALSE,GovStack,
+individual,fk,Individual,The individual who has signed this consent record,TRUE,FALSE,GovStack,
+opt_in,boolean,,True: The individual has positively opted in. False: The individual has explicitly said no (or withdrawn a previous consent).,FALSE,FALSE,GovStack,
+state,string,,unsigned/pending more signatures/signed,TRUE,FALSE,GovStack,
+signature,fk,Signature,"A signature that hashes all the values of the consent record and has signed it with the key of the Invidiual, making it verifiable and tamper-proof. TBD: Relation to a Signature schema?",TRUE,TRUE,GovStack,
+,,,,,,,
+Model: Revision,,,"A *generic* revision model captures the serialized contents of any shema's single row. This is then subject to 1) cryptographic signature and 2) auditing.
+
+Aside from ""successor"" column, a revision should be considered locked.",,,GovStack,
+id,string,,,TRUE,FALSE,,
+schema,string,,,TRUE,FALSE,GovStack,
+object_id,string,,,TRUE,FALSE,GovStack,
+serialized_snapshot,string,,,TRUE,FALSE,GovStack,
+timestamp,string,,,TRUE,FALSE,GovStack,
+authorized_by_individual,fk,Individual,,FALSE,TRUE,GovStack,
+authorized_by_other,string,,Reference to an admin user that has created this revision,FALSE,TRUE,GovStack,
+successor,fk,Revision,"This revision is no longer the latest revision, refer to its successor.",FALSE,FALSE,GovStack,
+predecessor_hash,string,,Tamper-resistent artifact from previous record,FALSE,FALSE,GovStack,
+predecessor_signature,string,,Tamper-resistent artifact from previous record (we don't know if the previous record was signed or not),FALSE,FALSE,GovStack,
+,,,,,,,
+Model: AgreementFilter,,,Query filter for API endpoint listing Agreement objects,,,,
+id,string,,,TRUE,FALSE,,
+name,string,,,TRUE,FALSE,,
+,,,,,,,
+Model: ConsentRecordFilter,,,Query filter for API endpoint listing ConsentRecord objects,,,,
+id,string,,,TRUE,FALSE,,
+opt_in,boolean,,,TRUE,FALSE,,
+,,,,,,,
+Model: PolicyFilter,,,Query filter for API endpoint listing Policy objects,,,,
+id,string,,,TRUE,FALSE,,
+name,string,,,TRUE,FALSE,,
+revision,fk,Revision,,FALSE,FALSE,,
+,,,,,,,
+Model: Controller,,,Details of a data controller.,,,ADA*,
+id,string,,,TRUE,FALSE,,
+name,string,,Name of data controller (may be omitted if no data involved),TRUE,FALSE,ADA,
+url,string,,URL of data controller (may be omitted if no data involved),TRUE,FALSE,ADA,
+,,,,,,,
+Model: Signature,,,"A generic signature contains a cryptographic hash of some value, together with a signature created by some private key in another system. Required signing methods: Revision object or another Signature object.",,,GovStack,
+id,string,,,TRUE,FALSE,,
+verification_method,string,,,TRUE,FALSE,GovStack,Kantara (Consent Receipt Collection Method)
+verification_hash,string,,Internally generated cryptographic hash of the value to be signed.,TRUE,FALSE,GovStack,
+verification_signature,string,,Signature of verification_hash,TRUE,FALSE,GovStack,
+verification_artifact,string,,"A verification artifact in the form of a scanned object, image, signature etc.",FALSE,TRUE,GovStack,
+jws_header,string,,"Alternative to the verification_method, verification_hash and verification_signature, give a JWS serialized object (RFC7515)",FALSE,TRUE,GovStack,
+signed_by,string,,"Identifier information may change over time. This field could contain a natural individual's names, personal number, email addresses - store a snapshot that binds to the signature at the time of signing.",TRUE,TRUE,GovStack,
+timestamp,string,,Timestamp of signature,TRUE,TRUE,GovStack,
+object_type,string,,signature/revision,FALSE,TRUE,GovStack,
+object_reference,string,,"A symmetric relation / back reference to the object_type that was signed. We are currently just modelling signing another signature (a chain) or signing a Revision (which can be a revision of an agreement, policy etc)",FALSE,TRUE,GovStack,
+,,,,,,,
+Model: AgreementPurpose,,,TBD: Models the purpose of an agreement,,,ADA*,
+id,string,,,TRUE,TRUE,,
+name,string,,Name of purpose,TRUE,TRUE,ADA*,
+description,string,,Description of purpose,TRUE,TRUE,ADA*,
+,,,,,,,
+Model: AgreementLifecycle,,,TBD: Models the valid lifecycle states of an Agreement,,,GovStack/ADA,
+id,string,,,TRUE,TRUE,,
+name,string,,Definition / Preparation / Capture / Use / Proof,TRUE,TRUE,,
+,,,,,,,
+Model: RegistryReference,,,"TBD: When creating an Invidiual, we need some input that refers to a functional or foundational ID in an external system",,,,
+id,string,,,TRUE,TRUE,,
+foundational_id,string,,,FALSE,FALSE,,
+functional_id,string,,,FALSE,FALSE,,
+,,,,,,,
+Model: AuditTracker,,,TBD: An external tracker receiving information from the system that can be subject to external auditing and verification of correct behavior. This is one of several notification/monitor/subscription patterns that may be more suitable for an encrypted Pub/Sub service.,,,GovStack,
+id,string,,,TRUE,TRUE,,
+name,string,,Name of the auditing system,TRUE,TRUE,,
+public_key,string,,The auditing system's public key for encrypting data sent to callback functions,TRUE,TRUE,GovStack,
+callback_agreement,string,,A URL receiving a callback with the Agreement object + Revision + AuditEventType,TRUE,TRUE,GovStack,
+callback_consent_record,string,,A URL receiving a callback with the ConsentRecord object + Revision + AuditEventType,TRUE,TRUE,GovStack,
+callback_policy,string,,A URL receiving a callback with the Policy object + Revision + AuditEventType,TRUE,TRUE,GovStack,
+callback_revision_table_hash,string,,"A URL receiving a callback with + AuditEventType. Periodically, the system can publish the hash of the revision table.",FALSE,TRUE,MOSIP,
+callback_signature_table_hash,string,,"A URL receiving a callback with + AuditEventType. Periodically, the system can publish the hash of the signature table.",FALSE,TRUE,MOSIP,
+,,,,,,,
+Model: AuditEventType,,,"TBD: Model for the possible events pertaining a change to an object subject to auditing. This model is not necessarily a database-backed model, but part of application code.",,,,
+id,string,,,TRUE,TRUE,,
+event_name,string,,What happened - create/update/delete,,,,
\ No newline at end of file
diff --git a/api/consent-openapi.yaml b/api/consent-openapi.yaml
new file mode 100644
index 0000000..b6e371c
--- /dev/null
+++ b/api/consent-openapi.yaml
@@ -0,0 +1,1958 @@
+openapi: 3.0.0
+servers:
+ # Added by API Auto Mocking Plugin
+ - description: SwaggerHub API Auto Mocking
+ url: https://app.swaggerhub.com/apis/GovStack/consent-management-bb/
+info:
+ description: This is a basic API for GovStack's Consent Management Building Block. It reflects the basic requirements of the Consent Management BB specification, which is versioned .
+ version: 0.9.0-rc1
+ title: Consent Management BB API
+ contact:
+ email: balder@overtag.dk
+ license:
+ name: Apache 2.0
+ url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
+tags:
+ - name: org
+ description: Secured operations available to organization API integration
+ - name: dataconsumer
+ description: Secured operations for data consumers and applications to verify consent
+ - name: individual
+ description: Individual operations
+ - name: auditor
+ description: Operations for external auditing systems to query detailed data from the system and subscribe to notifications.
+ - name: notification
+ description: Subscribe/unsubscribe notifications for data processors, consumers and frontend systems for individuals.
+ - name: callback
+ description: Callback API for other Building Blocks, especially relevant for asynchronous processes.
+paths:
+
+ /org/policy/:
+
+ get:
+ tags:
+ - org
+ summary: "Returns a list of readable Policy objects"
+ operationId: "orgListPolicy"
+ description: "LIST - Fetches list of readable Policy objects"
+ parameters:
+ - in: query
+ name: PolicyFilter
+ description: "An object of type PolicyFilter"
+ required: true
+ schema:
+ $ref: '#/components/schemas/PolicyFilter'
+
+ - in: query
+ name: "offset"
+ description: "Requested index for start of resources to be provided in response requested by client"
+ required: false
+ schema:
+ type: integer
+
+ - in: query
+ name: "limit"
+ description: "Requested number of resources to be provided in response requested by client"
+ required: false
+ schema:
+ type: integer
+
+ x-specification-usecase: "UC-C-PIC-A-001, UC-C-PIC-A-002"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: "A list of Policy objects readable for the current session's credentials."
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [admin]
+
+
+ post:
+ tags:
+ - org
+ summary: "CREATE - Creates a new Policy object and returns the new object and a PolicyRevision"
+ operationId: "orgCreatePolicy"
+ description: "CREATE - Creates a new Policy object and returns the new object and a PolicyRevision"
+ parameters:
+ - in: query
+ name: Policy
+ description: "An object of type Policy"
+ required: true
+ schema:
+ $ref: '#/components/schemas/Policy'
+
+ x-specification-usecase: "UC-C-PIC-A-001"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: "A set consisting of the new Policy object created, together with the initial Revision object."
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ /org/policy/{id}/:
+
+ get:
+ tags:
+ - org
+ summary: "READ - get a Policy object + latest Revision. If a PolicyFilter is supplied and contains a revision_id, then this specific revision is returned."
+ operationId: "orgReadPolicy"
+ description: "READ - get a Policy object + latest Revision. If a PolicyFilter is supplied and contains a revision_id, then this specific revision is returned."
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ - in: query
+ name: PolicyFilter
+ description: "An object of type PolicyFilter"
+ required: true
+ schema:
+ $ref: '#/components/schemas/PolicyFilter'
+
+ x-specification-usecase: "UC-C-PIC-A-003"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ put:
+ tags:
+ - org
+ summary: "UPDATE - Updates an existing Policy object, returning the updated version and a new revision. Updating a Policy does not affect existing references in Agreement, the new revision should be specified for Agreement."
+ operationId: "orgUpdatePolicy"
+ description: "UPDATE - Updates an existing Policy object, returning the updated version and a new revision. Updating a Policy does not affect existing references in Agreement, the new revision should be specified for Agreement."
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ - in: query
+ name: Policy
+ description: "An object of type Policy"
+ required: true
+ schema:
+ $ref: '#/components/schemas/Policy'
+
+ x-specification-usecase: "UC-C-PIC-A-002"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ delete:
+ tags:
+ - org
+ summary: "DELETE - Deletes an existing Policy object, returning the updated version and a new revision. Deleting a Policy is not possible if it's associated with active Agreement."
+ operationId: "orgDeletePolicy"
+ description: "DELETE - Deletes an existing Policy object, returning the updated version and a new revision. Deleting a Policy is not possible if it's associated with active Agreement."
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ x-specification-usecase: "UC-C-PIC-A-004"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ /org/policy/{id}/revisions/:
+
+ get:
+ tags:
+ - org
+ summary: "LIST - returns a Policy object with a list of all Revisions"
+ operationId: "orgListPolicyRevisions"
+ description: "LIST - returns a Policy object with a list of all Revisions"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ - in: query
+ name: "offset"
+ description: "Requested index for start of resources to be provided in response requested by client"
+ required: false
+ schema:
+ type: integer
+
+ - in: query
+ name: "limit"
+ description: "Requested number of resources to be provided in response requested by client"
+ required: false
+ schema:
+ type: integer
+
+ x-specification-usecase: "UC-C-PIC-A-003"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ /org/agreement/:
+
+ get:
+ tags:
+ - org
+ summary: ""
+ operationId: "orgListAgreement"
+ description: ""
+ parameters:
+ - in: query
+ name: AgreementFilter
+ description: "An object of type AgreementFilter"
+ required: true
+ schema:
+ $ref: '#/components/schemas/AgreementFilter'
+
+ - in: query
+ name: "offset"
+ description: "Requested index for start of resources to be provided in response requested by client"
+ required: false
+ schema:
+ type: integer
+
+ - in: query
+ name: "limit"
+ description: "Requested number of resources to be provided in response requested by client"
+ required: false
+ schema:
+ type: integer
+
+ x-specification-usecase: "UC-C-PIC-A-003"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ post:
+ tags:
+ - org
+ summary: "CREATE - A new Agreement object is created and returned together with AgreementRevision"
+ operationId: "orgCreateAgreement"
+ description: "CREATE - A new Agreement object is created and returned together with AgreementRevision"
+ parameters:
+ - in: query
+ name: Agreement
+ description: "An object of type Agreement"
+ required: true
+ schema:
+ $ref: '#/components/schemas/Agreement'
+
+ x-specification-usecase: "UC-C-PIC-A-001"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ delete:
+ tags:
+ - org
+ summary: ""
+ operationId: "orgDeleteAgreement"
+ description: ""
+ parameters: []
+ x-specification-usecase: "UC-C-PIC-A-004"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ /org/agreement/{id}/:
+
+ get:
+ tags:
+ - org
+ summary: "READ - fetches the latest version of an Agreement"
+ operationId: "orgReadAgreement"
+ description: "READ - fetches the latest version of an Agreement"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ x-specification-usecase: "UC-C-PIC-A-003"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ put:
+ tags:
+ - org
+ summary: "UPDATE - An existing Agreement object is created and returned together with AgreementRevision"
+ operationId: "orgUpdateAgreement"
+ description: "UPDATE - An existing Agreement object is created and returned together with AgreementRevision"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ - in: query
+ name: Agreement
+ description: "An object of type Agreement"
+ required: true
+ schema:
+ $ref: '#/components/schemas/Agreement'
+
+ x-specification-usecase: "UC-C-PIC-A-002"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ /org/record/{id}/:
+
+ get:
+ tags:
+ - org
+ summary: "READ - fetches a ConsentRecord"
+ operationId: "orgReadConsentRecord"
+ description: "READ - fetches a ConsentRecord"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ x-specification-usecase: ""
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "True"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ /org/record/{id}/withdraw/:
+
+ put:
+ tags:
+ - org
+ summary: "UPDATE - invalidates/withdraws a ConsentRecord, for usage in unconventional withdrawal of consent, for instance if withdrawal happens through an email or phone call."
+ operationId: "orgUpdateConsentRecord"
+ description: "UPDATE - invalidates/withdraws a ConsentRecord, for usage in unconventional withdrawal of consent, for instance if withdrawal happens through an email or phone call."
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ x-specification-usecase: ""
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "True"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ /org/individual/:
+
+ post:
+ tags:
+ - org
+ summary: "CREATE - Creates an Individual in the Consent system"
+ operationId: "orgIndividualCreate"
+ description: "CREATE - Creates an Individual in the Consent system"
+ parameters:
+ - in: query
+ name: RegistryReference
+ description: "An object of type RegistryReference"
+ required: true
+ schema:
+ $ref: '#/components/schemas/RegistryReference'
+
+ x-specification-usecase: ""
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "True"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ /org/individual/{id}/:
+
+ get:
+ tags:
+ - org
+ summary: "READ - Fetch an Individual in the Consent system"
+ operationId: "orgIndividualRead"
+ description: "READ - Fetch an Individual in the Consent system"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ x-specification-usecase: ""
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "True"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ put:
+ tags:
+ - org
+ summary: "UPDATE - Updates an Individual in the Consent system"
+ operationId: "orgIndividualUpdate"
+ description: "UPDATE - Updates an Individual in the Consent system"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ x-specification-usecase: ""
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "True"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ delete:
+ tags:
+ - org
+ summary: "DELETE - entirely removes an individual from the system and cascades necessary actions to related ConsentRecord objects"
+ operationId: "orgIndividualDelete"
+ description: "DELETE - entirely removes an individual from the system and cascades necessary actions to related ConsentRecord objects"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ x-specification-usecase: ""
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "True"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [org]
+
+
+ /dataconsumer/config/agreement/:
+
+ get:
+ tags:
+ - dataconsumer
+ summary: "LIST - Fetch agreements"
+ operationId: ""
+ description: "LIST - Fetch agreements"
+ parameters:
+ - in: query
+ name: AgreementFilter
+ description: "An object of type AgreementFilter"
+ required: true
+ schema:
+ $ref: '#/components/schemas/AgreementFilter'
+
+ x-specification-usecase: ""
+ x-specification-scenario: "1.1"
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [consumer]
+
+
+ /dataconsumer/consent/:
+
+ get:
+ tags:
+ - dataconsumer
+ summary: "LIST - Fetch consent records. For a given Agreement and Individual, query if consent exists"
+ operationId: ""
+ description: "LIST - Fetch consent records. For a given Agreement and Individual, query if consent exists"
+ parameters:
+ - in: query
+ name: ConsentRecordFilter
+ description: "An object of type ConsentRecordFilter"
+ required: true
+ schema:
+ $ref: '#/components/schemas/ConsentRecordFilter'
+
+ x-specification-usecase: ""
+ x-specification-scenario: "3.1, 1.2"
+ x-specification-pii-or-sensitive: "True"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [consumer]
+
+
+ /dataconsumer/agreement/{id}/:
+
+ get:
+ tags:
+ - dataconsumer
+ summary: "READ - Fetch a specific agreement"
+ operationId: ""
+ description: "READ - Fetch a specific agreement"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ x-specification-usecase: ""
+ x-specification-scenario: "1.2"
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [consumer]
+
+
+ /individual/{id}/agreement/{agreementId}/:
+
+ post:
+ tags:
+ - individual
+ summary: "CREATE - For a particular Individual and a particular Agreement, create a new Consent Record pointing to the current Revision of a given Agreement"
+ operationId: ""
+ description: "CREATE - For a particular Individual and a particular Agreement, create a new Consent Record pointing to the current Revision of a given Agreement"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ - in: path
+ name: "agreementId"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ - in: query
+ name: Individual
+ description: "An object of type Individual"
+ required: true
+ schema:
+ $ref: '#/components/schemas/Individual'
+
+ - in: query
+ name: Agreement
+ description: "An object of type Agreement"
+ required: true
+ schema:
+ $ref: '#/components/schemas/Agreement'
+
+ - in: query
+ name: Revision
+ description: "An object of type Revision"
+ required: true
+ schema:
+ $ref: '#/components/schemas/Revision'
+
+ x-specification-usecase: "UC-C-PIC-I-002"
+ x-specification-scenario: "1.2"
+ x-specification-pii-or-sensitive: "True"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [individual]
+
+
+ get:
+ tags:
+ - individual
+ summary: "LIST"
+ operationId: ""
+ description: "LIST"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ - in: path
+ name: "agreementId"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ x-specification-usecase: "UC-C-PIC-I-001"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "True"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [individual]
+
+
+ /individual/{id}/consentrecord/{consentRecordId}/:
+
+ put:
+ tags:
+ - individual
+ summary: "UPDATE*"
+ operationId: ""
+ description: "UPDATE*"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ - in: path
+ name: "consentRecordId"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ - in: query
+ name: Individual
+ description: "An object of type Individual"
+ required: true
+ schema:
+ $ref: '#/components/schemas/Individual'
+
+ - in: query
+ name: Agreement
+ description: "An object of type Agreement"
+ required: true
+ schema:
+ $ref: '#/components/schemas/Agreement'
+
+ - in: query
+ name: Revision
+ description: "An object of type Revision"
+ required: true
+ schema:
+ $ref: '#/components/schemas/Revision'
+
+ x-specification-usecase: "UC-C-PIC-I-003"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "True"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [individual]
+
+
+ /individual/{id}/agreement/{agreementId}/withdraw/:
+
+ put:
+ tags:
+ - individual
+ summary: "UPDATE*"
+ operationId: ""
+ description: "UPDATE*"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ - in: path
+ name: "agreementId"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ - in: query
+ name: Individual
+ description: "An object of type Individual"
+ required: true
+ schema:
+ $ref: '#/components/schemas/Individual'
+
+ x-specification-usecase: "UC-C-PIC-I-003"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "True"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [individual]
+
+
+ /individual/{id}/agreement/:
+
+ get:
+ tags:
+ - individual
+ summary: "LIST"
+ operationId: ""
+ description: "LIST"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ x-specification-usecase: "UC-C-PIC-I-001"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "True"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [individual]
+
+
+ /individual/{id}/:
+
+ delete:
+ tags:
+ - individual
+ summary: "DELETE - Cascading delete operation for Right To Be Forgotten, deletes all Consent Records that shall not be retained and have a \"forgettable\" Agreement."
+ operationId: ""
+ description: "DELETE - Cascading delete operation for Right To Be Forgotten, deletes all Consent Records that shall not be retained and have a \"forgettable\" Agreement."
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ x-specification-usecase: ""
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "True"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [individual]
+
+
+ /auditor/tracker/:
+
+ get:
+ tags:
+ - auditor
+ summary: "LIST - show available AuditTracker objects"
+ operationId: ""
+ description: "LIST - show available AuditTracker objects"
+ parameters: []
+ x-specification-usecase: "UC-C-PIC-AT-001, UC-C-PIC-AT-002"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: []
+
+
+ post:
+ tags:
+ - auditor
+ summary: "CREATE - A new AuditTracker is set up"
+ operationId: ""
+ description: "CREATE - A new AuditTracker is set up"
+ parameters:
+ - in: query
+ name: AuditTracker
+ description: "An object of type AuditTracker"
+ required: true
+ schema:
+ $ref: '#/components/schemas/AuditTracker'
+
+ x-specification-usecase: "UC-C-PIC-AT-001, UC-C-PIC-AT-002"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: []
+
+
+ /auditor/tracker/{id}/:
+
+ get:
+ tags:
+ - auditor
+ summary: "READ - get the details of an AuditTracker"
+ operationId: ""
+ description: "READ - get the details of an AuditTracker"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ x-specification-usecase: "UC-C-PIC-AT-001, UC-C-PIC-AT-002"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: []
+
+
+ put:
+ tags:
+ - auditor
+ summary: "UPDATE - get the details of an AuditTracker"
+ operationId: ""
+ description: "UPDATE - get the details of an AuditTracker"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ - in: query
+ name: AuditTracker
+ description: "An object of type AuditTracker"
+ required: true
+ schema:
+ $ref: '#/components/schemas/AuditTracker'
+
+ x-specification-usecase: "UC-C-PIC-AT-001, UC-C-PIC-AT-002"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: []
+
+
+ delete:
+ tags:
+ - auditor
+ summary: "DELETE - removes an AuditTracker"
+ operationId: ""
+ description: "DELETE - removes an AuditTracker"
+ parameters:
+ - in: path
+ name: "id"
+ description: "Unique ID of an object"
+ required: true
+ schema:
+ type: string
+
+ x-specification-usecase: "UC-C-PIC-AT-001, UC-C-PIC-AT-002"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: []
+
+
+ /auditor/consentrecord/:
+
+ get:
+ tags:
+ - auditor
+ summary: "LIST - fetch ConsentRecord objects"
+ operationId: ""
+ description: "LIST - fetch ConsentRecord objects"
+ parameters:
+ - in: query
+ name: ConsentRecordFilter
+ description: "An object of type ConsentRecordFilter"
+ required: true
+ schema:
+ $ref: '#/components/schemas/ConsentRecordFilter'
+
+ x-specification-usecase: "UC-C-PIC-AT-003"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: []
+
+
+ /auditor/agreement/:
+
+ get:
+ tags:
+ - auditor
+ summary: "LIST - fetch configured Agreement objects"
+ operationId: ""
+ description: "LIST - fetch configured Agreement objects"
+ parameters:
+ - in: query
+ name: AgreementFilter
+ description: "An object of type AgreementFilter"
+ required: true
+ schema:
+ $ref: '#/components/schemas/AgreementFilter'
+
+ x-specification-usecase: "UC-C-PIC-AT-003"
+ x-specification-scenario: ""
+ x-specification-pii-or-sensitive: "False"
+ responses:
+ '200':
+ description: ""
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: []
+
+
+
+components:
+ schemas:
+
+ Individual:
+ type: object
+ description: "Shallowly models an Individual which may reference some instance in an external system (registration system, functional ID, foundational ID etc). An Individual instance of this model is not to be mistaken with a unique natural individual. It is up to the system owner to decide if this record permits mapping to a natural individual and/or if a single Individual row can map to several consent agreements."
+ required:
+ - id
+ - functional_id
+ - foundational_id
+ - session_id
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: "The unique ID of an Individual row."
+
+ functional_id:
+ type: string
+ format: ""
+ example: ""
+ description: "Non-mandatory reference to a functional ID, which is likely PII"
+
+ foundational_id:
+ type: string
+ format: ""
+ example: ""
+ description: "Non-mandatory (natural) ID and PII"
+
+ session_id:
+ type: string
+ format: ""
+ example: ""
+ description: "An Individual may simply be mapped to a temporary session."
+
+
+ Agreement:
+ type: object
+ description: "An agreement contains the specification of a single purpose that can be consented to. An Agreement is universal and can be consented to by *many* individuals through a ConsentRecord"
+ required:
+ - id
+ - version
+ - controller
+ - policy
+ - purpose
+ - lawful_basis
+ - data_use
+ - dpia
+ - lifecycle
+ - signature
+ - active
+ - forgettable
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ version:
+ type: string
+ format: ""
+ example: ""
+ description: "The version of this specification to which a receipt conforms"
+
+ controller:
+ $ref: '#/components/schemas/Controller'
+
+ policy:
+ $ref: '#/components/schemas/Policy'
+
+ purpose:
+ $ref: '#/components/schemas/AgreementPurpose'
+
+ lawful_basis:
+ type: string
+ format: ""
+ example: ""
+ description: "Lawful basis of the agreement - consent / legal_obligation / contract / vital_interest / public_task / legitimate_interest"
+
+ data_use:
+ type: string
+ format: ""
+ example: ""
+ description: "null/data-source/data-using-service"
+
+ dpia:
+ type: string
+ format: ""
+ example: ""
+ description: "Data Protection Impact Assessment"
+
+ lifecycle:
+ $ref: '#/components/schemas/AgreementLifecycle'
+
+ signature:
+ $ref: '#/components/schemas/Signature'
+
+ active:
+ type: boolean
+ format: ""
+ example: ""
+ description: "Agreement is active and new ConsentRecords can be created."
+
+ forgettable:
+ type: boolean
+ format: ""
+ example: ""
+ description: "Agreement may be deleted when consent is withdrawn, as its existence is not necessary for auditability."
+
+
+ AgreementData:
+ type: object
+ description: "Agreement data contains specifications of exactly what is collected."
+ required:
+ - id
+ - agreement
+ - name
+ - sensitivity
+ - category
+ - hash
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ agreement:
+ $ref: '#/components/schemas/Agreement'
+
+ name:
+ type: string
+ format: ""
+ example: ""
+ description: "Name of the attribute, for instance \"name\" or \"age\""
+
+ sensitivity:
+ type: string
+ format: ""
+ example: ""
+ description: "TBD: categories of sensitivity from som ISO"
+
+ category:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ hash:
+ type: string
+ format: ""
+ example: ""
+ description: "In order to sign an Agreement, this relation needs to have a cryptopgraphic hash to be included in the Signature of the Agreement."
+
+
+ Policy:
+ type: object
+ description: "A policy governs data and Agreement in the realm of an organisation that is refered to as \"data controller\" (GDPR) and owner of referencing Agreements."
+ required:
+ - id
+ - name
+ - version
+ - url
+ - jurisdiction
+ - industry_sector
+ - data_retention_period_days
+ - geographic_restriction
+ - storage_location
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ name:
+ type: string
+ format: ""
+ example: ""
+ description: "Name of the policy"
+
+ version:
+ type: string
+ format: ""
+ example: ""
+ description: "Version of the policy"
+
+ url:
+ type: string
+ format: ""
+ example: ""
+ description: "Permanent URL at which this very version of the Policy can be read, should not be allowed to change over time."
+
+ jurisdiction:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ industry_sector:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ data_retention_period_days:
+ type: integer
+ format: ""
+ example: ""
+ description: ""
+
+ geographic_restriction:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ storage_location:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+
+ ConsentRecord:
+ type: object
+ description: "A Consent Record expresses consent (as defined in this building block's specification) to a single Agreement."
+ required:
+ - id
+ - agreement
+ - agreement_revision
+ - individual
+ - opt_in
+ - state
+ - signature
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ agreement:
+ $ref: '#/components/schemas/Agreement'
+
+ agreement_revision:
+ $ref: '#/components/schemas/Revision'
+
+ individual:
+ $ref: '#/components/schemas/Individual'
+
+ opt_in:
+ type: boolean
+ format: ""
+ example: ""
+ description: "True: The individual has positively opted in. False: The individual has explicitly said no (or withdrawn a previous consent)."
+
+ state:
+ type: string
+ format: ""
+ example: ""
+ description: "unsigned/pending more signatures/signed"
+
+ signature:
+ $ref: '#/components/schemas/Signature'
+
+
+ Revision:
+ type: object
+ description: "A *generic* revision model captures the serialized contents of any shema's single row. This is then subject to 1) cryptographic signature and 2) auditing.\n\nAside from \"successor\" column, a revision should be considered locked."
+ required:
+ - id
+ - schema
+ - object_id
+ - serialized_snapshot
+ - timestamp
+ - authorized_by_individual
+ - authorized_by_other
+ - successor
+ - predecessor_hash
+ - predecessor_signature
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ schema:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ object_id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ serialized_snapshot:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ timestamp:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ authorized_by_individual:
+ $ref: '#/components/schemas/Individual'
+
+ authorized_by_other:
+ type: string
+ format: ""
+ example: ""
+ description: "Reference to an admin user that has created this revision"
+
+ successor:
+ $ref: '#/components/schemas/Revision'
+
+ predecessor_hash:
+ type: string
+ format: ""
+ example: ""
+ description: "Tamper-resistent artifact from previous record"
+
+ predecessor_signature:
+ type: string
+ format: ""
+ example: ""
+ description: "Tamper-resistent artifact from previous record (we don't know if the previous record was signed or not)"
+
+
+ AgreementFilter:
+ type: object
+ description: "Query filter for API endpoint listing Agreement objects"
+ required:
+ - id
+ - name
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ name:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+
+ ConsentRecordFilter:
+ type: object
+ description: "Query filter for API endpoint listing ConsentRecord objects"
+ required:
+ - id
+ - opt_in
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ opt_in:
+ type: boolean
+ format: ""
+ example: ""
+ description: ""
+
+
+ PolicyFilter:
+ type: object
+ description: "Query filter for API endpoint listing Policy objects"
+ required:
+ - id
+ - name
+ - revision
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ name:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ revision:
+ $ref: '#/components/schemas/Revision'
+
+
+ Controller:
+ type: object
+ description: "Details of a data controller."
+ required:
+ - id
+ - name
+ - url
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ name:
+ type: string
+ format: ""
+ example: ""
+ description: "Name of data controller (may be omitted if no data involved)"
+
+ url:
+ type: string
+ format: ""
+ example: ""
+ description: "URL of data controller (may be omitted if no data involved)"
+
+
+ Signature:
+ type: object
+ description: "A generic signature contains a cryptographic hash of some value, together with a signature created by some private key in another system. Required signing methods: Revision object or another Signature object."
+ required:
+ - id
+ - verification_method
+ - verification_hash
+ - verification_signature
+ - verification_artifact
+ - jws_header
+ - signed_by
+ - timestamp
+ - object_type
+ - object_reference
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ verification_method:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ verification_hash:
+ type: string
+ format: ""
+ example: ""
+ description: "Internally generated cryptographic hash of the value to be signed."
+
+ verification_signature:
+ type: string
+ format: ""
+ example: ""
+ description: "Signature of verification_hash"
+
+ verification_artifact:
+ type: string
+ format: ""
+ example: ""
+ description: "A verification artifact in the form of a scanned object, image, signature etc."
+
+ jws_header:
+ type: string
+ format: ""
+ example: ""
+ description: "Alternative to the verification_method, verification_hash and verification_signature, give a JWS serialized object (RFC7515)"
+
+ signed_by:
+ type: string
+ format: ""
+ example: ""
+ description: "Identifier information may change over time. This field could contain a natural individual's names, personal number, email addresses - store a snapshot that binds to the signature at the time of signing."
+
+ timestamp:
+ type: string
+ format: ""
+ example: ""
+ description: "Timestamp of signature"
+
+ object_type:
+ type: string
+ format: ""
+ example: ""
+ description: "signature/revision"
+
+ object_reference:
+ type: string
+ format: ""
+ example: ""
+ description: "A symmetric relation / back reference to the object_type that was signed. We are currently just modelling signing another signature (a chain) or signing a Revision (which can be a revision of an agreement, policy etc)"
+
+
+ AgreementPurpose:
+ type: object
+ description: "TBD: Models the purpose of an agreement"
+ required:
+ - id
+ - name
+ - description
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ name:
+ type: string
+ format: ""
+ example: ""
+ description: "Name of purpose"
+
+ description:
+ type: string
+ format: ""
+ example: ""
+ description: "Description of purpose"
+
+
+ AgreementLifecycle:
+ type: object
+ description: "TBD: Models the valid lifecycle states of an Agreement"
+ required:
+ - id
+ - name
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ name:
+ type: string
+ format: ""
+ example: ""
+ description: "Definition / Preparation / Capture / Use / Proof"
+
+
+ RegistryReference:
+ type: object
+ description: "TBD: When creating an Invidiual, we need some input that refers to a functional or foundational ID in an external system"
+ required:
+ - id
+ - foundational_id
+ - functional_id
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ foundational_id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ functional_id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+
+ AuditTracker:
+ type: object
+ description: "TBD: An external tracker receiving information from the system that can be subject to external auditing and verification of correct behavior. This is one of several notification/monitor/subscription patterns that may be more suitable for an encrypted Pub/Sub service."
+ required:
+ - id
+ - name
+ - public_key
+ - callback_agreement
+ - callback_consent_record
+ - callback_policy
+ - callback_revision_table_hash
+ - callback_signature_table_hash
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ name:
+ type: string
+ format: ""
+ example: ""
+ description: "Name of the auditing system"
+
+ public_key:
+ type: string
+ format: ""
+ example: ""
+ description: "The auditing system's public key for encrypting data sent to callback functions"
+
+ callback_agreement:
+ type: string
+ format: ""
+ example: ""
+ description: "A URL receiving a callback with the Agreement object + Revision + AuditEventType"
+
+ callback_consent_record:
+ type: string
+ format: ""
+ example: ""
+ description: "A URL receiving a callback with the ConsentRecord object + Revision + AuditEventType"
+
+ callback_policy:
+ type: string
+ format: ""
+ example: ""
+ description: "A URL receiving a callback with the Policy object + Revision + AuditEventType"
+
+ callback_revision_table_hash:
+ type: string
+ format: ""
+ example: ""
+ description: "A URL receiving a callback with + AuditEventType. Periodically, the system can publish the hash of the revision table."
+
+ callback_signature_table_hash:
+ type: string
+ format: ""
+ example: ""
+ description: "A URL receiving a callback with + AuditEventType. Periodically, the system can publish the hash of the signature table."
+
+
+ AuditEventType:
+ type: object
+ description: "TBD: Model for the possible events pertaining a change to an object subject to auditing. This model is not necessarily a database-backed model, but part of application code."
+ required:
+ - id
+ - event_name
+ properties:
+
+ id:
+ type: string
+ format: ""
+ example: ""
+ description: ""
+
+ event_name:
+ type: string
+ format: ""
+ example: ""
+ description: "What happened - create/update/delete"
+
+
+
+ securitySchemes:
+ OAuth2:
+ type: oauth2
+ flows:
+ authorizationCode:
+ authorizationUrl: https://example.com/oauth/authorize
+ tokenUrl: https://example.com/oauth/token
+ scopes:
+ read: Grants global read access
+ write: Grants global write access
+ org: Grants access to org operations
+ consumer: Grants access to data consumer operations
+ individual: Grants access to specific individual read/write operations
+ auditor: Grants access to specific auditor read operations
+
+security:
+ - OAuth2:
+ - read
\ No newline at end of file
diff --git a/api/govstack_csv_to_openapi.py b/api/govstack_csv_to_openapi.py
new file mode 100755
index 0000000..cfe6697
--- /dev/null
+++ b/api/govstack_csv_to_openapi.py
@@ -0,0 +1,404 @@
+#!/usr/bin/env python3
+from subprocess import Popen, PIPE
+import csv
+import os
+import re
+import shutil
+import sys
+
+
+if len(sys.argv) < 3:
+ print("USAGE: govstack_csv_to_openapi.py [--html-table]")
+ print("")
+ print("Tip: On Linux, pipe command to `xclip -selection clipboard` to direct outputs straight into X's clipboard and then paste it.")
+ print("")
+ print("")
+ print("Example of copying to text-only clipboard:")
+ print("./govstack_csv_to_openapi.py GovStack\ Consent\ BB\ API\ endpoints\ -\ endpoints.csv GovStack\ Consent\ BB\ API\ endpoints\ -\ schema.csv | xclip -selection clipboard")
+ print("")
+ print("")
+ print("Example of copying HTML table to html-only clipboard:")
+ print("./govstack_csv_to_openapi.py GovStack\ Consent\ BB\ API\ endpoints\ -\ endpoints.csv GovStack\ Consent\ BB\ API\ endpoints\ -\ schema.csv --html-table | xclip -selection clipboard -i -t text/html")
+ sys.exit(1)
+
+
+class SafeDict(dict):
+ """
+ https://stackoverflow.com/a/17215533/405682
+ """
+ def __missing__(self, key):
+ return '{' + key + '}'
+
+template = """openapi: 3.0.0
+servers:
+ # Added by API Auto Mocking Plugin
+ - description: SwaggerHub API Auto Mocking
+ url: https://app.swaggerhub.com/apis/GovStack/consent-management-bb/
+info:
+ description: This is a basic API for GovStack's Consent Management Building Block. It reflects the basic requirements of the Consent Management BB specification, which is versioned .
+ version: 0.9.0-rc1
+ title: Consent Management BB API
+ contact:
+ email: balder@overtag.dk
+ license:
+ name: Apache 2.0
+ url: 'http://www.apache.org/licenses/LICENSE-2.0.html'
+tags:
+ - name: org
+ description: Secured operations available to organization API integration
+ - name: dataconsumer
+ description: Secured operations for data consumers and applications to verify consent
+ - name: individual
+ description: Individual operations
+ - name: auditor
+ description: Operations for external auditing systems to query detailed data from the system and subscribe to notifications.
+ - name: notification
+ description: Subscribe/unsubscribe notifications for data processors, consumers and frontend systems for individuals.
+ - name: callback
+ description: Callback API for other Building Blocks, especially relevant for asynchronous processes.
+paths:
+{paths}
+
+components:
+ schemas:
+{schemas}
+
+ securitySchemes:
+ OAuth2:
+ type: oauth2
+ flows:
+ authorizationCode:
+ authorizationUrl: https://example.com/oauth/authorize
+ tokenUrl: https://example.com/oauth/token
+ scopes:
+ read: Grants global read access
+ write: Grants global write access
+ org: Grants access to org operations
+ consumer: Grants access to data consumer operations
+ individual: Grants access to specific individual read/write operations
+ auditor: Grants access to specific auditor read operations
+
+security:
+ - OAuth2:
+ - read
+"""
+
+path_spec_template = """
+ {method}:
+ tags:
+ - {tag}
+ summary: "{summary}"
+ operationId: "{operationId}"
+ description: "{description}"
+ parameters: {url_parameters}
+ x-specification-usecase: "{usecase}"
+ x-specification-scenario: "{scenario}"
+ x-specification-pii-or-sensitive: "{sensitive}"
+ responses:
+ '200':
+ description: "{responseOK}"
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: '#/components/schemas/Policy'
+ '400':
+ description: bad input parameter
+ security:
+ - OAuth2: [{security}]
+"""
+
+path_spec_template_post = path_spec_template + """
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/{request_parameter}'
+ description: Insert manually
+"""
+
+
+# See: https://swagger.io/docs/specification/describing-parameters/
+parameter_template = """
+ - in: {where}
+ name: "{name}"
+ description: "{description}"
+ required: {required}
+ schema:
+ type: {schema_type}
+"""
+
+# See: https://swagger.io/docs/specification/describing-parameters/
+parameter_template_schema = """
+ - in: {where}
+ name: {name}
+ description: "{description}"
+ required: {required}
+ schema:
+ $ref: '#/components/schemas/{schema_model}'
+"""
+
+schema_template = """
+ {schema}:
+ type: {schema_type}
+ description: "{description}"
+ required:
+{required}
+ properties:
+{properties}
+"""
+
+schema_property_template = """
+ {name}:
+ type: {property_type}
+ format: "{format}"
+ example: "{example}"
+ description: "{description}"
+"""
+
+schema_property_fk_template = """
+ {name}:
+ $ref: '#/components/schemas/{fk_model}'
+"""
+
+
+# This table is copy-paste friendly for a Google Doc
+html_table_template = """
+
+
+
+| Model |
+Description |
+Fields |
+
+
+{rows}
+
+"""
+
+html_table_rows_template = """
+
+ | {model_name} |
+ {model_description} |
+ {model_fields} |
+
+"""
+
+html_table_cols_template = """
+
+"""
+
+
+def get_api_spec_from_row(row, current_tag):
+
+ url = row[0]
+ method = row[1].lower()
+
+ description = row[6].replace("\n", "\\n").replace("\"", "\\\"")
+
+ # YAML quotation friendlyness: Use \n as newline characters
+ # See: https://stackoverflow.com/questions/3790454/how-do-i-break-a-string-in-yaml-over-multiple-lines
+ summary = row[8].replace("\n", "\\n").replace("\"", "\\\"") or description
+ parameters = ""
+
+ pattern_url_parameters = re.compile("{(\w+)}")
+
+ # Identifier of specification usecase
+ usecase = row[2].replace("\n", "\\n").replace("\"", "\\\"") or ""
+
+ # Identifier of specification scenario
+ scenario = row[3].replace("\n", "\\n").replace("\"", "\\\"") or ""
+
+ sensitive = row[7] == "TRUE"
+
+ operation_id = row[9]
+ response_ok = row[10]
+ security = row[11]
+
+ for parameter in pattern_url_parameters.findall(url):
+ parameters += parameter_template.format(
+ where="path",
+ name=parameter,
+ required="true",
+ schema_type="string",
+ description="Unique ID of an object",
+ )
+
+ for query_parameter in filter(lambda x: bool(x), row[4].split(", ")):
+ parameters += parameter_template_schema.format(
+ where="query",
+ name=query_parameter,
+ required="true",
+ schema_model=query_parameter,
+ description="An object of type {}".format(query_parameter),
+ )
+
+ if "List" in operation_id:
+ parameters += parameter_template.format(
+ where="query",
+ name="offset",
+ required="false",
+ description="Requested index for start of resources to be provided in response requested by client",
+ schema_type="integer",
+ )
+ parameters += parameter_template.format(
+ where="query",
+ name="limit",
+ required="false",
+ description="Requested number of resources to be provided in response requested by client",
+ schema_type="integer",
+ )
+
+
+ return {
+ "url": url,
+ "tag": current_tag,
+ "method": method,
+ "summary": summary,
+ "operationId": operation_id,
+ "description": description,
+ "url_parameters": parameters or "[]",
+ "request_parameter": "",
+ "responseOK": response_ok,
+ "security": security,
+ "usecase": usecase,
+ "scenario": scenario,
+ "sensitive": sensitive,
+ }
+
+
+endpoint_csv_file = sys.argv[1]
+schema_csv_file = sys.argv[2]
+
+if not os.path.exists(endpoint_csv_file):
+ print("File not found: {}".format(endpoint_csv_file))
+
+if not os.path.exists(schema_csv_file):
+ print("File not found: {}".format(schema_csv_file))
+
+
+def is_row_with_api_url(row):
+ return "/" in row[0] and row[1]
+
+
+def is_row_with_api_tag(row):
+ return "API tag:" in row[0]
+
+def is_row_with_model_name(row):
+ return "Model:" in row[0]
+
+def is_row_with_schema_property(row):
+ return not is_row_with_model_name(row) and row[0] and not row[2]
+
+def is_row_with_schema_fk(row):
+ return not is_row_with_model_name(row) and row[0] and row[2]
+
+
+
+#####################################
+# PROCESS ENDPOINT CSV #
+#####################################
+
+path_specs = {}
+
+current_tag = None
+with open(endpoint_csv_file, newline='') as csvfile:
+ spamreader = csv.reader(csvfile, delimiter=',', quotechar='"')
+ for row in spamreader:
+ if is_row_with_api_tag(row):
+ current_tag = row[0].split(": ")[-1]
+ if is_row_with_api_url(row):
+
+ api_path = get_api_spec_from_row(row, current_tag)
+
+ path = path_spec_template.format(
+ **api_path
+ )
+ if not api_path["url"] in path_specs:
+ path_specs[api_path["url"]] = []
+ path_specs[api_path["url"]].append(path)
+
+paths_template = """
+ {url}:
+{path_spec}
+"""
+
+paths = {}
+
+for url, path_spec in path_specs.items():
+ if not url in paths:
+ paths[url] = ""
+ paths[url] += ("\n".join(path_spec))
+
+output_paths = ""
+for url, path_spec_rendered in paths.items():
+ output_paths += paths_template.format(url=url, path_spec=path_spec_rendered)
+
+
+#####################################
+# PROCESS SCHEMA CSV #
+#####################################
+models = {}
+
+current_model = None
+output_schemas = ""
+schema_fields = {}
+schema_field_names = {}
+schema_descriptions = {}
+
+with open(schema_csv_file, newline='') as csvfile:
+ spamreader = csv.reader(csvfile, delimiter=',', quotechar='"')
+ for row in spamreader:
+ if is_row_with_model_name(row):
+ current_model = row[0].split(": ")[-1]
+ schema_descriptions[current_model] = row[3].replace("\n", "\\n").replace("\"", "\\\"")
+
+ if current_model:
+ schema_fields.setdefault(current_model, "")
+ schema_field_names.setdefault(current_model, [])
+
+ if current_model and is_row_with_schema_property(row):
+ schema_field_names[current_model].append(row[0])
+ schema_fields[current_model] += schema_property_template.format(
+ name=row[0],
+ property_type=row[1],
+ format="",
+ example="",
+ description=row[3].replace("\n", "\\n").replace("\"", "\\\""),
+ )
+ elif current_model and is_row_with_schema_fk(row):
+ schema_field_names[current_model].append(row[0])
+ schema_fields[current_model] += schema_property_fk_template.format(
+ name=row[0],
+ fk_model=row[2],
+ )
+
+
+html_table_rows_output = ""
+
+for schema_name, properties in schema_fields.items():
+ output_schemas += schema_template.format(
+ schema=schema_name,
+ description=schema_descriptions[schema_name],
+ schema_type="object",
+ properties=properties,
+ required="\n".join(" - {}".format(name) for name in schema_field_names[schema_name])
+ )
+ html_table_rows_output += html_table_rows_template.format(
+ model_name="""{}""".format(schema_name),
+ model_description=schema_descriptions[schema_name].replace("\\n", "
"),
+ model_fields=", ".join("""{}""".format(x) for x in schema_field_names[schema_name])
+ )
+
+yaml_output = template.format(paths=output_paths, schemas=output_schemas)
+
+html_table_output = html_table_template.format(rows=html_table_rows_output)
+
+if len(sys.argv) > 3 and sys.argv[3].strip() == "--html-table":
+
+ print(html_table_output)
+
+else:
+ print(yaml_output)
+
diff --git a/examples/demo/Caddyfile b/examples/demo/Caddyfile
new file mode 100644
index 0000000..719a0e7
--- /dev/null
+++ b/examples/demo/Caddyfile
@@ -0,0 +1,33 @@
+{$SITE_ADDRESS}:80, {$SITE_ADDRESS}:443 {
+
+
+ @api {
+ path /api/*
+ }
+
+ route @api {
+ uri strip_prefix /api
+ reverse_proxy {
+ to consent:8000
+ }
+ openapi {
+ spec /consent-openapi.yaml
+ log_error
+ check {
+ req_params req_body
+ # When we are ready to handle validation of the body:
+ # req_params req_body resp_body
+ }
+ validate_servers
+ }
+ }
+
+
+ handle_errors {
+ respond @api "Resource: {http.request.orig_uri}. Error: {openapi.error}" {openapi.status_code} {
+ close
+ }
+ }
+
+ respond "all is OK"
+}
diff --git a/examples/demo/Dockerfile_app b/examples/demo/Dockerfile_app
new file mode 100644
index 0000000..b30d845
--- /dev/null
+++ b/examples/demo/Dockerfile_app
@@ -0,0 +1,14 @@
+FROM python:3
+
+# This is a demo app. It's okay to run pip as root inside a docker container
+ENV PIP_ROOT_USER_ACTION=ignore
+
+COPY examples/demo/djangoapp/requirements.txt /requirements.txt
+
+RUN python3 -m pip install pip --upgrade && pip install -r /requirements.txt
+
+ADD ./examples/demo/djangoapp/ /djangoapp
+
+WORKDIR "/djangoapp/"
+
+CMD ./entrypoint.sh
diff --git a/examples/demo/Dockerfile_caddy b/examples/demo/Dockerfile_caddy
new file mode 100644
index 0000000..eb8a1fb
--- /dev/null
+++ b/examples/demo/Dockerfile_caddy
@@ -0,0 +1,13 @@
+FROM caddy:2-builder AS builder
+
+RUN xcaddy build --with github.com/chukmunnlee/caddy-openapi
+
+FROM caddy:2-alpine
+
+COPY --from=builder /usr/bin/caddy /usr/bin/caddy
+
+COPY examples/demo/Caddyfile /etc/caddy/Caddyfile
+
+COPY api/consent-openapi.yaml /consent-openapi.yaml
+
+CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile"]
diff --git a/examples/demo/README.md b/examples/demo/README.md
new file mode 100644
index 0000000..178743c
--- /dev/null
+++ b/examples/demo/README.md
@@ -0,0 +1,20 @@
+# GovStack Consent BB - demo
+A stand-alone docker-compose configuration simulating the Consent BB specification.
+
+## Running the demo
+
+The demo can be run on a local Docker environment using the following command:
+
+```
+docker-compose up
+```
+
+After this, you can visit for instance https://localhost:8888/api/org/policy/ -- notice that Caddy produces a self-signed SSL certificate that you have to accept.
+
+## Components of the demo
+
+* An HTTP server (Caddy)
+* The Consent BB OpenAPI spec
+* A Caddy module for validating OpenAPI specs (caddy-openapi)
+* Mocked static responses for static endpoints
+* A demo application written in Django for dynamic endpoints
diff --git a/api/swagger.json b/examples/demo/djangoapp/consentbb/__init__.py
similarity index 100%
rename from api/swagger.json
rename to examples/demo/djangoapp/consentbb/__init__.py
diff --git a/api/swagger.yaml b/examples/demo/djangoapp/consentbb/app/__init__.py
similarity index 100%
rename from api/swagger.yaml
rename to examples/demo/djangoapp/consentbb/app/__init__.py
diff --git a/examples/demo/djangoapp/consentbb/app/admin.py b/examples/demo/djangoapp/consentbb/app/admin.py
new file mode 100644
index 0000000..8c38f3f
--- /dev/null
+++ b/examples/demo/djangoapp/consentbb/app/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/examples/demo/djangoapp/consentbb/app/apps.py b/examples/demo/djangoapp/consentbb/app/apps.py
new file mode 100644
index 0000000..6794d37
--- /dev/null
+++ b/examples/demo/djangoapp/consentbb/app/apps.py
@@ -0,0 +1,7 @@
+from django.apps import AppConfig
+
+
+class AppConfig(AppConfig):
+ default_auto_field = 'django.db.models.BigAutoField'
+ name = 'consentbb.app'
+ label = 'app'
diff --git a/examples/demo/djangoapp/consentbb/app/migrations/__init__.py b/examples/demo/djangoapp/consentbb/app/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/examples/demo/djangoapp/consentbb/app/models.py b/examples/demo/djangoapp/consentbb/app/models.py
new file mode 100644
index 0000000..71a8362
--- /dev/null
+++ b/examples/demo/djangoapp/consentbb/app/models.py
@@ -0,0 +1,3 @@
+from django.db import models
+
+# Create your models here.
diff --git a/examples/demo/djangoapp/consentbb/app/tests.py b/examples/demo/djangoapp/consentbb/app/tests.py
new file mode 100644
index 0000000..7ce503c
--- /dev/null
+++ b/examples/demo/djangoapp/consentbb/app/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/examples/demo/djangoapp/consentbb/app/views.py b/examples/demo/djangoapp/consentbb/app/views.py
new file mode 100644
index 0000000..91ea44a
--- /dev/null
+++ b/examples/demo/djangoapp/consentbb/app/views.py
@@ -0,0 +1,3 @@
+from django.shortcuts import render
+
+# Create your views here.
diff --git a/examples/demo/djangoapp/consentbb/asgi.py b/examples/demo/djangoapp/consentbb/asgi.py
new file mode 100644
index 0000000..fe9f04d
--- /dev/null
+++ b/examples/demo/djangoapp/consentbb/asgi.py
@@ -0,0 +1,16 @@
+"""
+ASGI config for consentapp project.
+
+It exposes the ASGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.0/howto/deployment/asgi/
+"""
+
+import os
+
+from django.core.asgi import get_asgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'consentapp.settings')
+
+application = get_asgi_application()
diff --git a/examples/demo/djangoapp/consentbb/settings.py b/examples/demo/djangoapp/consentbb/settings.py
new file mode 100644
index 0000000..7d962d7
--- /dev/null
+++ b/examples/demo/djangoapp/consentbb/settings.py
@@ -0,0 +1,124 @@
+"""
+Django settings for consentbb project.
+
+Generated by 'django-admin startproject' using Django 4.0.5.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.0/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/4.0/ref/settings/
+"""
+
+from pathlib import Path
+
+# Build paths inside the project like this: BASE_DIR / 'subdir'.
+BASE_DIR = Path(__file__).resolve().parent.parent
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/4.0/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'django-insecure-02@!!e3b$w_mzw^q90vhb1q#ke^%s$^njrgxxuma+0e%f0k)%w'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = [
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ 'consentbb.app',
+]
+
+MIDDLEWARE = [
+ 'django.middleware.security.SecurityMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.common.CommonMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'consentbb.urls'
+
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.request',
+ 'django.contrib.auth.context_processors.auth',
+ 'django.contrib.messages.context_processors.messages',
+ ],
+ },
+ },
+]
+
+WSGI_APPLICATION = 'consentbb.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/4.0/ref/settings/#databases
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': BASE_DIR / 'db.sqlite3',
+ }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/4.0/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+ {
+ 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+ },
+ {
+ 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+ },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/4.0/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/4.0/howto/static-files/
+
+STATIC_URL = 'static/'
+
+# Default primary key field type
+# https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field
+
+DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
diff --git a/examples/demo/djangoapp/consentbb/urls.py b/examples/demo/djangoapp/consentbb/urls.py
new file mode 100644
index 0000000..60467bb
--- /dev/null
+++ b/examples/demo/djangoapp/consentbb/urls.py
@@ -0,0 +1,21 @@
+"""consentapp URL Configuration
+
+The `urlpatterns` list routes URLs to views. For more information please see:
+ https://docs.djangoproject.com/en/4.0/topics/http/urls/
+Examples:
+Function views
+ 1. Add an import: from my_app import views
+ 2. Add a URL to urlpatterns: path('', views.home, name='home')
+Class-based views
+ 1. Add an import: from other_app.views import Home
+ 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
+Including another URLconf
+ 1. Import the include() function: from django.urls import include, path
+ 2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
+"""
+from django.contrib import admin
+from django.urls import path
+
+urlpatterns = [
+ path('admin/', admin.site.urls),
+]
diff --git a/examples/demo/djangoapp/consentbb/wsgi.py b/examples/demo/djangoapp/consentbb/wsgi.py
new file mode 100644
index 0000000..5737925
--- /dev/null
+++ b/examples/demo/djangoapp/consentbb/wsgi.py
@@ -0,0 +1,16 @@
+"""
+WSGI config for consentapp project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/4.0/howto/deployment/wsgi/
+"""
+
+import os
+
+from django.core.wsgi import get_wsgi_application
+
+os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'consentapp.settings')
+
+application = get_wsgi_application()
diff --git a/examples/demo/djangoapp/entrypoint.sh b/examples/demo/djangoapp/entrypoint.sh
new file mode 100755
index 0000000..035704b
--- /dev/null
+++ b/examples/demo/djangoapp/entrypoint.sh
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+# This is the entrypoint used by the docker container
+
+python manage.py runserver 0.0.0.0:8000
diff --git a/examples/demo/djangoapp/manage.py b/examples/demo/djangoapp/manage.py
new file mode 100755
index 0000000..7657608
--- /dev/null
+++ b/examples/demo/djangoapp/manage.py
@@ -0,0 +1,22 @@
+#!/usr/bin/env python
+"""Django's command-line utility for administrative tasks."""
+import os
+import sys
+
+
+def main():
+ """Run administrative tasks."""
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'consentbb.settings')
+ try:
+ from django.core.management import execute_from_command_line
+ except ImportError as exc:
+ raise ImportError(
+ "Couldn't import Django. Are you sure it's installed and "
+ "available on your PYTHONPATH environment variable? Did you "
+ "forget to activate a virtual environment?"
+ ) from exc
+ execute_from_command_line(sys.argv)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/examples/demo/djangoapp/requirements.txt b/examples/demo/djangoapp/requirements.txt
new file mode 100644
index 0000000..9d4986e
--- /dev/null
+++ b/examples/demo/djangoapp/requirements.txt
@@ -0,0 +1 @@
+django==4.0.5
diff --git a/examples/demo/docker-compose.yml b/examples/demo/docker-compose.yml
new file mode 100644
index 0000000..185a032
--- /dev/null
+++ b/examples/demo/docker-compose.yml
@@ -0,0 +1,34 @@
+version: "3"
+
+services:
+ consent:
+ image: consent_bb_demo_app
+ expose:
+ - 8000
+ networks:
+ - web
+ build:
+ context: ../../
+ dockerfile: examples/demo/Dockerfile_app
+
+ caddy:
+ image: consent_bb_demo_http
+ ports:
+ - "8080:80"
+ - "8888:443"
+ environment:
+ - SITE_ADDRESS=localhost
+ volumes:
+ - caddy:/data
+ networks:
+ - web
+ build:
+ context: ../../
+ dockerfile: examples/demo/Dockerfile_caddy
+
+volumes:
+ caddy:
+
+networks:
+ web:
+ driver: bridge
diff --git a/examples/someApp/.env.example b/examples/someApp/.env.example
deleted file mode 100644
index 8330c1e..0000000
--- a/examples/someApp/.env.example
+++ /dev/null
@@ -1 +0,0 @@
-# some applications use an env file for config
diff --git a/examples/someApp/.gitignore b/examples/someApp/.gitignore
deleted file mode 100644
index efe6d35..0000000
--- a/examples/someApp/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-# Make sure to add data directories to the ignore
\ No newline at end of file
diff --git a/examples/someApp/Caddyfile b/examples/someApp/Caddyfile
deleted file mode 100644
index 96dc0d3..0000000
--- a/examples/someApp/Caddyfile
+++ /dev/null
@@ -1,46 +0,0 @@
-# This Caddyfile configures an Adaptor to make someApp's API GovStack compliant.
-
-localhost
-reverse_proxy someApp:5678
-
-# This example is for a worfklow engine
-# Workflow API Spec: https://app.swaggerhub.com/apis-docs/GovStack/Workflow-BB/1.0.0#/developers
-
-@list_processes {
- path /processes
-}
-
-@detail_process {
- path /processes/*
- path_regexp static \/processes\/(\w+)
-}
-
-@start_process {
- path /processes/*/start
- path_regexp static \/processes\/(\w+)
-}
-
-@list_instances {
- path /instances
-}
-
-@detail_instance {
- path /instances/*
- path_regexp static \/instances\/(\w+)
-}
-
-rewrite @list_processes /rest/workflows
-rewrite @detail_process /rest/workflows/{re.static.1}
-rewrite @start_process /webhook-test/{re.static.1}
-rewrite @list_instances /rest/executions
-rewrite @detail_instance /rest/executions/{re.static.1}
-
-# Mock responses
-# respond /rest/workflows "Here's a list of processes served from '{path}'"
-# respond /rest/workflows/{re.static.1} "Here's a single process being served from '{path}'"
-# respond /webhook-test/{re.static.1} "You've started a process instance from '{path}'"
-# respond /rest/executions "Here's a list of instances served from '{path}'"
-# respond /rest/executions/{re.static.1} "Here's a single instance being served from '{path}'"
-
-# Catch all
-respond / "Nothing matched."
\ No newline at end of file
diff --git a/examples/someApp/Dockerfile b/examples/someApp/Dockerfile
deleted file mode 100644
index 4fda5ba..0000000
--- a/examples/someApp/Dockerfile
+++ /dev/null
@@ -1,4 +0,0 @@
-FROM caddy:latest
-
-# Configure Caddy in the image build, so we don't rely on persistent volumes.
-COPY Caddyfile /etc/caddy/Caddyfile
\ No newline at end of file
diff --git a/examples/someApp/docker-compose.yaml b/examples/someApp/docker-compose.yaml
deleted file mode 100644
index 3cde5ed..0000000
--- a/examples/someApp/docker-compose.yaml
+++ /dev/null
@@ -1,25 +0,0 @@
-version: '3.7'
-
-services:
- someApp:
- image: someOrg/someApp
- restart: always
- ports:
- - '127.0.0.1:5678:5678'
- environment:
- - SOME_ENV=som_evalue
- - NODE_ENV=production
- - WEBHOOK_URL=https://127.0.0.1:5678/
- - GENERIC_TIMEZONE=${GENERIC_TIMEZONE}
- volumes:
- - ${SOMEAPP_DATA_FOLDER}:/home/node/.someApp
- - ${SOMEAPP_LOCAL_FILES}:/files
-
- caddy:
- build: .
- restart: unless-stopped
- ports:
- - '80:80'
- - '443:443'
- volumes:
- - ${CADDY_DATA_FOLDER}:/data
diff --git a/spec/diagrams/Consent Mangement BB Extended resource relationship model.drawio b/spec/diagrams/Consent Mangement BB Extended resource relationship model.drawio
new file mode 100644
index 0000000..e31d675
--- /dev/null
+++ b/spec/diagrams/Consent Mangement BB Extended resource relationship model.drawio
@@ -0,0 +1 @@
+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
\ No newline at end of file
diff --git a/spec/diagrams/Consent Mangement BB Extended resource relationship model.drawio.png b/spec/diagrams/Consent Mangement BB Extended resource relationship model.drawio.png
new file mode 100644
index 0000000..a7a02b7
Binary files /dev/null and b/spec/diagrams/Consent Mangement BB Extended resource relationship model.drawio.png differ
diff --git a/spec/diagrams/Consent Mangement BB Simplified resource relationship model.drawio b/spec/diagrams/Consent Mangement BB Simplified resource relationship model.drawio
new file mode 100644
index 0000000..59dc8d3
--- /dev/null
+++ b/spec/diagrams/Consent Mangement BB Simplified resource relationship model.drawio
@@ -0,0 +1 @@
+7Vptb6s2FP41kbYrrYIQ8vKxSdqu0qpV6512+9EFB7xrbGZMEu6vnw024JikSZu0abeqivCxMfZ5znPO8UvPmyXrGwbS+I6GEPf6TrjuefNevz8ZDcWvFBSVYOg4lSBiKKxEbiN4QD+gEupmOQphZjTklGKOUlMYUEJgwA0ZYIyuzGYLis2vpiCCluAhANiW/oVCHlfSse808l8himL9ZVfPLwG6sRJkMQjpyhDBNb+mhKsh3kOWAAIJFzV3gH2HrOdfxZzLmV72+tfifyFbX0SURhiCFGUXAU2EOMhEk+sFSBCWam51NFUdic95Vz1vxijl1VOynkEsodIwVGO63lJb64HJfvd44aZ4mmF/NV7Gtxwsf0y+PqZ//iJfkN0sAc6VgpVyeKE1zmhOQih7cXredBUjDh9SEMjalTAxIYt5gkXJFY8hyOKyrSxknNHvcEYxZWVXnlP+1TUaQNl2gTButZwMJ4O5mMfUnqaa+RIyDtctkZr2DaQJ5KwQTVSt5yl4lckLm6/Kq8aA+iMli1vGUzcEyiKiuu9G0eJB6foQvTv/Bb2banf7HWqfdKl9fCq1jy0lw1B4F1WkjMc0ogTgq0Y6NWFo2vxGaap0+DfkvFCuEuScmtAIBbLim3q/LDzKwoWvi/N1u3JeqNJWBDKaswDumKb2y4BFkO+yQuX1QsPl2ngyiAFHS9MDHx0c13sBOkHOlrXdvx6qNeLfGnBE6bFV0+AkC0UbtLOE1zs2vOrVe4rKmKidQN/kuedv0LcaqHprw0jqYbzCbixX+juLAEE/xKQo6fWHWChp+iRi7jCSTz+FgIMqQxHeEGPIft7heyX4gAXKZNw9XDHAKCLiORDAiki/6XS9Tgc9cUZD/zhu138+2tVJUdvtDk7ldXXq+F5ut6Hio8HEbl4aHuXlJO2/F0lfl5dYXLqnGAXFdhalZf3nYlDfOTsKDc4mNurnVpQ7o9jo7Um74VnRzrNoN6Mkq1aelxGDMIEqdn5WinmDd6fY6Gwo9rL087AwZywYX863wYfk2+CFKWPK6BKFcvvGoaxKIbM8OXkCuR9WByzMfd8gnzvuIJ/XQb6T7Ye4/scmn9t7o/jmf0i++RbfbkmIBJVygD9VWBuMNjLHLma9aVgb7kgt/oABZeGnAsAbnV1eMTwf1/aS1P1A13akvGK0p5/zz8rPjSyyXa0FDYj0coJtERK2vy3FWOQkkFVl29u5TjEWEnzQqvhgucZwj8MX1+8g5MkOAdyxhZKGQ8QkjUcLuKzIOEx0G/HNVrM3BOOQU51jADc2gRu8eyhzJx1pRI1SUp10f6JYZiHgvTcC9Rxs6sSupoTILxYoyk1HJz7XtNDCVAvuAeOZ9HgL8dPkJ3eAgEjtfSgPTiIZFaj8iWG1Amt/rOrhyyoG/IusBVL2pBrKXoUpVO/P6i6yFAZogQKpML3XIgcDSFi3SdUuqBNRgR9Rw4hhBo23Lmy/3lJAutVpCIPgpu2ZhkUokVlB+6xWiTJhvXI03txvSl/LvEAeMnfbuJzDApd3H2IUhpBYSYbheOQlh1OlaxsL0Q4LrwNB28LrM6fjm7i9F2ebeHv1oi1rJ/Q7bH+LuQcg5TmDWfsDggMyYc8q6xXIBrFUAZNGKNEr84Ucq0HJwy3NiJIHqB61sFPnIX/K4D+56BgXNR1Ke66/0uYPCAKYZSV9KmIIkAVrSsFTUSYqrPxGxgEJ5BvNMVu5R9JQSu+i/E+Xg+ky2FjdTDr40pVM1cQ6Pl/svbQtFj2d2nA/oCTF2ozuOiO4AntfhFtGIYFQ4V6MUpVVx7Je6h0FAF+qOJ8IcMvV1+487IT4DiYmvp3+sOvKzOkuKtlbNxZCkISX8maf1BgGWSZCqYGDyZX9zlefXdC1NNJl8Fr2yrsNo+FGCqYXD7qLaiFr3W2wO3Ke6ejElyT69j6Q0P9lAkhxRPdqEWcrxbr87A6fegRubSLQ5TuHHZZ0Os/5MQ+ctkLx/JUIZYPP30t7q91rUWwu4FZUay5Ne1f/Ag==
\ No newline at end of file
diff --git a/spec/diagrams/Consent Mangement BB Simplified resource relationship model.drawio.png b/spec/diagrams/Consent Mangement BB Simplified resource relationship model.drawio.png
new file mode 100644
index 0000000..142ab3d
Binary files /dev/null and b/spec/diagrams/Consent Mangement BB Simplified resource relationship model.drawio.png differ
diff --git a/spec/diagrams/graph-data-resource-model-simplified.mermaid b/spec/diagrams/graph-data-resource-model-simplified.mermaid
new file mode 100644
index 0000000..6861cbd
--- /dev/null
+++ b/spec/diagrams/graph-data-resource-model-simplified.mermaid
@@ -0,0 +1,19 @@
+graph BT
+
+ subgraph Individual's Consent Choices
+ consentRecord(Consent Record)
+ individual(Individual) --> consentRecord
+ end
+
+ individual -.- registration(Registration
Functional ID or
Foundational ID)
+
+ subgraph Configuration
+ agreement(Consent Agreement) --> consentRecord
+ policy --> agreement
+ end
+
+ org --> policy(Data Policy)
+
+ consumer(Organization
Consumer) -..- agreement
+ consumer -..- consentRecord
+ org(Organization
Provider or Controller) --> agreement
diff --git a/spec/diagrams/sequence-information-mediator.mermaid b/spec/diagrams/sequence-information-mediator.mermaid
new file mode 100644
index 0000000..7ffcd7a
--- /dev/null
+++ b/spec/diagrams/sequence-information-mediator.mermaid
@@ -0,0 +1,15 @@
+sequenceDiagram
+ Workflow BB->>Consent BB: Verifies that consent exists
+
+ Consent BB->>Workflow BB: Success
+
+ Workflow BB->>Information Mediator BB: Discover data service
+
+ Information Mediator BB->>Workflow BB: ExternalService URL
+
+ Workflow BB->>Information Mediator BB: Consume data*)
+
+ Information Mediator BB->>Workflow BB: Data from ExternalService
+
+
+ Note over Workflow BB: *) Consumes data which requires consent