commit a0754eb65b5860ccf4f6f2fb7a0111f14afa8314
parent 3f9de49643ea0150e847c452894140bb3fd12dd0
Author: srfsh <dev@srf.sh>
Date: Mon, 20 Jun 2022 15:32:51 +0300
docs: improve
Diffstat:
10 files changed, 2266 insertions(+), 119 deletions(-)
diff --git a/docs/HACKING.md b/docs/HACKING.md
@@ -1,46 +0,0 @@
-# Running a local instance
-
-Simple instructions to run a local instance using postgres DB inside Docker and local elixir 1.12
-
-
-Setup the DB
-```
-docker run -d -v /var/lib/postgres/data -p 5432:5432 --name db -e POSTGRES_PASSWORD=zenflows postgres:12-alpine
-```
-
-Install elixir
-```
-apt-get install -y erlang erlang-dev erlang-os-mon erlang-parsetools erlang-tools
-```
-
-Build Zenflows
-```
-mix deps.get
-mix compile
-```
-
-Setup the DB for tests
-```
-echo << EOF > conf/test.local.exs
-import Config
-
-config :zenflows, Zenflows.DB.Repo,
- username: "postgres",
- password: "zenflows"
-EOF
-
-./mann -t db.create
-./mann -t db.migrate
-```
-
-Run all tests
-```
-mix test
-```
-
-Clean the build
-```
-rm -rf ./deps
-rm -rf ./_build
-```
-
diff --git a/docs/configuration-guide.md b/docs/configuration-guide.md
@@ -0,0 +1,70 @@
+# Configuration Guide
+
+Zenflows is configured through basic POSIX-compliant shell scripts. When you
+run `mann env.setup`, it'll copy the example template, `conf/.example-env.sh`,
+to `conf/env.sh`. You can edit that file according to your needs. The
+available options are mentioned below.
+
+
+## All available options
+
+The options here might seem a bit much, but it is to allow flexibility. Please
+also see the [Required Options](#required-options).
+
+* `DB_HOST`: The hostname or IP address of the database host. The default is
+ `localhost`.
+* `DB_PORT`: The port number of the database host. The default is `5432`. It
+ must be an integer between `0` and `65535`, inclusive.
+* `DB_NAME`: The database name of the database host. The default is `zenflows`
+ if run in production mode; `zenflows_dev` in development mode; `zenflows_test`
+ in testing mode.
+* `DB_USER`: The name of the user/role of the database host.
+* `DB_PASS`: The passphrane of the user/role of the database host.
+* `DB_SOCK`: The Unix socket path of the database daemon.
+* `DB_URI`: The URI connection string. The syntax is
+ `scheme://user:pass@host:port/dbname?key0=val0&key1=val1&keyN=valN`, where:
+ 1. `scheme` is any valid scheme, such as `db`, `a`, `foo` or even `http`;
+ 2. `user` is the name of the user/role of teh database host.
+ 3. `pass` is the passphrane of the user/role of the database host.
+ 4. `host` is the hostname or IP address of the database host.
+ 5. `port` is the port number of the database host.
+ 6. `key0=val0`, `key1=val1`, and `keyN=valN` query strings are additional,
+ adapter-related options, such as `ssl=true` and `timeout=10000`. The list
+ of additional options can be viewed at the [PostgreSQL Adapter docs](
+ https://hexdocs.pm/ecto_sql/Ecto.Adapters.Postgres.html#module-connection-options).
+
+ This option should be used if extended configuration is desired (using the
+ options mention in the link above).
+
+* `ROOM_HOST`: The hostname or IP address of the Restroom instance.
+* `ROOM_PORT`: The port number of the Restroom instance. It must be an integer
+ between `0` and `65535`, inclusive.
+* `ROOM_SALT`: A 64-octect long, lowercase-base16-encoded string used for the
+ salt of the passphrase hashing function. Can be generated with `openssl rand
+ -hex 64`. It is automatically generated when you run `mann env.setup`
+
+
+## Required Options
+
+Some of the options on how to connect to the database and the Restroom intance
+are required, along with `ROOM_SALT` that is used for passhprase hashing.
+
+For the Restroom instance, you need the `ROOM_HOST` and `ROOM_PORT` options.
+
+About the database, there are only 2 things you need to setup: how to connect to
+the database host, and what credentials to use.
+
+To specify what credentials to use, you must set `DB_USER` and `DB_PASS`
+variables accordingly.
+
+To specify how to connect to the database host, you have 3 options:
+
+* Setting only `DB_HOST` and `DB_PORT`. This is the most masic one, and what
+ most people will use. You don't even need to set up any of these, as these
+ have the default values of `localhost` and `5432`.
+* Setting only `DB_SOCK`. This is to allow people to use Unix sockets.
+* Setting only `DB_URI`. This is to allow people to provide additional options.
+ It is basically setting `DB_HOST` and `DB_PORT` in the same variable, plus
+ additional options (that is, you can't use Unix sockets with this option).
+These options are mutually-exclusive and the order of precedence is `DB_URI` >
+`DB_SOCK` > `DB_HOST` and `DB_PORT`.
diff --git a/docs/dependency-management.md b/docs/dependency-management.md
@@ -0,0 +1,40 @@
+# Dependency Management
+
+The dependencies are put in version control in Zenflows. But elixir/mix doesn't
+like this approach because it puts generated files (such as erlex, absinthe) in
+the dependencies' directory, which makes it hard to track/differentiate source
+files and generated files.
+
+For that reason, the actual dependencies (the real source code) are stored and
+tracked in the `.deps/` directory instead of the `deps/` directory. Then, the
+`.deps/` directory is copied over to `deps/` directory when we want to use the
+dependencies in the project. Similarly, `deps/` is copied over to `.deps/`
+whenever we update or add a dependency (of course, `deps/` is cleaned first, in
+order to avoid generated files).
+
+But this approach needs some care when you want to update or add a dependency:
+you must first clean the `deps/` directory with `mann dep.clean`, then copy
+`.deps/` over to `deps/` with `mann dep.setup`, then use whatever mix command
+you want to add or update a dependency (to update, use `mann mix deps.update
+mydep`), then copy `deps/` over back to `.deps/`.
+
+Let's give some examples. Suppose you want to update `absinthe`. You do:
+
+1. `mann dep.clean`
+2. `mann dep.setup`
+3. `mann mix deps.update absinthe`
+4. `mann dep.copy`
+5. `git add .deps/`
+6. `git commit -m 'dep: update absinthe to x.y.z'`
+
+Now let's suppose you want to add a new dependency, `absinthe`, to your project.
+You do:
+
+1. `mann dep.clean`
+2. `mann dep.setup`
+3. edit `mix.exs` to add the dependency
+4. `mann dep.copy`
+5. `git add .deps/`
+6. `git commit -m 'dep: add absinthe x.y.z'`
+
+Similar process happens with dependency removal, but I think it is clear now.
diff --git a/docs/deps-licences b/docs/deps-licences
@@ -1,38 +0,0 @@
-# elixir and erlang/otp
-elixir * Apache-2.0
-erlang/otp * Apache-2.0
-
-# library deps (name, version, license, "dev" if used in development)
-absinthe 1.6.6 Expat
-absinthe_plug 1.5.8 Expat
-bunt 0.2.0 Expat dev
-connection 1.1.0 Apache-2.0
-cowboy 2.9.0 ISC
-cowboy_telemetry 0.4.0 Apache-2.0
-cowlib 2.11.0 ISC
-credo 1.6.1 Expat dev
-db_connection 2.4.1 Apache-2.0
-decimal 2.0.0 Apache-2.0
-dialyxir 1.1.0 Apache-2.0 dev
-ecto 3.7.1 Apache-2.0
-ecto_sql 3.7.1 Apache-2.0
-erlex 0.2.6 Apache-2.0 dev
-exsync 0.2.4 BSD-3 dev
-file_system 0.2.10 WTFPL dev
-jason 1.3.0 Apache-2.0
-mime 2.0.2 Apache-2.0
-nimble_parsec 1.2.0 Apache-2.0
-plug 1.12.1 Apache-2.0
-plug_cowboy 2.5.2 Apache-2.0
-plug_crypto 1.2.2 Apache-2.0
-postgrex 0.15.13 Apache-2.0
-ranch 1.8.0 ISC
-telemetry 1.0.0 Apache-2.0
-
-
-# db
-postgres * psql
-
-# vf
-valueflows-gql * Apache-2.0
-valueflows-docs * CC BY-SA
diff --git a/docs/runtime-conf b/docs/runtime-conf
@@ -1,28 +0,0 @@
-When running in production, the following environment variables can be
-passed to Zenflows (all number ranges are inclusive):
-
- * DB_HOST: The hostname to connect to for the database. The default
- is `localhost'.
- * DB_PORT: The port number of the database. The default is 5432.
- It must be an integer between 0 and 65535.
- * DB_NAME: The name of the database in PostgreSQL. The default is
- `zenflows'.
- * DB_USER: The username of the PostgreSQL user/role to connect as.
- It is required if DB_SOCK is not provided.
- * DB_PASS: The passphrase of the PostgreSQL user/role to connect as.
- It is required if DB_SOCK is not provided.
- * DB_SOCK: The path to the Unix socket of PostgreSQL. It takes
- presence over DB_HOST, DB_PORT, DB_USER, and DB_PASS.
-
- * PASS_ITER: Iteration count for the hashing. The default is
- 160000. It must be an integer between 1024 and 1073741823.
- * PASS_KLEN: The length in octets for the derived key. The default is
- 64. It must be an integer between 1 and 4294967295.
- * PASS_SLEN: The length in octets for the randomly-generated salt.
- The default is 16. It must be an integer between 16 and 255.
-
-You can put these in a file, for example, called `env' and do:
-
- env $(cat env) zenflows start
-
-to start the application easily with your configuration.
diff --git a/docs/software-licences.md b/docs/software-licences.md
@@ -0,0 +1,66 @@
+# Software Licenses
+
+The list of software licenses used by Zenflows. You can view the license
+details of Zenflows in [the license file](docs/LICENSE).
+
+
+## Elixir and Erlang/OTP distribution
+
+| Name | License |
+|------------|-----------------------|
+| elixir | [Apache-2.0][apache2] |
+| erlang/otp | [Apache-2.0][apache2] |
+
+
+## Library Dependencies
+
+| Name | License | Only in Development? |
+|------------------|-----------------------|----------------------|
+| absinthe | [Expat][expat] | |
+| absinthe_plug | [Expat][expat] | |
+| bunt | [Expat][expat] | Yes |
+| connection | [Apache-2.0][apache2] | |
+| cowboy | [ISC][isc] | |
+| cowboy_telemetry | [Apache-2.0][apache2] | |
+| cowlib | [ISC][isc] | |
+| credo | [Expat][expat] | Yes |
+| db_connection | [Apache-2.0][apache2] | |
+| decimal | [Apache-2.0][apache2] | |
+| dialyxir | [Apache-2.0][apache2] | Yes |
+| ecto | [Apache-2.0][apache2] | |
+| ecto_sql | [Apache-2.0][apache2] | |
+| erlex | [Apache-2.0][apache2] | |
+| exsync | [BSD-3][bsd3] | Yes |
+| file_system | [WTFPL][wtfpl] | Yes |
+| jason | [Apache-2.0][apache2] | |
+| mime | [Apache-2.0][apache2] | |
+| nimble_parsec | [Apache-2.0][apache2] | |
+| plug | [Apache-2.0][apache2] | |
+| plug_cowboy | [Apache-2.0][apache2] | |
+| plug_crypto | [Apache-2.0][apache2] | |
+| postgrex | [Apache-2.0][apache2] | |
+| ranch | [ISC][isc] | |
+| telemetry | [Apache-2.0][apache2] | |
+
+
+## Database
+
+| Name | License |
+|----------|----------------------------|
+| postgres | [postgresql license][psql] |
+
+
+## Valueflows
+
+| Name | License |
+|----------------|-----------------------|
+|valueflows-docs | [CC BY-SA][ccbysa] |
+|valueflows-gql | [Apache-2.0][apache2] |
+
+[apache2]: https://www.gnu.org/licenses/license-list.en.html#apache2
+[expat]: https://www.gnu.org/licenses/license-list.en.html#Expat
+[isc]: https://www.gnu.org/licenses/license-list.en.html#ModifiedBSD
+[bsd3]: https://www.gnu.org/licenses/license-list.en.html#ModifiedBSD
+[wtfpl]: https://www.gnu.org/licenses/license-list.en.html#WTFPL
+[psql]: https://www.postgresql.org/about/licence/
+[ccbysa]: https://www.gnu.org/licenses/license-list.en.html#ccbysa
diff --git a/docs/style-guide b/docs/style-guide
@@ -1,4 +0,0 @@
-* Use tabs for indentation, spaces for aligment.
-* Don't indent the top-level code in modules.
-* Use trailing commas in multi-line lists, maps, functions, etc. where
- possible.
diff --git a/docs/style-guide.md b/docs/style-guide.md
@@ -0,0 +1,51 @@
+# Style Guide
+
+Having a style guide is great for having consistency.
+
+
+## Elixir
+
+For Elixir (`.ex`) or Elixir script files (`.exs`), follow these guide lines:
+
+* Keep line lengths at about 80 lines, not a hard rule.
+* Use Unix line endings and make sure you have a <newline> character at the end
+ of the file (any decent editor will already do that).
+* Use tabs for indentation, spaces for aligment.
+* Don't indent the top-level code in modules and avoid nesting modules.
+* Use trailing commas in multi-line lists, maps, functions, etc. wherever
+ possible.
+* Prefer exclicit `do ... end` syntax over `, do: ...` syntax.
+
+
+## Markdown
+
+For Markdown files (`.md`), follow these guide lines:
+
+* Keep lines lengths at most 80 lines (unless it is in a code block, then it is
+ not a hard rule).
+* Capitalize first letters of all the titles (except for words like and, or, of,
+ etc.)
+* Separate all titles from each other with two blank lines.
+* Separate a title from the immediate paragraph by a blank line.
+* Separate a list from the before and after paragraph by a blank line.
+* Separate a code block (not inline) from the before and after paragraph by a
+ blank line.
+* Aling the lines breaked from a list line like this:
+
+ ```
+ * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
+
+ 1. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
+ eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
+ minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex
+
+ 2. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
+ eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
+ minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex
+
+ * Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
+ tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
+ quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
+ ```
diff --git a/docs/vf-intro-gql-iface.md b/docs/vf-intro-gql-iface.md
@@ -0,0 +1,2009 @@
+# VF Intro
+
+This document tries to explain how to use Zenflows's implementaton of the
+Valueflows vocabulary. Please read about Valueflows documentation a bit to grasp
+some concepts such as *Processes*, *EconomicEvents*, *EconomicResources*, and
+*ResourceSpecifications* in order for this document to be more effective.
+
+
+## Ownership and Quanty Types of Resources
+
+There are two quantity types in Zenflows:
+
+* `accountingQuantity`
+* `onhandQuantity`
+
+Their meaning is defined by how they are used by the events. For example:
+
+* `produce` and `raise` events increase both quantities
+* `consume` and `lower` events decrease both quantities
+* `accept` events decrease `onhandQuantity`
+* `modify` events increase `onhandQuantity`
+* `transferAllRights` events decrease `accountingQuantity` of one resource, and
+ increase `accountingQuantity` of the other resource
+
+The ownership types specify who is the owner of the given quantity type. Those
+types are:
+
+* `primaryAccountable`: the owner of the quantity `accountingQuantity`
+* `custodian`: the current owner who has custody over the resource, amounted by
+ `onhandQuantity`
+
+
+## ResourceSpecification and ProcessSpecification
+
+In order to tell what a resource is, we use *ResourceSpecifications*. If two
+resources conform to the same ResourceSpecification, they would be of the same
+type. Each resource has a field named `conformsTo` that points to a
+ResourceSpecification. The field gets set by `resourceConformsTo` of `produce`
+and `raise` events.
+
+But sometimes ResourceSpecification is not enough to differentiate between other
+resources. Sometimes you need to, for example, differentiate between "clean",
+"used", "dirty", "donated" gown resources. You use ProcessSpecifications to
+differentiate between those. Each resource has a field named `stage` that could
+point to a ProcessSpecification. The field gets set by `modify` events.
+
+
+## Event Side-Effects and Enforcements
+
+In Zenflows, each event has its own requirements, enforcements, and possible
+side-effects. Even though the GraphQL types allow some fields optionally,
+depending on the action, the back-end enforces some fields required by the
+events.
+
+
+### Common Requirements and Enforcements
+
+Each event requires an Action. If no Action is provided, the back-end can't
+know which fields to enforce and which side-effects to create. The supported
+Actions are:
+
+* `produce`
+* `consume`
+* `use`
+* `work`
+* `cite`
+* `deliverService` (alias: `deliver-service`)
+* `pickup`
+* `dropoff`
+* `accept`
+* `modify`
+* `pack`
+* `unpack`
+* `transferCustody` (alias: `transfer-custody`)
+* `transferAllRights` (alias: `transfer-all-rights`)
+* `transfer`
+* `move`
+* `raise`
+* `lower`
+
+Each event requires a `provider` and a `receiver`. If any of them is not
+provided, the back-end will default to the currently logged-in agent. This
+might be changed in the future, however (the front-ends can default to currently
+logged-in agent by themselves). Also, at the moment, `provider` must be the
+same agent as the logged-in agent.
+
+Each event requires you to provide some sort of time-related data. These are
+provided by the fields `hasPointInTime`, `hasBeginning`, and `hasEnd`. The
+back-end allows only these mutually-exclusive combinations, and if none of these
+combinations are met, you'll not be able to create your event:
+
+* Only `hasPointInTime`
+* Only `hasBeginning`
+* Only `hasEnd`
+* Both `hasBeginning` and `hasEnd`
+
+Currently, there's no check regarding the date-time fields. For example,
+the back-end do not check if `hasBeginning` is older than `hasEnd`.
+
+The fields that take a reference (ID) to a record (such as
+`resourceInventoriedAs`, `resourceConformsTo`, `atLocation`, and `toLocation`)
+checks if the provided record exists. You can't create an event with invalid
+references.
+
+The quantity fields take only positive amounts at the moment.
+
+
+### Produce Events
+
+`produce` events are used for creating stuff. This does not only mean something
+like harvesting crops, making a wood toy; it can also mean separating a resource
+that have quantities of five pieces into five individual pieces (in that case,
+you'd `consume` the resource that have five pieces, and `produce` five individual
+pieces).
+
+Generally used with `consume`, `work`, `use`, and `cite` events together to
+create a meaningful scenario.
+
+There are two things a `produce` event can do:
+
+* creating a new resource
+* increasing quantities of an existing resource
+
+The back-end differentiates them by whether the event has
+`resourceInventoriedAs` field or not. If it has, it'll try to increase the
+quantities of the resource `resourceInventoriedAs`.
+
+Whether it creates a new resource or just increases the quantities of an existing
+resource, the events will require `outputOf`, `resourceConformsTo`, and
+`resourceQuantity` to be provided, and that the `provider` and `receiver` are
+the same agents.
+
+If it creates a new resource, it'll try to get the fields `name`, `note`,
+`trackingIdentifier`, `currentLocation`, and `stage` from
+`newInventoriedResource` and put them into the newly-created resource.
+
+If it increases the quantities of an existing resource, it'll just do it, but
+these requirements must be met first:
+
+* The `provider` and `receiver` must be the same agent as the
+ `primaryAccountable` and `custodian` of the resource `resourceInventoriedAs`.
+* The `resourceQuantity.hasUnit` of the event must be the same as
+ `accountingQuantity.hasUnit` and `onhandQuantity.hasUnit` of the resource
+ `resourceInventoriedAs`.
+* The `resourceConformsTo` must be same as `conformsTo` of the resource
+ `resourceInventoriedAs`
+* The `resourceInventoriedAs` can't be a container or packed resource.
+
+
+### Raise Events
+
+`raise` events are pretty much require and have the same side-effects as
+`produce` events, but they can't have `outputOf` (or `inputOf`).
+
+The semantic meaning of `raise`, hower is different than `produce`.
+
+
+### Consume Events
+
+`consume` events are used for... consuming stuff. This does not only mean
+something like consuming seeds to plant crops; it can also mean separating a
+resource that have quantities of five pieces into five individual pieces (in
+that case, you'd `consume` the resource that have five pieces, and `produce` five
+individual pieces).
+
+Generally used with `produce`, `work`, `use`, and `cite` events together to
+create a meaningful scenario.
+
+The events require `inputOf`, `resourceInventoriedAs`, and `resourceQuantity`
+to be provided, and that the `provider` and `receiver` are the same agents.
+
+It'll decrease the quantities of the resource `resourceInventoriedAs`, but these
+requirements must be met:
+
+* The `provider` and `receiver` must be the same agent as the
+ `primaryAccountable` and `custodian` of the resource `resourceInventoriedAs`.
+* The `resourceQuantity.hasUnit` of the event must be the same as
+ `accountingQuantity.hasUnit` and `onhandQuantity.hasUnit` of the resource
+ `resourceInventoriedAs`.
+* The `resourceInventoriedAs` can't be a container or packed resource.
+
+
+### Lower Events
+
+`lower` events are pretty much require and have the same side-effects as
+`consume` events, but they can't have `inputOf` (or `outputOf`).
+
+The semantic meaning of `lower`, hower is different than `consume`.
+
+
+### Use Events
+
+`use` events are used for... using stuff. The stuff you use are either an
+actual resource or its specification.
+
+Generally used with `produce`, `consume`, `work`, and `cite` events together to
+create a meaningful scenario.
+
+The events require `inputOf`, `effortQuantity`, and either
+`resourceInventoriedAs` or `resourceConformsTo` (they're mutally-exclusive).
+Optionally, you can also provide `resourceQuantity`.
+
+If you choose to have `resourceInventoriedAs`, these requirements must be met:
+
+* The `resourceQuantity.hasUnit` of the event must be the same as
+ `accountingQuantity.hasUnit` and `onhandQuantity.hasUnit` of the resource
+ `resourceInventoriedAs`
+* The `resourceInventoriedAs` can't be a container or packed resource.
+
+
+### Work Events
+
+`work` events are used for indicating labor power used in a process. This can
+be the "repairing" in a car repairing scenario, "kneading" in a making a pie
+scenario.
+
+Generally used with `produce`, `consume`, `use`, and `cite` events together to
+create a meaningful scenario.
+
+The events require `inputOf`, `effortQuantity`, and `resourceConformsTo`.
+
+
+### Cite Events
+
+`cite` events are used for indicating the usage of instructions, blueprints and
+the like. They are used resourced but not consumed (that is, decreasing
+quantities).
+
+Generally used with `produce`, `consume`, `use`, and `work` events together to
+create a meaningful scenario.
+
+The events require `inputOf`, and `resourceQuantity`, and `resourceConformsTo`
+or `resourceInventoriedAs` (they're mutually-exclusive).
+
+If you choose to have `resourceInventoriedAs`, these requirements must be met:
+
+* The `resourceQuantity.hasUnit` of the event must be the same as
+ `accountingQuantity.hasUnit` and `onhandQuantity.hasUnit` of the resource
+* The `resourceInventoriedAs` can't be a container or packed resource.
+
+
+### DeliverService Events
+
+`deliverService` events are used for indicating delivered services, such as
+transportation of apples, painting the walls of the house.
+
+The events require `inputOf` and/or `outputOf`, and
+`resourceConformsTo`. If both of `inputOf` and `outputOf` are provided, they
+must refer to different Processes.
+
+
+### Pickup and Dropoff Events
+
+`pickup` and `dropoff` events are used in pairs to transport resources from one
+location to another.
+
+`pickup` and `dropoff` events are paired through the resource
+`resourceInventoriedAs`. If they both refer to the same resource, they are
+paired. That's the definition of "pair" here.
+
+The `pickup` events require `inputOf`, `resourceQuantity`, and
+`resourceInventoriedAs`, and that the `provider` and `receiver` are the same
+agents.
+
+The `pickup` events also require that:
+
+* The `provider` is the same agent as the `custodian` of the resource
+ `resourceInventoriedAs`
+* The `resourceInventoriedAs` can't be a packed resource
+* The `resourceQuantity.hasUnit` of the event must be the same as
+ `onhandQuantity.hasUnit` of the resource `resourceInventoriedAs`
+* The `onhandQuantity.hasNumericalValue` of the resource is positive
+* The `resourceQuantity.hasNumericalValue` of the event must be the same as
+ `onhandQuantity.hasNumericalValue` of the resource `resourceInventoriedAs`
+* There is no other `pickup` event that refers to the same resource
+ `resourceInventoriedAs` in the same process
+
+The `dropoff` events requires `outputOf`, `resourceQuantity`, and
+`resourceInventoriedAs`, and that the `provider` and `receiver` are the same
+agents.
+
+The `dropoff` events also requires that:
+
+* There is exactly one `pickup` event referring to the same resource
+ `resourceInventoriedAs` in the same process. Due to this, most of the
+ `pickup` events requrimenst apply here out of the box
+* The `provider` is the same agent as the `provider` of the paired event
+* There is no other `dropoff` events that refer to the same resource
+ `resourceInventoriedAs` in the same process
+* The `resourceQuantity.hasUnit` of the event must be the same as
+ the paired `pickup` event's `resourceQuantity.hasUnit`
+
+If `toLocation` is provided, `dropoff` events will set the `currentLocation` of
+the resource `resourceInventoriedAs`. If the resource `resourceInventoriedAs`
+is a container, it'll also set the `currentLocation` of all the contained
+resources.
+
+I'm thinking to add another validation logic here: until the resource
+`resourceInventoriedAs` is `dropoff`'ed, any other event that are not in the
+same process won't be able to affect it (as in `consume`, `cite`, `use`,
+`transfer`, and so on).
+
+
+### Accept and Modify Events
+
+`accept` and `modify` events are used in pairs and have the follow
+functionalities:
+
+* set a resource's `stage` field
+* specify the container resource used for `pack` and `unpack`
+
+`accept` and `modify` events are paired through the resource
+`resourceInventoriedAs`. If they both refer to the same resource, they are
+paired. That's the definition of "pair" here.
+
+The `accept` events require `inputOf`, `resourceQuantity`, and
+`resourceInventoriedAs`, and that the `provider` and `receiver` are the same
+agents.
+
+The `accept` events also require that:
+
+* The `provider` is the same agent as the `custodian` of the resource
+ `resourceInventoriedAs`
+* The `resourceInventoriedAs` can't be a packed resource.
+* There is no other `accept` event that refers to the same resource
+ `resourceInventoriedAs` in the same process
+* The `resourceQuantity.hasUnit` of the event must be the same as
+ `onhandQuantity.hasUnit` of the resource `resourceInventoriedAs`
+* There is no `pack` or `unpack` events in the same process
+* If the resource `resourceInventoriedAs` is a contanier, the
+ `onhandQuantity.hasNumericalValue` of the resource is positive
+* If the resource `resourceInventoriedAs` is a container, the
+ `resourceQuantity.hasNumericalValue` of the event must be the same as
+ `onhandQuantity.hasNumericalValue` of the resource
+
+If these requirements above are met, the `onhandQuantity.hasNumericalValue` of
+the resource `resourceInventoriedAs` will be decreased by
+`resourceQuantity.hasNumericalValue` of the event.
+
+The `modify` events require `outputOf`, `resourceQuantity`, and
+`resourceInventoriedAs`, and that the `provider` and `receiver` are the same
+agents.
+
+The `modify` events also require that:
+
+* There is exactly one `accept` event referring to the same resource
+ `resourceInventoriedAs` in the same process. Due to this, most of the
+ `accept` events requrimenst apply here out of the box
+* The `provider` is the same agent as the `provider` of the paired event
+* The `resourceQuantity.hasUnit` of the event must be the same as
+ the paired `accept` event's `resourceQuantity.hasUnit`
+* There is no other `modify` events that refer to the same resource
+ `resourceInventoriedAs` in the same process
+* The `resourceQuantity.hasNumericalValue` of the event must be the same as
+ the paired `accept` event's `resourceQuantity.hasNumericalValue`
+
+If these requirements above are met, the `onhandQuantity.hasNumericalValue` of
+the resource `resourceInventoriedAs` will be increased by
+`resourceQuantity.hasNumericalValue` of the event, and the resource's `stage`
+will be set to the same ProcessesSpecification of the current Process (`basedOn`
+field of the Process). Note that this also includes the `null` value.
+
+
+### Pack and Unpack Events
+
+`pack` and `unpack` events are *not* used in pairs, even though it kinda sounds
+like that. `pack` events put a resource into a container resource, `unpack`
+events take them out.
+
+The `pack` events require `inputOf`, and `resourceInventoriedAs`, and that the
+`provider` and `receiver` are the same agents.
+
+The `pack` events also require that:
+
+* There's exactly one `accept` event in the same process. It requires it
+ beforehand so that the back-end can see what container is used with this
+* The `provider` is the same agent as the `custodian` of the resource
+ `resourceInventoriedAs`
+* The `resourceInventoriedAs` can't be an already-packed resource
+* There is no `unpack` events in the same process
+
+If these requirements above are met, the `containedIn` of the resource
+`resourceInventoriedAs` will be set to `resourceInventoriedAs` of the accept
+event in the process.
+
+The `unpack` events require `outputOf`, and `resourceInventoriedAs`, and that the
+`provider` and `receiver` are the same agents.
+
+The `unpack` events also require that:
+
+* There's exactly one `accept` event in the same process. It requires it
+ beforehand so that the back-end can see what container is used with this
+* The `provider` is the same agent as the `custodian` of the resource
+ `resourceInventoriedAs`
+* The resource `resourceInventoriedAs` is actually in the container provided by
+ the `accept` event
+* There is no `pack` events in the same process
+
+If these requirements above are met, the `containedIn` of the resource
+`resourceInventoriedAs` will be set to `null`.
+
+
+### TransferCustody Events
+
+`transferCustody` events transfer the custody ownership, that is, `custodian`
+and thus, it only affects `onhandQuantity`.
+
+There are two things a `transferCustody` event can do:
+
+* when only `resourceInventoriedAs` is provided, it'll create a new resource on
+ the other end
+* when both `resourceInventoriedAs` and `toResourceInventoriedAs` are provided,
+ it'll increase the `onhandQuantity` of `toResourceInventoriedAs` while
+ decreasing `resourceInventoriedAs`'s
+
+In any case, they require `resourceInventoriedAs`, `resourceQuantity` and,
+optionally if you want to "transfer into" another resource,
+`toResourceInventoriedAs`.
+
+If only `resourceInventoriedAs` is provided, you need to fulfill these
+requirements:
+
+* The `provider` is the same agent as the `custodian` of the resource
+ `resourceInventoriedAs`
+* The `resourceInventoriedAs` can't be a packed resource
+* The `resourceQuantity.hasUnit` of the event must be the same as
+ `onhandQuantity.hasUnit` of the resource `resourceInventoriedAs`
+* If the resource `resourceInventoriedAs` is a container, the
+ `onhandQuantity.hasNumericalValue` of the resource must be postitive
+* If the resource `resourceInventoriedAs` is a container,
+ `resourceQuantity.hasNumericalValue` of the event must be the same as
+ `onhandQuantity.hasNumericalValue` of the resource
+
+If these requirements above are met, it'll create a new resource that will:
+
+* have `onhandQuantity.hasUnit` and `onhandQuantity.hasNumericalValue` set from
+ `resourceQuantity` of the event
+* have `accountingQuantity.hasNumericalValue` set to `0` and
+ `accountingQuantity.hasUnit` set to `resourceQuantity.hasUnit` of the event
+* have `currentLocation` set to `toLocation` of the event, if it is available
+* have all the other fields copied from the resource `resourceInventoriedAs`,
+ except for `name`, `note`, `trackingIdentifier` if they are provided by
+ `newInventoriedResource` when creating the event
+
+It'll also decrease the `onhandQuantity.hasNumericalValue` of the resourece
+`resourceInventoriedAs` by `resourceQuantity.hasNumericalValue` of the event.
+And if the resource `resourceInventoriedAs` was a container, the packed resources'
+`containedIn` will be set to the newly created resource and `custodian` set to
+`receiver` of the event.
+
+If both `resourceInventoriedAs` and `toResourceInventoriedAs` are provided, you
+need to fulfill these requirements:
+
+* The `provider` is the same agent as the `custodian` of the resource
+ `resourceInventoriedAs`
+* The `resourceInventoriedAs` and `toResourceInventoriedAs` can't be a packed
+ resource
+* The `resourceQuantity.hasUnit` of the event must be the same as
+ `onhandQuantity.hasUnit` of the resource `resourceInventoriedAs` and
+ `toResourceInventoriedAs`
+* The `resourceInventoriedAs.conformsTo` and
+ `toResourceInventoriedAs.conformsTo` must bethe same
+* If the resource `resourceInventoriedAs` is a container, the
+ `onhandQuantity.hasNumericalValue` of the resource must be postitive
+* If the resource `resourceInventoriedAs` is a container,
+ `resourceQuantity.hasNumericalValue` of the event must be the same as
+ `onhandQuantity.hasNumericalValue` of the resource
+
+If these requirements above are met, it'll increase the
+`onhandQuantity.hasNumericalValue` of the resource `toResourceInventoriedAs`
+while decreasing `onhandQuantity.hasNumericalValue` of `resourceInventoriedAs`
+by `resourceQuantity.hasNumericalValue` of the event. And if the resource
+`resourceInventoriedAs` was a container, the packed resources' `containedIn`
+will be set to `toResourceInventoriedAs` and `custodian` set to `receiver` of
+the event.
+
+
+### TransferAllRights Events
+
+`transferAllRight` events transfer the accounting ownership, that is,
+`primaryAccountable` and thus, it only affects `accountingQuantity`.
+
+There are two things a `transferAllRight` event can do:
+
+* when only `resourceInventoriedAs` is provided, it'll create a new resource on
+ the other end
+* when both `resourceInventoriedAs` and `toResourceInventoriedAs` are provided,
+ it'll increase the `accountingQuantity` of `toResourceInventoriedAs` while
+ decreasing `resourceInventoriedAs`'s
+
+In any case, they require `resourceInventoriedAs`, `resourceQuantity` and,
+optionally if you want to "transfer into" another resource,
+`toResourceInventoriedAs`.
+
+If only `resourceInventoriedAs` is provided, you need to fulfill these
+requirements:
+
+* The `provider` is the same agent as the `primaryAccountable` of the resource
+ `resourceInventoriedAs`
+* The `resourceInventoriedAs` can't be a packed resource
+* The `resourceQuantity.hasUnit` of the event must be the same as
+ `accountingQuantity.hasUnit` of the resource `resourceInventoriedAs`
+* If the resource `resourceInventoriedAs` is a container, the
+ `accountingQuantity.hasNumericalValue` of the resource must be postitive
+* If the resource `resourceInventoriedAs` is a container,
+ `resourceQuantity.hasNumericalValue` of the event must be the same as
+ `accountingQuantity.hasNumericalValue` of the resource
+
+If these requirements above are met, it'll create a new resource that will:
+
+* have `accountingQuantity.hasUnit` and `accountingQuantity.hasNumericalValue`
+ set from `resourceQuantity` of the event
+* have `onhandQuantity.hasNumericalValue` set to `0` and
+ `onhandQuantity.hasUnit` set to `resourceQuantity.hasUnit` of the event
+* have all the other fields copied from the resource `resourceInventoriedAs`,
+ except for `name`, `note`, `trackingIdentifier` if they are provided by
+ `newInventoriedResource` when creating the event
+
+It'll also decrease the `accountingQuantity.hasNumericalValue` of the resourece
+`resourceInventoriedAs` by `resourceQuantity.hasNumericalValue` of the event.
+And if the resource `resourceInventoriedAs` was a container, the packed resources'
+`containedIn` will be set to the newly created resource and `primaryAccountable`
+set to `receiver` of the event.
+
+If both `resourceInventoriedAs` and `toResourceInventoriedAs` are provided, you
+need to fulfill these requirements:
+
+* The `provider` is the same agent as the `primaryAccountable` of the resource
+ `resourceInventoriedAs`
+* The `resourceInventoriedAs` and `toResourceInventoriedAs` can't be a packed
+ resource
+* The `resourceQuantity.hasUnit` of the event must be the same as
+ `accountingQuantity.hasUnit` of the resource `resourceInventoriedAs` and
+ `toResourceInventoriedAs`
+* The `resourceInventoriedAs.conformsTo` and
+ `toResourceInventoriedAs.conformsTo` must bethe same
+* If the resource `resourceInventoriedAs` is a container, the
+ `accountingQuantity.hasNumericalValue` of the resource must be postitive
+* If the resource `resourceInventoriedAs` is a container,
+ `resourceQuantity.hasNumericalValue` of the event must be the same as
+ `accountingQuantity.hasNumericalValue` of the resource
+
+If these requirements above are met, it'll increase the
+`accountingQuantity.hasNumericalValue` of the resource `toResourceInventoriedAs`
+while decreasing `accountingQuantity.hasNumericalValue` of
+`resourceInventoriedAs` by `resourceQuantity.hasNumericalValue` of the event.
+And if the resource `resourceInventoriedAs` was a container, the packed
+resources' `containedIn` will be set to `toResourceInventoriedAs` and
+`primaryAccountable` set to `receiver` of the event.
+
+
+### Transfer Events
+
+`transfer` events transfer the both types of ownership, that is,
+`primaryAccountable` and `custodian` and thus, it affects both
+`accountingQuantity` and `onhandQuantity`.
+
+There are two things a `transfer` event can do:
+
+* when only `resourceInventoriedAs` is provided, it'll create a new resource on
+ the other end
+* when both `resourceInventoriedAs` and `toResourceInventoriedAs` are provided,
+ it'll increase the `accountingQuantity` and `onhandQuantity` of
+ `toResourceInventoriedAs` while decreasing `resourceInventoriedAs`'s
+
+In any case, they require `resourceInventoriedAs`, `resourceQuantity` and,
+optionally if you want to "transfer into" another resource,
+`toResourceInventoriedAs`.
+
+If only `resourceInventoriedAs` is provided, you need to fulfill these
+requirements:
+
+* The `provider` is the same agent as the `primaryAccountable` and `custodian`
+ of the resource `resourceInventoriedAs`
+* The `resourceInventoriedAs` can't be a packed resource
+* The `resourceQuantity.hasUnit` of the event must be the same as
+ `accountingQuantity` and `onhandQuantity.hasUnit` of the resource
+ `resourceInventoriedAs`
+* If the resource `resourceInventoriedAs` is a container, the
+ `accountingQuantity.hasNumericalValue` and `onhandQuantity.hasNumericalValue`
+ of the resource must be postitive
+* If the resource `resourceInventoriedAs` is a container,
+ `resourceQuantity.hasNumericalValue` of the event must be the same as
+ `accountingQuantity.hasNumericalValue` and `onhandQuantity.hasNumericalValue`
+ of the resource
+
+If these requirements above are met, it'll create a new resource that will:
+
+* have `accountingQuantity.hasUnit`, `accountingQuantity.hasNumericalValue`,
+ `onhandQuantity.hasUnit`, and `onhandQuantity.hasNumericalValue` set from
+ `resourceQuantity` of the event
+* have all the other fields copied from the resource `resourceInventoriedAs`,
+ except for `name`, `note`, `trackingIdentifier` if they are provided by
+ `newInventoriedResource` when creating the event
+
+It'll also decrease the `accountingQuantity.hasNumericalValue` and
+`onhandQuantity.hasNumericalValue` of the resourece `resourceInventoriedAs` by
+`resourceQuantity.hasNumericalValue` of the event.
+And if the resource `resourceInventoriedAs` was a container, the packed resources'
+`containedIn` will be set to the newly created resource, and `primaryAccountable`
+and `custodian` set to `receiver` of the event.
+
+If both `resourceInventoriedAs` and `toResourceInventoriedAs` are provided, you
+need to fulfill these requirements:
+
+* The `provider` is the same agent as the `primaryAccountable` and `custodian`
+ of the resource `resourceInventoriedAs`
+* The `resourceInventoriedAs` and `toResourceInventoriedAs` can't be a packed
+ resource
+* The `resourceQuantity.hasUnit` of the event must be the same as
+ `accountingQuantity` and `onhandQuantity.hasUnit` of the resource
+ `resourceInventoriedAs` and `toResourceInventoriedAs`
+* The `resourceInventoriedAs.conformsTo` and
+ `toResourceInventoriedAs.conformsTo` must bethe same
+* If the resource `resourceInventoriedAs` is a container, the
+ `accountingQuantity.hasNumericalValue` and `onhandQuantity.hasNumericalValue`
+ of the resource must be postitive
+* If the resource `resourceInventoriedAs` is a container,
+ `resourceQuantity.hasNumericalValue` of the event must be the same as
+ `accountingQuantity.hasNumericalValue` and `onhandQuantity.hasNumericalValue`
+ of the resource
+
+If these requirements above are met, it'll increase the
+`accountingQuantity.hasNumericalValue` and `onhandQuantity.hasNumericalValue` of
+the resource `toResourceInventoriedAs` while decreasing
+`accountingQuantity.hasNumericalValue` and `onhandQuantity.hasNumericalValue` of
+`resourceInventoriedAs` by `resourceQuantity.hasNumericalValue` of the event.
+And if the resource `resourceInventoriedAs` was a container, the packed
+resources' `containedIn` will be set to `toResourceInventoriedAs`, and
+`primaryAccountable` and `custodian` set to `receiver` of the event.
+
+
+### Move Events
+
+`move` events are used for internal dividing and such. When companed to
+`transfer`, it is similar to what `produce` is to `raise` and what `consume` is
+to `lower`
+
+The only differenece between `move` and `transfer` in the back-end is that
+`move` requires both the `provider` and `receiver` be the same person.
+
+
+## Examples
+
+
+### Produce Examples
+Harvesting apples from a tree farm.
+
+Give:
+```
+mutation {
+ createEconomicEvent(
+ event: {
+ action: "produce"
+ provider: "01FWN12XX7TJX1AFF5KA4WPNN9" # bob
+ receiver: "01FWN12XX7TJX1AFF5KA4WPNN9" # bob
+ outputOf: "01FWN136SPDMKWWF23SWQZRM5F" # harvesting apples process
+ resourceConformsTo: "01FWN136Y4ZZ7K9F314HQ7MKRG" # apple
+ resourceQuantity: {
+ hasNumericalValue: 50
+ hasUnit: "01FWN136S5VPCCR3B3TGYDYEY9" # kilogram
+ }
+ atLocation: "01FWN136ZAPQ5ENBF3FZ79935D" # bob's farm
+ hasPointInTime: "2022-01-02T03:04:05Z"
+ }
+ newInventoriedResource: {
+ name: "bob's apples"
+ note: "bob's delish apples"
+ trackingIdentifier: "lot 123"
+ currentLocation: "01FWN136ZAPQ5ENBF3FZ79935D" # bob's farm
+ stage: "01FWN136X183DM43CTWXESNWAB" # fresh
+ }
+ ) {
+ economicEvent {
+ id
+ action {id}
+ provider {id}
+ receiver {id}
+ outputOf {id}
+ resourceConformsTo {id}
+ resourceQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ atLocation {id}
+ hasPointInTime
+ }
+ economicResource { # this is the newly-created resource
+ id
+ name
+ note
+ trackingIdentifier
+ stage {id}
+ currentLocation {id}
+ conformsTo {id}
+ primaryAccountable {id}
+ custodian {id}
+ accountingQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ onhandQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ }
+ }
+}
+```
+
+Get:
+```
+{
+ "data": {
+ "createEconomicEvent": {
+ "economicEvent": {
+ "id: "01FWN16MMRPWEWCWHGNNH9TCTK",
+ "action": {"id": "produce"},
+ "provider": {"id": "01FWN12XX7TJX1AFF5KA4WPNN9"}, # bob
+ "receiver": {"id": "01FWN12XX7TJX1AFF5KA4WPNN9"}, # bob
+ "outputOf": {"id": "01FWN136SPDMKWWF23SWQZRM5F"}, # harvesting apples process
+ "resourceConformsTo": {"id": "01FWN136Y4ZZ7K9F314HQ7MKRG"}, # apple
+ "resourceQuantity": {
+ "hasNumericalValue": 50,
+ "hasUnit": {"id": "01FWN136S5VPCCR3B3TGYDYEY9"} # kilogram
+ },
+ "atLocation": {"id": "01FWN136ZAPQ5ENBF3FZ79935D"}, # bob's farm
+ "hasPointInTime": "2022-01-02T03:04:05.000000Z"
+ },
+ "economicResource": {
+ "id": "01FWN16MMVVVWEWTMC6Z5PMCM0",
+ "name": "bob's apples",
+ "note": "bob's delish apples",
+ "trackingIdentifier": "lot 123",
+ "stage": {"id": "01FWN136X183DM43CTWXESNWAB"}, # fresh
+ "currentLocation": {"id": "01FWN136ZAPQ5ENBF3FZ79935D"}, # bob's farm
+ "conformsTo": {"id": "01FWN136Y4ZZ7K9F314HQ7MKRG"}, # apple
+ "primaryAccountable": {"id": "01FWN12XX7TJX1AFF5KA4WPNN9"}, # bob
+ "custodian": {"id": "01FWN12XX7TJX1AFF5KA4WPNN9"}, # bob
+ "accountingQuantity": {
+ "hasNumericalValue": 50,
+ "hasUnit": {"id": "01FWN136S5VPCCR3B3TGYDYEY9"} # kilogram
+ },
+ "onhandQuantity": {
+ "hasNumericalValue": 50,
+ "hasUnit": {"id": "01FWN136S5VPCCR3B3TGYDYEY9"} # kilogram
+ }
+ }
+ }
+ }
+}
+```
+
+Harvesting apples, but using the existing apple resource (created above).
+
+Give:
+```
+mutation {
+ createEconomicEvent(event: {
+ action: "produce"
+ provider: "01FWN12XX7TJX1AFF5KA4WPNN9" # bob
+ receiver: "01FWN12XX7TJX1AFF5KA4WPNN9" # bob
+ outputOf: "01FWN136SPDMKWWF23SWQZRM5F" # harvesting apples process
+ resourceConformsTo: "01FWN136Y4ZZ7K9F314HQ7MKRG" # apple
+ resourceQuantity: {
+ hasNumericalValue: 15
+ hasUnit: "01FWN136S5VPCCR3B3TGYDYEY9" # kilogram
+ }
+ resourceInventoriedAs: "01FWN16MMVVVWEWTMC6Z5PMCM0" # resource "bob's apples"
+ atLocation: "01FWN136ZAPQ5ENBF3FZ79935D" # bob's farm
+ hasPointInTime: "2022-01-02T03:04:05Z"
+ }) {
+ economicEvent {
+ id
+ action {id}
+ provider {id}
+ receiver {id}
+ outputOf {id}
+ resourceConformsTo {id}
+ resourceQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ resourceInventoriedAs { # this is the already-existing resource "bob's apples"
+ id
+ name
+ note
+ trackingIdentifier
+ stage {id}
+ currentLocation {id}
+ conformsTo {id}
+ primaryAccountable {id}
+ custodian {id}
+ accountingQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ onhandQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ }
+ atLocation {id}
+ hasPointInTime
+ }
+ }
+}
+```
+
+Get:
+```
+{
+ "data": {
+ "createEconomicEvent": {
+ "economicEvent": {
+ "id: "01FWN2Z7XNACJBT2K4TR9EM40W",
+ "action": {"id": "produce"},
+ "provider": {"id": "01FWN12XX7TJX1AFF5KA4WPNN9"}, # bob
+ "receiver": {"id": "01FWN12XX7TJX1AFF5KA4WPNN9"}, # bob
+ "outputOf": {"id": "01FWN136SPDMKWWF23SWQZRM5F"}, # harvesting apples process
+ "resourceConformsTo": {"id": "01FWN136Y4ZZ7K9F314HQ7MKRG"}, # apple
+ "resourceQuantity": {
+ "hasNumericalValue": 15,
+ "hasUnit": {"id": "01FWN136S5VPCCR3B3TGYDYEY9"} # kilogram
+ },
+ "atLocation": {"id": "01FWN136ZAPQ5ENBF3FZ79935D"}, # bob's farm
+ "hasPointInTime": "2022-01-02T03:04:05.000000Z"
+ },
+ "economicResource": {
+ "id": "01FWN16MMVVVWEWTMC6Z5PMCM0",
+ "name": "bob's apples",
+ "note": "bob's delish apples",
+ "trackingIdentifier": "lot 123",
+ "stage": {"id": "01FWN136X183DM43CTWXESNWAB"}, # fresh
+ "currentLocation": {"id": "01FWN136ZAPQ5ENBF3FZ79935D"}, # bob's farm
+ "conformsTo": {"id": "01FWN136Y4ZZ7K9F314HQ7MKRG"}, # apple
+ "primaryAccountable": {"id": "01FWN12XX7TJX1AFF5KA4WPNN9"}, # bob
+ "custodian": {"id": "01FWN12XX7TJX1AFF5KA4WPNN9"}, # bob
+ "accountingQuantity": {
+ "hasNumericalValue": 65,
+ "hasUnit": {"id": "01FWN136S5VPCCR3B3TGYDYEY9"} # kilogram
+ },
+ "onhandQuantity": {
+ "hasNumericalValue": 65,
+ "hasUnit": {"id": "01FWN136S5VPCCR3B3TGYDYEY9"} # kilogram
+ }
+ }
+ }
+ }
+}
+```
+
+
+### Raise Examples
+Suppose a person joined to the instance at a later time. But they already have
+some resources they want to import. You can use `raise` events for that.
+
+Give:
+```
+mutation {
+ createEconomicEvent(
+ event: {
+ action: "raise"
+ provider: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ receiver: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ resourceConformsTo: "01FWN136Y4ZZ7K9F314HQ7MKRG" # apple
+ resourceQuantity: {
+ hasNumericalValue: 30
+ hasUnit: "01FWN136S5VPCCR3B3TGYDYEY9" # kilogram
+ }
+ atLocation: "01FWN3VH3H8T4KHN8XC7FJ32V3" # alice's kitchen
+ hasPointInTime: "2022-01-02T03:04:05Z"
+ }
+ newInventoriedResource: {
+ name: "alice's apples"
+ note: "alice's delish apples"
+ trackingIdentifier: "lot 123"
+ currentLocation: "01FWN3VH3H8T4KHN8XC7FJ32V3" # alice's kitchen
+ stage: "01FWN136X183DM43CTWXESNWAB" # fresh
+ }
+ ) {
+ economicEvent {
+ id
+ action {id}
+ provider {id}
+ receiver {id}
+ resourceConformsTo {id}
+ resourceQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ atLocation {id}
+ hasPointInTime
+ }
+ economicResource { # this is the newly-created resource
+ id
+ name
+ note
+ trackingIdentifier
+ stage {id}
+ currentLocation {id}
+ conformsTo {id}
+ primaryAccountable {id}
+ custodian {id}
+ accountingQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ onhandQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ }
+ }
+}
+```
+
+Get:
+```
+{
+ "data": {
+ "createEconomicEvent": {
+ "economicEvent": {
+ "id: "01FWN3YAT32CGRFJG827XWTSWY",
+ "action": {"id": "raise"},
+ "provider": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "receiver": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "resourceConformsTo": {"id": "01FWN136Y4ZZ7K9F314HQ7MKRG"}, # apple
+ "resourceQuantity": {
+ "hasNumericalValue": 30,
+ "hasUnit": {"id": "01FWN136S5VPCCR3B3TGYDYEY9"} # kilogram
+ },
+ "atLocation": {"id": "01FWN3VH3H8T4KHN8XC7FJ32V3"}, # alice's kitchen
+ "hasPointInTime": "2022-01-02T03:04:05.000000Z"
+ },
+ "economicResource": {
+ "id": "01FWN3ZY2Z8ZJ071YXJ315KC2W",
+ "name": "alice's apples",
+ "note": "alice's delish apples",
+ "trackingIdentifier": "lot 123",
+ "stage": {"id": "01FWN136X183DM43CTWXESNWAB"}, # fresh
+ "currentLocation": {"id": "01FWN3VH3H8T4KHN8XC7FJ32V3"}, # alice's kitchen
+ "conformsTo": {"id": "01FWN136Y4ZZ7K9F314HQ7MKRG"}, # apple
+ "primaryAccountable": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "custodian": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "accountingQuantity": {
+ "hasNumericalValue": 30,
+ "hasUnit": {"id": "01FWN136S5VPCCR3B3TGYDYEY9"} # kilogram
+ },
+ "onhandQuantity": {
+ "hasNumericalValue": 30,
+ "hasUnit": {"id": "01FWN136S5VPCCR3B3TGYDYEY9"} # kilogram
+ }
+ }
+ }
+ }
+}
+```
+
+Found more apples? Add them to the stack!
+
+Give:
+```
+mutation {
+ createEconomicEvent(event: {
+ action: "raise"
+ provider: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ receiver: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ resourceConformsTo: "01FWN136Y4ZZ7K9F314HQ7MKRG" # apple
+ resourceQuantity: {
+ hasNumericalValue: 15
+ hasUnit: "01FWN136S5VPCCR3B3TGYDYEY9" # kilogram
+ }
+ resourceInventoriedAs: "01FWN3ZY2Z8ZJ071YXJ315KC2W" # resource "alice's apples"
+ atLocation: "01FWN3VH3H8T4KHN8XC7FJ32V3" # alice's kitchen
+ hasPointInTime: "2022-01-02T03:04:05Z"
+ }) {
+ economicEvent {
+ id
+ action {id}
+ provider {id}
+ receiver {id}
+ resourceConformsTo {id}
+ resourceQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ resourceInventoriedAs { # this is the already-existing resource "bob's apples"
+ id
+ name
+ note
+ trackingIdentifier
+ stage {id}
+ currentLocation {id}
+ conformsTo {id}
+ primaryAccountable {id}
+ custodian {id}
+ accountingQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ onhandQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ }
+ atLocation {id}
+ hasPointInTime
+ }
+ }
+}
+```
+
+Get:
+```
+{
+ "data": {
+ "createEconomicEvent": {
+ "economicEvent": {
+ "id: "01FWN3ZY2Z8ZJ071YXJ315KC2W",
+ "action": {"id": "raise"},
+ "provider": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "receiver": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "resourceConformsTo": {"id": "01FWN136Y4ZZ7K9F314HQ7MKRG"}, # apple
+ "resourceQuantity": {
+ "hasNumericalValue": 15,
+ "hasUnit": {"id": "01FWN136S5VPCCR3B3TGYDYEY9"} # kilogram
+ },
+ "resourceInventoriedAs": {
+ "id": "01FWN3ZY2Z8ZJ071YXJ315KC2W",
+ "name": "alice's apples",
+ "note": "alice's delish apples",
+ "trackingIdentifier": "lot 123",
+ "stage": {"id": "01FWN136X183DM43CTWXESNWAB"}, # fresh
+ "currentLocation": {"id": "01FWN3VH3H8T4KHN8XC7FJ32V3"}, # alice's kitchen
+ "conformsTo": {"id": "01FWN136Y4ZZ7K9F314HQ7MKRG"}, # apple
+ "primaryAccountable": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "custodian": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "accountingQuantity": {
+ "hasNumericalValue": 45,
+ "hasUnit": {"id": "01FW15136S5VPCCR3B3TGYDYEY9"} # kilogram
+ },
+ "onhandQuantity": {
+ "hasNumericalValue": 45,
+ "hasUnit": {"id": "01FWN136S5VPCCR3B3TGYDYEY9"} # kilogram
+ }
+ },
+ "atLocation": {"id": "01FWN3VH3H8T4KHN8XC7FJ32V3"}, # alice's kitchen
+ "hasPointInTime": "2022-01-02T03:04:05.000000Z"
+ }
+ }
+ }
+}
+```
+
+
+### Consume Examples
+
+Consume apples for making apple juice.
+
+Give:
+```
+mutation {
+ createEconomicEvent(event: {
+ action: "consume"
+ provider: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ receiver: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ inputOf: "01FWN5SVCHH662KD10E73M221J" # process "making apple juice"
+ resourceInventoriedAs: "01FWN3ZY2Z8ZJ071YXJ315KC2W" # resource "alice's apples" 45kg
+ resourceQuantity: {
+ hasNumericalValue: 20
+ hasUnit: "01FWN136S5VPCCR3B3TGYDYEY9" # kilogram
+ }
+ atLocation: "01FWN3VH3H8T4KHN8XC7FJ32V3" # alice's kitchen
+ hasPointInTime: "2022-01-02T03:04:05Z"
+ }) {
+ economicEvent {
+ id
+ action {id}
+ provider {id}
+ receiver {id}
+ inputOf {id}
+ resourceInventoriedAs {
+ id
+ name
+ note
+ trackingIdentifier
+ stage {id}
+ currentLocation {id}
+ conformsTo {id}
+ primaryAccountable {id}
+ custodian {id}
+ accountingQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ onhandQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ }
+ resourceQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ atLocation {id}
+ hasPointInTime
+ }
+ }
+}
+```
+
+Get:
+```
+{
+ "data": {
+ "createEconomicEvent": {
+ "economicEvent": {
+ "id: "01FWN6ABS0RCKEVC636N8TY58D",
+ "action": {"id": "consume"},
+ "provider": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "receiver": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "inputOf": {"id": "01FWN5SVCHH662KD10E73M221J"}, # process "making apple juice"
+ "resourceConformsTo": {"id": "01FWN136Y4ZZ7K9F314HQ7MKRG"}, # apple
+ "resourceQuantity": {
+ "hasNumericalValue": 20,
+ "hasUnit": {"id": "01FWN136S5VPCCR3B3TGYDYEY9"} # kilogram
+ },
+ "resourceInventoriedAs": {
+ "id": "01FWN3ZY2Z8ZJ071YXJ315KC2W",
+ "name": "alice's apples",
+ "note": "alice's delish apples",
+ "trackingIdentifier": "lot 123",
+ "stage": {"id": "01FWN136X183DM43CTWXESNWAB"}, # fresh
+ "currentLocation": {"id": "01FWN3VH3H8T4KHN8XC7FJ32V3"}, # alice's kitchen
+ "conformsTo": {"id": "01FWN136Y4ZZ7K9F314HQ7MKRG"}, # apple
+ "primaryAccountable": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "custodian": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "accountingQuantity": {
+ "hasNumericalValue": 25, # = 45 - 15
+ "hasUnit": {"id": "01FW15136S5VPCCR3B3TGYDYEY9"} # kilogram
+ },
+ "onhandQuantity": {
+ "hasNumericalValue": 25, # = 45 - 15
+ "hasUnit": {"id": "01FWN136S5VPCCR3B3TGYDYEY9"} # kilogram
+ }
+ },
+ "atLocation": {"id": "01FWN3VH3H8T4KHN8XC7FJ32V3"}, # alice's kitchen
+ "hasPointInTime": "2022-01-02T03:04:05.000000Z"
+ }
+ }
+ }
+}
+```
+
+### Lower Examples
+
+Oh, did you import 5kg of apples accidentally? We can `lower` it!
+
+Give:
+```
+mutation {
+ createEconomicEvent(event: {
+ action: "lower"
+ provider: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ receiver: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ resourceInventoriedAs: "01FWN3ZY2Z8ZJ071YXJ315KC2W" # resource "alice's apples" 20kg
+ resourceQuantity: {
+ hasNumericalValue: 5
+ hasUnit: "01FWN136S5VPCCR3B3TGYDYEY9" # kilogram
+ }
+ atLocation: "01FWN3VH3H8T4KHN8XC7FJ32V3" # alice's kitchen
+ hasPointInTime: "2022-01-02T03:04:05Z"
+ }) {
+ economicEvent {
+ id
+ action {id}
+ provider {id}
+ receiver {id}
+ resourceInventoriedAs {
+ id
+ name
+ note
+ trackingIdentifier
+ stage {id}
+ currentLocation {id}
+ conformsTo {id}
+ primaryAccountable {id}
+ custodian {id}
+ accountingQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ onhandQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ }
+ resourceQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ atLocation {id}
+ hasPointInTime
+ }
+ }
+}
+```
+
+Get:
+```
+{
+ "data": {
+ "createEconomicEvent": {
+ "economicEvent": {
+ "id: "01FWN6ABS0RCKEVC636N8TY58D",
+ "action": {"id": "lower"},
+ "provider": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "receiver": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "resourceConformsTo": {"id": "01FWN136Y4ZZ7K9F314HQ7MKRG"}, # apple
+ "resourceQuantity": {
+ "hasNumericalValue": 5,
+ "hasUnit": {"id": "01FWN136S5VPCCR3B3TGYDYEY9"} # kilogram
+ },
+ "resourceInventoriedAs": {
+ "id": "01FWN3ZY2Z8ZJ071YXJ315KC2W",
+ "name": "alice's apples",
+ "note": "alice's delish apples",
+ "trackingIdentifier": "lot 123",
+ "stage": {"id": "01FWN136X183DM43CTWXESNWAB"}, # fresh
+ "currentLocation": {"id": "01FWN3VH3H8T4KHN8XC7FJ32V3"}, # alice's kitchen
+ "conformsTo": {"id": "01FWN136Y4ZZ7K9F314HQ7MKRG"}, # apple
+ "primaryAccountable": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "custodian": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "accountingQuantity": {
+ "hasNumericalValue": 15, # = 20 - 5
+ "hasUnit": {"id": "01FW15136S5VPCCR3B3TGYDYEY9"} # kilogram
+ },
+ "onhandQuantity": {
+ "hasNumericalValue": 15, # = 20 - 5
+ "hasUnit": {"id": "01FWN136S5VPCCR3B3TGYDYEY9"} # kilogram
+ }
+ },
+ "atLocation": {"id": "01FWN3VH3H8T4KHN8XC7FJ32V3"}, # alice's kitchen
+ "hasPointInTime": "2022-01-02T03:04:05.000000Z"
+ }
+ }
+ }
+}
+```
+
+
+### Use Examples
+
+Suppose you want to make some apple juice out of... apples. You would `consume`
+some apple resources and `produce` some apple juice resources, but this story
+doesn't sound quite right. If you want to record how you did get the juice, you
+could use a `use` event, specifying that you used a juicer.
+
+The below example demonstates that we used a juicer machine for 2 hours.
+
+Give:
+```
+mutation {
+ createEconomicEvent(event: {
+ action: "use"
+ provider: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ receiver: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ inputOf: "01FWN9E7MD5JKJE52EMP5MHYT3" # process "making apple juice"
+ resourceInventoriedAs: "01FWN9A23V1Y1XRJPZ5CG2BDYW" # the juicer
+ resourceQuantity: {
+ hasNumericalValue: 1
+ hasUnit: "01FWN9828J8M6NB95C0GV0Z324" # one/each/pcs
+ }
+ effortQuantity: {
+ hasNumericalValue: 2
+ hasUnit: "01FWN96JV5KG2N91Q3FSZRZZQ3" # hour
+ }
+ atLocation: "01FWN3VH3H8T4KHN8XC7FJ32V3" # alice's kitchen
+ hasPointInTime: "2022-01-02T03:04:05Z"
+ }) {
+ economicEvent {
+ id
+ action {id}
+ provider {id}
+ receiver {id}
+ inputOf {id}
+ resourceInventoriedAs {
+ id
+ name
+ accountingQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ onhandQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ }
+ resourceQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ effortQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ atLocation {id}
+ hasPointInTime
+ }
+ }
+}
+```
+
+Get:
+```
+{
+ "data": {
+ "createEconomicEvent": {
+ "economicEvent": {
+ "id: "01FWN9W5Y9JY6ZFTZ6518SF6PP",
+ "action": {"id": "use"},
+ "provider": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "receiver": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "inputOf": {"id": "01FWN9E7MD5JKJE52EMP5MHYT3"}, # process "making apple juice"
+ "resourceInventoriedAs": {
+ "id": "01FWN9A23V1Y1XRJPZ5CG2BDYW",
+ "name": "the juicer machine",
+ "accountingQuantity": {
+ "hasNumericalValue": 1,
+ "hasUnit": {"id": "01FWN9828J8M6NB95C0GV0Z324"} # one/each/pcs
+ },
+ "onhandQuantity": {
+ "hasNumericalValue": 1,
+ "hasUnit": {"id": "01FWN9828J8M6NB95C0GV0Z324"} # one/each/pcs
+ }
+ },
+ "resourceQuantity": {
+ "hasNumericalValue": 1,
+ "hasUnit": {"id": "01FWN9828J8M6NB95C0GV0Z324"} # one/each/pcs
+ },
+ "effortQuantity": {
+ "hasNumericalValue": 2,
+ "hasUnit": {"id": "01FWN96JV5KG2N91Q3FSZRZZQ3"} # hour
+ },
+ "atLocation": {"id": "01FWN3VH3H8T4KHN8XC7FJ32V3"}, # alice's kitchen
+ "hasPointInTime": "2022-01-02T03:04:05.000000Z"
+ }
+ }
+ }
+}
+```
+
+You can also choose to not use `resourceQuantity` or `resourceInventoriedAs` at
+all. But if you choose to not use `resourceInventoriedAs`, you must provide a
+ResourceSpecification in the field `resourceConformsTo`.
+
+This would mean that we used a machine for 2 hours, but we didn't want to use an
+actual resource for it and didn't want to provide how many of them we used.
+This is a valid usage of `use` events.
+
+Give:
+```
+mutation {
+ createEconomicEvent(event: {
+ action: "use"
+ provider: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ receiver: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ inputOf: "01FWN9E7MD5JKJE52EMP5MHYT3" # process "making apple juice"
+ resourceConformsTo: "01FWNA5WDM5FPJYPQ3BTGMFTQ5" # resource spec "juicer machine"
+ effortQuantity: {
+ hasNumericalValue: 2
+ hasUnit: "01FWN96JV5KG2N91Q3FSZRZZQ3" # hour
+ }
+ atLocation: "01FWN3VH3H8T4KHN8XC7FJ32V3" # alice's kitchen
+ hasPointInTime: "2022-01-02T03:04:05Z"
+ }) {
+ economicEvent {
+ id
+ action {id}
+ provider {id}
+ receiver {id}
+ inputOf {id}
+ resourceConformsTo {id}
+ effortQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ atLocation {id}
+ hasPointInTime
+ }
+ }
+}
+```
+
+Get:
+```
+{
+ "data": {
+ "createEconomicEvent": {
+ "economicEvent": {
+ "id: "01FWNA7DETHVJ2C97AQWK55Y8B",
+ "action": {"id": "use"},
+ "provider": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "receiver": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "inputOf": {"id": "01FWN9E7MD5JKJE52EMP5MHYT3"}, # process "making apple juice"
+ "resourceConformsTo": {"id": "01FWN9A23V1Y1XRJPZ5CG2BDYW"},
+ "effortQuantity": {
+ "hasNumericalValue": 2,
+ "hasUnit": {"id": "01FWN96JV5KG2N91Q3FSZRZZQ3"} # hour
+ },
+ "atLocation": {"id": "01FWN3VH3H8T4KHN8XC7FJ32V3"}, # alice's kitchen
+ "hasPointInTime": "2022-01-02T03:04:05.000000Z"
+ }
+ }
+ }
+}
+```
+
+
+### Work Examples
+
+`works` events are used when you want to specify what kind of work you put in a
+process. Suppose you are making some apple pies, and you are kneading the dough
+for the crust; you'd put "kneading the dough" as a work event to the proccess.
+
+There's a small catch, though: as the term "resource", thus its "specification",
+is broad in the Valueflows vocabulary, you are required to provide what kind of
+work you do to the field `resourceConformsTo`, that is, there's no such field
+as `effortConformsTo` and a type as `EffortSpecification`. Such work would be
+"kneading" in a "making apple pies" scenario.
+
+Give:
+```
+mutation {
+ createEconomicEvent(event: {
+ action: "work"
+ provider: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ receiver: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ inputOf: "01FWTXNRFVYPR98WQGPVB69DW8" # process "making apple pies"
+ resourceConformsTo: "01FWTWNTZEWYKAT0S45809QMFN" # resource spec "kneading"
+ effortQuantity: {
+ hasNumericalValue: 2
+ hasUnit: "01FWN96JV5KG2N91Q3FSZRZZQ3" # hour
+ }
+ atLocation: "01FWN3VH3H8T4KHN8XC7FJ32V3" # alice's kitchen
+ hasPointInTime: "2022-01-02T03:04:05Z
+ }) {
+ economicEvent {
+ id
+ provider {id}
+ receiver {id}
+ inputOf {id}
+ resourceInventoriedAs {id}
+ effortQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ atLocation {id}
+ hasPointInTime
+ }
+ }
+}
+```
+
+Get:
+```
+{
+ "data": {
+ "createEconomicEvent": {
+ "economicEvent": {
+ "id: "01FWTXN8ZY01XXNG9QK47PEKNH",
+ "action": {"id": "work"},
+ "provider": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "receiver": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "inputOf": {"id": "01FWTXNRFVYPR98WQGPVB69DW8"}, # process "making apple pies"
+ "resourceConformsTo": {"id": "01FWTWNTZEWYKAT0S45809QMFN"}, # resource spec "kneading"
+ "effortQuantity": {
+ "hasNumericalValue": 2,
+ "hasUnit": {"id": "01FWN96JV5KG2N91Q3FSZRZZQ3"}, # hour
+ },
+ "atLocation": {"id": "01FWN3VH3H8T4KHN8XC7FJ32V3"}, # alice's kitchen
+ "hasPointInTime": "2022-01-02T03:04:05.000000Z"
+ }
+ }
+ }
+}
+```
+
+
+### Cite Examples
+
+Suppose you are some sort of instruction paper, design files, blueprints (all
+can be digital as well) to produce something. You record the history of that
+with `cite` events. They cosume the cited resource. They're there because they
+help us to create a more meaningful history.
+
+Give:
+```
+mutation {
+ createEconomicEvent(event: {
+ action: "cite"
+ provider: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ receiver: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ inputOf: "01FWPA0H6YB1NDP2X1HNCXFQN9" # process "creating flags"
+ resourceInventoriedAs: "01FWPA7HXMA25AGA3VXXR0540K" # resource "flag design"
+ resourceQuantity: {
+ hasNumericalValue: 1
+ hasUnit: "01FWN9828J8M6NB95C0GV0Z324" # one/each/pcs
+ }
+ atLocation: "01FWPAG1YVBXXPTQNSCFG48RTY" # alice's workshop
+ hasPointInTime: "2022-01-02T03:04:05Z
+ }) {
+ economicEvent {
+ id
+ provider {id}
+ receiver {id}
+ inputOf {id}
+ resourceInventoriedAs {id}
+ resourceQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ atLocation {id}
+ hasPointInTime
+ }
+ }
+}
+```
+
+Get:
+```
+{
+ "data": {
+ "createEconomicEvent": {
+ "economicEvent": {
+ "id: "01FWPAE4JC2P039G4B93D0AS4Q",
+ "action": {"id": "cite"},
+ "provider": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "receiver": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "inputOf": {"id": "01FWPA0H6YB1NDP2X1HNCXFQN9"}, # process "creating flags"
+ "resourceInventoriedAs": {"id": "01FWPA7HXMA25AGA3VXXR0540K"}, # resource "flag design"
+ "resourceQuantity": {
+ "hasNumericalValue": 1,
+ "hasUnit": {"id": "01FWN9828J8M6NB95C0GV0Z324"}, # one/each/pcs
+ },
+ "atLocation": {"id": "01FWPAG1YVBXXPTQNSCFG48RTY"}, # alice's workshop
+ "hasPointInTime": "2022-01-02T03:04:05.000000Z"
+ }
+ }
+ }
+}
+```
+
+With `cite` events, you may wish to just use a ResourceSpecification instead of
+an Economicresource. But, you must provide the quantity nonetheless.
+
+Give:
+```
+mutation {
+ createEconomicEvent(event: {
+ action: "cite"
+ provider: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ receiver: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice
+ inputOf: "01FWPA0H6YB1NDP2X1HNCXFQN9" # process "creating flags"
+ resourceConformsTo: "01FWPAN3ST2FE431DSBQTCMBN9" # resource spec "flag design"
+ resourceQuantity: {
+ hasNumericalValue: 1
+ hasUnit: "01FWN9828J8M6NB95C0GV0Z324" # one/each/pcs
+ }
+ atLocation: "01FWPAG1YVBXXPTQNSCFG48RTY" # alice's workshop
+ hasPointInTime: "2022-01-02T03:04:05Z
+ }) {
+ economicEvent {
+ id
+ provider {id}
+ receiver {id}
+ inputOf {id}
+ resourceConformsTo {id}
+ resourceQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ atLocation {id}
+ hasPointInTime
+ }
+ }
+}
+```
+
+Get:
+```
+{
+ "data": {
+ "createEconomicEvent": {
+ "economicEvent": {
+ "id: "01FWPAE4JC2P039G4B93D0AS4Q",
+ "action": {"id": "cite"},
+ "provider": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "receiver": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice
+ "inputOf": {"id": "01FWPA0H6YB1NDP2X1HNCXFQN9"}, # process "creating flags"
+ "resourceConformsTo": {"id": "01FWPAN3ST2FE431DSBQTCMBN9"} # resource spec "flag design"
+ "resourceQuantity": {
+ "hasNumericalValue": 1,
+ "hasUnit": {"id": "01FWN9828J8M6NB95C0GV0Z324"}, # one/each/pcs
+ },
+ "atLocation": {"id": "01FWPAG1YVBXXPTQNSCFG48RTY"}, # alice's workshop
+ "hasPointInTime": "2022-01-02T03:04:05.000000Z"
+ }
+ }
+ }
+}
+```
+
+
+### DeliverService Examples
+
+When you want to indicate the services used in a process, you use
+`deliverService` events.
+
+Painting a house, transporting a pizza, and dry-cleaning clothes are examples of
+services.
+
+Similar to `work` events, `resourceConformsTo` refer to the type of service.
+
+Give:
+```
+mutation {
+ createEconomicEvent(event: {
+ action: "deliverService"
+ provider: "01FWN12XX7TJX1AFF5KA4WPNN9" # bob the painter
+ receiver: "01FWN3QA3Q2G0JNYHBCCBEN76H" # alice the house owner
+ outputOf: "01FWV0BXSCMRWHRCFCQ82JM2S3" # process "painting alice's house"
+ resourceConformsTo: "01FWV0G7X0H03BQKPV0W8Q32EA" # resource spec "painting"
+ atLocation: "01FWV0REX2G4VHRRBH5QSWD7N8" # alice's house
+ hasPointInTime: "2022-01-02T03:04:05Z"
+ }) {
+ economicEvent {
+ id
+ provider {id}
+ receiver {id}
+ outputOf {id}
+ resourceConformsTo {id}
+ atLocation {id}
+ hasPointInTime
+ }
+ }
+}
+```
+
+Get:
+```
+{
+ "data": {
+ "createEconomicEvent": {
+ "economicEvent": {
+ "id: "01FWV0N1FE320H75Q8RYVAFTR4",
+ "action": {"id": "deliverService"},
+ "provider": {"id": "01FWN12XX7TJX1AFF5KA4WPNN9"}, # bob the painter
+ "receiver": {"id": "01FWN3QA3Q2G0JNYHBCCBEN76H"}, # alice the house owner
+ "outputOf": {"id": "01FWPA0H6YB1NDP2X1HNCXFQN9"}, # process "painting alice's house"
+ "resourceConformsTo": {"id": "01FWV0G7X0H03BQKPV0W8Q32EA"} # resource spec "painting"
+ "atLocation": {"id": "01FWV0REX2G4VHRRBH5QSWD7N8"}, # alice's workshop
+ "hasPointInTime": "2022-01-02T03:04:05.000000Z"
+ }
+ }
+ }
+}
+```
+
+# GraphQL Documents
+
+
+## Economic Events
+
+All the events require `action`, `provider`, `receiver` fields along with one of these datetime combinations (no particular validation regarding the datetime fields is performed, such as wether `hasBeginning` is actually older or equal to than `hasEnd`):
+
+* only `hasPointInTime`
+* only `hasBeginning`
+* only `hasEnd`
+* both `hasBeginning` and `hasEnd`
+
+The rest of the sections will asume you are aware of this information.
+
+
+### Produce Events
+
+Produce events require `outputOf`, `resourceConformsTo`, `resourceQuantity`,
+and `newInventoriedResource.name`. You can provide the soon-to-be-created
+resource's `name`, `note`, `trackingIdentifier` through
+`newInventoriedResource`. Here is an example document that uses variables:
+
+```
+mutation (
+ $outputOf: ID!
+ $provider: ID!
+ $receiver: ID!
+ $resourceConformsTo: ID!
+ $resourceQuantity: IMeasure!
+ $newInventoriedResource: EconomicResourceCreateParams!
+ $hasPointInTime: DateTime
+ $hasBeginning: DateTime
+ $hasEnd: DateTime
+) {
+ createEconomicEvent(
+ event: {
+ action: "produce"
+ outputOf: $outputOf
+ provider: $provider
+ receiver: $receiver
+ resourceConformsTo: $resourceConformsTo
+ resourceQuantity: $resourceQuantity
+ hasPointInTime: $hasPointInTime
+ hasBeginning: $hasBeginning
+ hasEnd: $hasEnd
+ }
+ newInventoriedResource: $newInventoriedResource
+ ) {
+ economicEvent {
+ id
+ action {id}
+ outputOf {id}
+ provider {id}
+ receiver {id}
+ resourceConformsTo {id}
+ resourceQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ resourceInventoriedAs {
+ id
+ name
+ note
+ primaryAccountable {id}
+ accountingQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ onhandQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ conformsTo {id}
+ }
+ hasPointInTime
+ hasEnd
+ hasBeginning
+ }
+ }
+}
+```
+
+and the example variables:
+
+```
+{
+ "outputOf": "01G2Q2AT2PHQD56N9RFX3A240J",
+ "provider": "01FZFE8E43ANRY360J1E98PJ0Z",
+ "receiver": "01FZFE8E43ANRY360J1E98PJ0Z",
+ "resourceConformsTo": "01FTB03K54ZF38FHEKGVHTWGY8",
+ "resourceQuantity": {
+ "hasNumericalValue": 10.0,
+ "hasUnit": "01FTB06BQ64MSS7XSB3QMSW83R"
+ },
+ "newInventoriedResource": {
+ "name": "some name",
+ "note": "some note"
+ },
+ "hasEnd": "2022-01-02T03:04:05Z"
+}
+```
+
+
+### Consume Events
+
+Consume events require `inputOf`, `resourceInventoriedAs`, and
+`resourceQuantity` fields. Here is an example document that uses variables:
+
+```
+mutation (
+ $inputOf: ID!
+ $provider: ID!
+ $receiver: ID!
+ $resourceInventoriedAs: ID!
+ $resourceQuantity: IMeasure!
+ $hasPointInTime: DateTime
+ $hasBeginning: DateTime
+ $hasEnd: DateTime
+) {
+ createEconomicEvent(event: {
+ action: "consume"
+ inputOf: $inputOf
+ provider: $provider
+ receiver: $receiver
+ resourceInventoriedAs: $resourceInventoriedAs
+ resourceQuantity: $resourceQuantity
+ hasPointInTime: $hasPointInTime
+ hasBeginning: $hasBeginning
+ hasEnd: $hasEnd
+ }) {
+ economicEvent {
+ id
+ action {id}
+ inputOf {id}
+ provider {id}
+ receiver {id}
+ resourceQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ resourceInventoriedAs {
+ id
+ name
+ note
+ primaryAccountable {id}
+ accountingQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ onhandQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ conformsTo {id}
+ }
+ hasPointInTime
+ hasEnd
+ hasBeginning
+ }
+ }
+}
+```
+
+and the example variables:
+
+```
+{
+ "inputOf": "01G2Q2AT2PHQD56N9RFX3A240J",
+ "provider": "01FZFE8E43ANRY360J1E98PJ0Z",
+ "receiver": "01FZFE8E43ANRY360J1E98PJ0Z",
+ "resourceInventoriedAs": "01FTB03K54ZF38FHEKGVHTWGY8",
+ "resourceQuantity": {
+ "hasNumericalValue": 10.0,
+ "hasUnit": "01FTB06BQ64MSS7XSB3QMSW83R"
+ },
+ "hasPointInTime": "2022-01-02T03:04:05Z"
+}
+```
+
+
+### Raise Events
+
+Raise events are almost identical to produce events, execept for their semantic
+meaning, and the fact that they don't require `outputOf` to be provided (that's
+related to the semantic meaning). Here is an example document that uses
+variables:
+
+```
+mutation (
+ $provider: ID!
+ $receiver: ID!
+ $resourceConformsTo: ID!
+ $resourceQuantity: IMeasure!
+ $newInventoriedResource: EconomicResourceCreateParams!
+ $hasPointInTime: DateTime
+ $hasBeginning: DateTime
+ $hasEnd: DateTime
+) {
+ createEconomicEvent(
+ event: {
+ action: "raise"
+ provider: $provider
+ receiver: $receiver
+ resourceConformsTo: $resourceConformsTo
+ resourceQuantity: $resourceQuantity
+ hasPointInTime: $hasPointInTime
+ hasBeginning: $hasBeginning
+ hasEnd: $hasEnd
+ }
+ newInventoriedResource: $newInventoriedResource
+ ) {
+ economicEvent {
+ id
+ action {id}
+ provider {id}
+ receiver {id}
+ resourceConformsTo {id}
+ resourceQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ resourceInventoriedAs {
+ id
+ name
+ note
+ primaryAccountable {id}
+ accountingQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ onhandQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ conformsTo {id}
+ }
+ hasPointInTime
+ hasEnd
+ hasBeginning
+ }
+ }
+}
+```
+
+and the example variables:
+
+```
+{
+ "provider": "01FZFE8E43ANRY360J1E98PJ0Z",
+ "receiver": "01FZFE8E43ANRY360J1E98PJ0Z",
+ "resourceConformsTo": "01FTB03K54ZF38FHEKGVHTWGY8",
+ "resourceQuantity": {
+ "hasNumericalValue": 10.0,
+ "hasUnit": "01FTB06BQ64MSS7XSB3QMSW83R"
+ },
+ "newInventoriedResource": {
+ "name": "some name",
+ "note": "some note"
+ },
+ "hasBeginning": "2022-01-02T03:04:05Z"
+}
+```
+
+
+### Lower Events
+
+Raise events are almost identical to consume events, execept for their semantic
+meaning, and the fact that they don't require `inputOf` to be provided (that's
+related to the semantic meaning). Here is an example document that uses
+variables:
+
+```
+mutation (
+ $provider: ID!
+ $receiver: ID!
+ $resourceInventoriedAs: ID!
+ $resourceQuantity: IMeasure!
+ $hasPointInTime: DateTime
+ $hasBeginning: DateTime
+ $hasEnd: DateTime
+) {
+ createEconomicEvent(event: {
+ action: "lower"
+ provider: $provider
+ receiver: $receiver
+ resourceInventoriedAs: $resourceInventoriedAs
+ resourceQuantity: $resourceQuantity
+ hasPointInTime: $hasPointInTime
+ hasBeginning: $hasBeginning
+ hasEnd: $hasEnd
+ }) {
+ economicEvent {
+ id
+ action {id}
+ inputOf {id}
+ provider {id}
+ receiver {id}
+ resourceQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ resourceInventoriedAs {
+ id
+ name
+ note
+ primaryAccountable {id}
+ accountingQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ onhandQuantity {
+ hasNumericalValue
+ hasUnit {id}
+ }
+ conformsTo {id}
+ }
+ hasPointInTime
+ hasEnd
+ hasBeginning
+ }
+ }
+}
+```
+
+and the example variables:
+
+```
+{
+ "provider": "01FZFE8E43ANRY360J1E98PJ0Z",
+ "receiver": "01FZFE8E43ANRY360J1E98PJ0Z",
+ "resourceInventoriedAs": "01FTB03K54ZF38FHEKGVHTWGY8",
+ "resourceQuantity": {
+ "hasNumericalValue": 10.0,
+ "hasUnit": "01FTB06BQ64MSS7XSB3QMSW83R"
+ },
+ "hasBeginning": "2022-01-02T03:04:05Z",
+ "hasEnd": "2022-01-02T03:04:05Z"
+}
+```
diff --git a/mix.exs b/mix.exs
@@ -7,7 +7,7 @@ def project() do
version: "0.1.0",
elixir: "~> 1.11", # erlang/otp 22-24
start_permanent: Mix.env() == :prod,
- config_path: "conf/common.exs",
+ config_path: "conf/buildtime.exs",
deps: deps(),
releases: [
zenflows: [
@@ -19,12 +19,18 @@ def project() do
elixirc_paths: elixirc_paths(Mix.env()),
test_pattern: "*.test.exs",
warn_test_pattern: "*{.test.ex,_test.ex,_test.exs}",
+
+ # doc
+ name: "Zenflows",
+ source_url: "https://github.com/dyne/zenflows.git",
+ hompage_url: "https://github.com/dyne/zenflows",
+ docs: docs(),
]
end
def application() do
[
- extra_applications: [:logger],
+ extra_applications: [:logger, :inets, :ssl],
mod: {Zenflows.Application, []},
]
end
@@ -42,7 +48,7 @@ defp deps() do
{:plug_cowboy, "~> 2.5"},
# graphql
- {:absinthe, "~> 1.6"},
+ {:absinthe, "~> 1.7"},
{:absinthe_plug, "~> 1.5"},
{:jason, "~> 1.3"},
@@ -52,9 +58,30 @@ defp deps() do
# static analysis
{:credo, "~> 1.5", only: [:dev, :test], runtime: false},
{:dialyxir, "~> 1.0", only: [:dev], runtime: false},
+
+ # doc
+ {:ex_doc, "~> 0.28", only: :dev, runtime: false},
]
end
+defp docs() do
+[
+ main: "readme",
+ source_ref: "master",
+ extra_section: "DOCS",
+ extras: [
+ "README.md",
+ "docs/configuration-guide.md",
+ "docs/vf-intro-gql-iface.md",
+ "docs/software-licences.md",
+ "docs/dependency-management.md",
+ "docs/style-guide.md",
+ "LICENSE",
+ ],
+ output: ".docs"
+]
+end
+
defp elixirc_paths(:test), do: ["src/", "test/help/"]
defp elixirc_paths(_), do: ["src/"]
end