# Pod Resources

### Resource Types

ESS Pods supports storing different types of resources:

* [Resource Description Framework (RDF) Resources](https://docs.inrupt.com/reference/glossary#rdf-resource)
* [Non-RDF Resources](https://docs.inrupt.com/reference/glossary#non-rdf-resource)
* [Containers](https://docs.inrupt.com/reference/glossary#container)

### CRUD Operations

ESS supports the [Solid Protocol specification](https://solidproject.org/TR/protocol). As such, retrieving, creating, deleting and editing Solid Resources within a Pod is directly supported via the standard HTTP interfaces.

### Access Control

This section summarizes the relationship between Create/Read/Update/Delete (CRUD) operations and the required access modes.

{% tabs %}
{% tab title="Create" %}
To create a resource, the user requires either an **`Append`** or **`Write`** access.

{% hint style="info" %}
**Note**\
The creation operation creates the resource (be it container, RDF resource, non-RDF resource) and updates the content of the **parent** container with the new resource’s metadata.
{% endhint %}

<table><thead><tr><th width="132.97369384765625">Resource</th><th>Description</th></tr></thead><tbody><tr><td><a href="../../../reference/glossary#container">Container</a></td><td><p>Either <strong><code>Append</code></strong> or <strong><code>Write</code></strong> access on the <strong>parent</strong> container (under which the new container is to be created) allows agents to create a new container.</p><p>For example, to create <strong><code>https://storage..../parentcontainer/newContainer/</code></strong>, either an <strong><code>Append</code></strong> or a <strong><code>Write</code></strong> access on <strong><code>https://storage..../parentcontainer/</code></strong> allows agents to create <strong><code>https://storage..../parentcontainer/newContainer/</code></strong>.</p></td></tr><tr><td><a href="../../../reference/glossary#rdf-resource">RDF resource</a></td><td><p>Either <code>Append</code> or <code>Write</code> access on the <strong>parent</strong> container (under which the new resource is to be created) allows agents to create a RDF resource.</p><p>For example, to create <strong><code>https://storage..../parentcontainer/newResource/</code></strong>, either an <strong><code>Append</code></strong> or a <strong><code>Write</code></strong> access on <strong><code>https://storage..../parentcontainer/</code></strong> allows agents to create <strong><code>https://storage..../parentcontainer/newResource</code></strong>.</p></td></tr><tr><td><a href="../../../reference/glossary#non-rdf-resource">Non-RDF resource</a></td><td><p>Either <strong><code>Append</code></strong> or <strong><code>Write</code></strong> access on the <strong>parent</strong> container (under which the new resource is to be created) allows agents to create a new non-RDF resource.</p><p>For example, to create <strong><code>https://storage..../parentcontainer/foo.jpg</code></strong>, an <strong><code>Append</code></strong> or <strong><code>Write</code></strong> access on <strong><code>https://storage..../parentcontainer/</code></strong> allows agents to create <strong><code>https://storage..../parentcontainer/foo.jpg</code></strong>.</p></td></tr></tbody></table>
{% endtab %}

{% tab title="Read" %}
For read operations, the user requires **`Read`** access.

<table><thead><tr><th width="148.67333984375">Resource</th><th>Description</th></tr></thead><tbody><tr><td><a href="../../../reference/glossary#container">Container</a></td><td><p><strong><code>Read</code></strong> access to the target container (analogous to a folder in a file system), allowing agents to read/retrieve the container as a resource (not the resource(s) under the container). That is, Read access only affects read operation on the container itself.</p><p>Reading a container (which stores metadata about the resources contained within the container) allows a client to discover what resources are contained inside the container and their resource type (i.e., analogous to an <strong><code>ls</code></strong> on a folder in a file system).</p></td></tr><tr><td><a href="../../../reference/glossary#rdf-resource">RDF resource</a></td><td><p><strong><code>Read</code></strong> access to the RDF resource allows agents to read/retrieve the resource (regardless of the access on the parent container).</p><p>For example, if a resource has as its URL <strong><code>https://storage..../container/ResourceToRead</code></strong>, to read/retrieve this resource:</p><ul><li>The user must have <code>Read</code> access on <strong><code>https://storage..../container/ResourceToRead</code></strong>.</li><li>The user’s access on <strong><code>https://storage..../container/</code></strong> is immaterial.</li></ul></td></tr><tr><td><a href="../../../reference/glossary#non-rdf-resource">Non-RDF resource</a></td><td><p><strong><code>Read</code></strong> access on a non-RDF resource allows agents to read/retrieve the resource (regardless of Read access on the container).</p><p>For example, if a non-RDF resource has as its URL <strong><code>https://storage..../container/foo.jpg</code></strong>, to read/retrieve this resource:</p><ul><li>The user must have <code>Read</code> access on <strong><code>https://storage..../container/foo.jpg</code></strong>.</li><li>The user’s access on <strong><code>https://storage..../container/</code></strong> is immaterial.</li></ul></td></tr></tbody></table>

**`Read`** access is also required to subscribe to [notifications](https://docs.inrupt.com/ess/2.5/services/service-notification/service-websocket) about a resource.
{% endtab %}

{% tab title="Update" %}
For update operations, the user requires **`Append`** or **`Write`** access, depending on the specific update operation.

<table><thead><tr><th width="132.7393798828125">Resource</th><th>Description</th></tr></thead><tbody><tr><td><a href="../../../reference/glossary#container">Container</a></td><td><p>To add resources to the Container, see the <strong><code>Create</code></strong> tab.</p><p>To delete resources from the Container, see the <strong><code>Delete</code></strong> tab.</p></td></tr><tr><td><a href="../../../reference/glossary#rdf-resource">RDF resource</a></td><td><ul><li>Either <strong><code>Append</code></strong> or <strong><code>Write</code></strong> access on an RDF resource allows agents to add content (statements) to the resource.</li><li><strong><code>Write</code></strong> access on an RDF resource allows agents to delete content (statements) from the resource.</li><li><strong><code>Write</code></strong> access on an RDF resource allows agents to modify existing content (statements) in the resource.</li></ul></td></tr><tr><td><a href="../../../reference/glossary#non-rdf-resource">Non-RDF resource</a></td><td><p><code>Write</code> access on the target resource allows agents to overwrite/replace the resource (regardless of the access on the parent container).</p><p>For example, if the non-RDF resource has as its URL <strong><code>https://storage..../container/foo.jpg</code></strong>, to overwrite this resource:</p><ul><li>The user must have <strong><code>Write</code></strong> access on <strong><code>https://storage..../container/foo.jpg</code></strong>.</li><li>The user’s access on <strong><code>https://storage..../container/</code></strong> is immaterial.</li></ul></td></tr></tbody></table>
{% endtab %}

{% tab title="Delete" %}
For delete operations, the user requires **`Write`** access.

<table><thead><tr><th width="138.6839599609375">Resource</th><th>Description</th></tr></thead><tbody><tr><td><a href="../../../reference/glossary#container">Container</a></td><td><p><strong><code>Write</code></strong> access to both the parent container and the target container allows agents to delete the target container.</p><p>For example, to delete <strong><code>https://storage..../parentcontainer/containerToDelete/</code></strong>, <code>Write</code> access to both <strong><code>https://storage..../parentcontainer/</code></strong> and <strong><code>https://storage..../parentcontainer/containerToDelete/</code></strong> allows agents to delete <strong><code>https://storage..../parentcontainer/containerToDelete/</code></strong></p><div data-gb-custom-block data-tag="hint" data-style="warning" class="hint hint-warning"><p>Tip<br>To delete a container, the container must be empty.</p></div></td></tr><tr><td><a href="../../../reference/glossary#rdf-resource">RDF resource</a></td><td>To delete an RDF resource , <code>Write</code> access on both the<br>parent container and the target resource allows agents<br>to delete the target resource.<br>For example, to delete<strong><code>https://storage..../parentcontainer/resourceToDelete/</code>,<code>Write</code></strong> access on both<strong><code>https://storage..../parentcontainer/</code></strong> and<strong><code>https://storage..../parentcontainer/resourceToDelete</code></strong><br>allows agents to delete<strong><code>https://storage..../parentcontainer/resourceToDelete</code>.</strong></td></tr><tr><td><a href="../../../reference/glossary#non-rdf-resource">Non-RDF resource</a></td><td>To delete a non-RDF resource, <strong><code>Write</code></strong> access on both<br>the parent container and the target resource allows agents<br>to delete the target resource.<br>For example, to delete<strong><code>https://storage..../parentcontainer/foo.jpg</code></strong>, <strong><code>Write</code></strong><br>access on both <strong><code>https://storage..../parentcontainer/</code></strong><br>and <strong><code>https://storage..../parentcontainer/foo.jpg</code></strong> allows<br>agents to delete<strong><code>https://storage..../parentcontainer/foo.jpg</code></strong>.</td></tr></tbody></table>

{% hint style="warning" %}
Tip\
To delete a container, the container must be empty.
{% endhint %}
{% endtab %}
{% endtabs %}

### Other Considerations

#### **Resource Deletion**

For resource deletions, ESS uses soft deletes. That is, ESS marks the resource as deleted but does not perform an actual delete from the data store. The use of soft deletes can:

* Help maintain throughput when compared to database delete operations that may be potentially costly due to locking.
* Facilitate disaster recovery.
* Be part of a data-retention strategy.

{% hint style="info" %}
Overwriting a resource with a new resource also results in a soft delete of the old version of the resource.

Overwriting a resource with a new resource is separate from an operation that just modifies the contents of a resource. Instead, modification of the contents (even though the modification may completely replace the contents) results in orphan data.
{% endhint %}

ESS provides the ability to schedule [hard deletes](https://docs.inrupt.com/ess/services/service-pod-management/service-pod-storage#prune-hard-delete-feature) for the soft deleted resources

#### **Modification of Resource Content**

When data in a file is modified or deleted, the old data remains but is no longer referenced by metadata. That is, the replaced/deleted data is orphaned.

ESS provides the ability to schedule hard deletes for the orphan data.

{% hint style="info" %}
The modification/deletion of the data is separate from overwriting a file with a new file. Overwriting a file does not result in orphan data. Instead, overwriting a file with a new file results in a soft delete of the old version of the file.
{% endhint %}

### Initial Access Policies

When a Pod is created, like any other Pod resource, an Access Control Resource is also created for the Pod Root. The ACR is initialized with the default ACP policies for the Pod Owner and for Access Grant enablement:

* **Initial Pod Owner policies** give the Pod Owner read and write access to the Pod. These policies also specify a client matcher as well if the **Authorization service’s** configuration for the initial client allow list is set:
  * [**`INRUPT_AUTHORIZATION_DEFAULT_ACR_CLIENT_ID_ALLOW_LIST`**](https://docs.inrupt.com/ess/services/service-authorization#inrupt_authorization_default_acr_client_id_allow_list) or if that is unset,
  * [**`INRUPT_AUTHORIZATION_CLIENT_ID_ALLOW_LIST`**](https://docs.inrupt.com/ess/services/service-authorization#inrupt_authorization_client_id_allow_list)

{% tabs %}
{% tab title="Allow List is Set" %}
{% hint style="info" %}
ESS uses the values in its **Authorization service’s** [**`INRUPT_AUTHORIZATION_DEFAULT_ACR_CLIENT_ID_ALLOW_LIST`**](https://docs.inrupt.com/ess/services/service-authorization#inrupt_authorization_default_acr_client_id_allow_list) (at the time of Pod creation) to create the client matcher for the initial ACP policies. If the configuration is unset, ESS uses the values in its **Authorization service’s** [**`INRUPT_AUTHORIZATION_CLIENT_ID_ALLOW_LIST`**](https://docs.inrupt.com/ess/services/service-authorization#inrupt_authorization_client_id_allow_list) (at the time of Pod creation).
{% endhint %}

Using the value of the Pod owner’s WebID and an initial client allow list, ESS creates the initial policies of the form:

```
If allOf(AgentMatcher and ClientMatcher) evaluates to true, Then allow (Read and Write).
```

Specifically, ESS creates:

**Policy 1 for the Pod Root:**\
If the agent matches the Pod owner’s WebID, and if the client application’s Client ID has a match in the initial client allow list, allow Read and Write access.

**Policy 2 for the Pod Root’s Initial Member Policies:**\
If the agent matches the Pod owner’s WebID, and if the client application’s Client ID has a match in the initial client allow list, allow Read and Write access.

For more information on a Container’s Member Policies, see [Member Policies](https://docs.inrupt.com/security/authorization/acp#member-policies).
{% endtab %}

{% tab title="Allow List is Not Set" %}
{% hint style="info" %}
ESS uses the values in its **Authorization service’s** [**`INRUPT_AUTHORIZATION_DEFAULT_ACR_CLIENT_ID_ALLOW_LIST`**](https://docs.inrupt.com/ess/services/service-authorization#inrupt_authorization_default_acr_client_id_allow_list) (at the time of Pod creation) to create the client matcher for the initial ACP policies. If the configuration is unset, ESS uses the values in its **Authorization service’s** [**`INRUPT_AUTHORIZATION_CLIENT_ID_ALLOW_LIST`**](https://docs.inrupt.com/ess/services/service-authorization#inrupt_authorization_client_id_allow_list) (at the time of Pod creation).
{% endhint %}

If the initial client allow list is empty (when creating the policy), ESS uses the value of the Pod owner’s WebID to create initial policies of the form:

```
If allOf(AgentMatcher) evaluates to true, Then allow (Read and Write).
```

Specifically, ESS creates:

**Policy 1 for the Pod Root:**\
If the agent matches the Pod owner’s WebID, allow Read and Write access.

**Policy 2 for the Pod Root’s Initial Member Policies:**\
If the agent matches the Pod owner’s WebID, allow Read and Write access.

For more information on a Container’s Member Policies, see [Member Policies](https://docs.inrupt.com/security/authorization/acp#member-policies).
{% endtab %}
{% endtabs %}

{% hint style="danger" %}
**Disambiguation**\
Both [Authorization Service](https://docs.inrupt.com/ess/2.5/services/service-authorization) and [Pod Storage Service](https://docs.inrupt.com/ess/2.5/services/service-pod-management/service-pod-storage) have a **`INRUPT_AUTHORIZATION_CLIENT_ID_ALLOW_LIST`** setting.

**Only** the Authorization Service setting affects which clients are allowed. The Pod Storage Service is for [Discovery](https://docs.inrupt.com/ess/services/service-pod-management/service-pod-storage#discovery) purposes only.
{% endhint %}

* **Initial Access Grant Enablement policies** allow the use of [Access Grants](https://docs.inrupt.com/security/authorization/access-requests-grants) that grant read/write/append access to the Pod resources.

  ```
  If allOf(VC Matcher) evaluates to true, Then allow (Read and Write and Append).
  ```

  \
  Specifically, ESS creates:\
  \
  **Policy 3 for the Pod Root:**\
  If a presented VC matches the specified type, allow its use for\
  Read, Write, and Append access.\
  \
  **Policy 4 for the Pod Root’s Initial Member Policies:**\
  If a presented VC matches the specified type, allow its use for\
  Read, Write, and Append access.\
  \
  See also [**`INRUPT_AUTHORIZATION_DEFAULT_ACR_ACCESS_GRANTS_ALLOWED_MODES`**](https://docs.inrupt.com/ess/services/service-authorization#inrupt_authorization_default_acr_access_grants_allowed_modes).

{% hint style="warning" %}
**Important**\
The policies only enable the use of [Access Grants](https://docs.inrupt.com/security/authorization/access-requests-grants) for the allowed access modes. To determine the access for an agent using an access grant, ESS uses the *intersection* of:

* The allowed access specified by the policy, and
* The granted access specified in the Access Grant (for the resource specified in the Access Grant).
  {% endhint %}

{% hint style="info" %}
**Note**\
A Pod’s initial Policies are set when the Pod is provisioned. As such, updates to the various **`INRUPT_AUTHORIZATION_DEFAULT_ACR_*`** options do not affect existing Pods.

That is, once a Pod’s initial policies have been created, changes to the various **`INRUPT_AUTHORIZATION_DEFAULT_ACR_*`** options are not reflected in that Pod’s policies.
{% endhint %}
