diff --git a/acp/README.md b/acp/README.md
index 54c479b5ea..4c2c73907a 100644
--- a/acp/README.md
+++ b/acp/README.md
@@ -427,6 +427,209 @@ Error:
 
 ### Execute Explain example (coming soon)
 
+### Sharing Private Documents With Others
+
+To share a document (or grant a more restricted access) with another actor, we must add a relationship between the
+actor and the document. Inorder to make the relationship we require all of the following:
+
+1) **Target DocID**: The `docID` of the document we want to make a relationship for.
+2) **Collection Name**: The name of the collection that has the `Target DocID`.
+3) **Relation Name**: The type of relation (name must be defined within the linked policy on collection).
+4) **Target Identity**: The identity of the actor the relationship is being made with.
+5) **Requesting Identity**: The identity of the actor that is making the request.
+
+Note:
+  - ACP must be available (i.e. ACP can not be disabled).
+  - The collection with the target document must have a valid policy and resource linked.
+  - The target document must be registered with ACP already (private document).
+  - The requesting identity MUST either be the owner OR the manager (manages the relation) of the resource.
+  - If the specified relation was not granted the miminum DPI permissions (read or write) within the policy,
+  and a relationship is formed, the subject/actor will still not be able to access (read or write) the resource.
+  - If the relationship already exists, then it will just be a no-op.
+
+Consider the following policy that we have under `examples/dpi_policy/user_dpi_policy_with_manages.yml`:
+
+```yaml
+name: An Example Policy
+
+description: A Policy
+
+actor:
+  name: actor
+
+resources:
+  users:
+    permissions:
+      read:
+        expr: owner + reader + writer
+
+      write:
+        expr: owner + writer
+
+      nothing:
+        expr: dummy
+
+    relations:
+      owner:
+        types:
+          - actor
+
+      reader:
+        types:
+          - actor
+
+      writer:
+        types:
+          - actor
+
+      admin:
+        manages:
+          - reader
+        types:
+          - actor
+
+      dummy:
+        types:
+          - actor
+```
+
+Add the policy:
+```sh
+defradb client acp policy add -f examples/dpi_policy/user_dpi_policy_with_manages.yml \
+--identity e3b722906ee4e56368f581cd8b18ab0f48af1ea53e635e3f7b8acd076676f6ac
+```
+
+Result:
+```json
+{
+  "PolicyID": "ec11b7e29a4e195f95787e2ec9b65af134718d16a2c9cd655b5e04562d1cabf9"
+}
+```
+
+Add schema, linking to the users resource and our policyID:
+```sh
+defradb client schema add '
+type Users @policy(
+    id: "ec11b7e29a4e195f95787e2ec9b65af134718d16a2c9cd655b5e04562d1cabf9",
+    resource: "users"
+) {
+    name: String
+    age: Int
+}
+'
+```
+
+Result:
+```json
+[
+  {
+    "Name": "Users",
+    "ID": 1,
+    "RootID": 1,
+    "SchemaVersionID": "bafkreihhd6bqrjhl5zidwztgxzeseveplv3cj3fwtn3unjkdx7j2vr2vrq",
+    "Sources": [],
+    "Fields": [
+      {
+        "Name": "_docID",
+        "ID": 0,
+        "Kind": null,
+        "RelationName": null,
+        "DefaultValue": null
+      },
+      {
+        "Name": "age",
+        "ID": 1,
+        "Kind": null,
+        "RelationName": null,
+        "DefaultValue": null
+      },
+      {
+        "Name": "name",
+        "ID": 2,
+        "Kind": null,
+        "RelationName": null,
+        "DefaultValue": null
+      }
+    ],
+    "Indexes": [],
+    "Policy": {
+      "ID": "ec11b7e29a4e195f95787e2ec9b65af134718d16a2c9cd655b5e04562d1cabf9",
+      "ResourceName": "users"
+    },
+    "IsMaterialized": true
+  }
+]
+```
+
+Create a private document:
+```sh
+defradb client collection create --name Users '[{ "name": "SecretShahzadLone" }]' \
+--identity e3b722906ee4e56368f581cd8b18ab0f48af1ea53e635e3f7b8acd076676f6ac
+```
+
+Only the owner can see it:
+```sh
+defradb client collection docIDs --identity e3b722906ee4e56368f581cd8b18ab0f48af1ea53e635e3f7b8acd076676f6ac
+```
+
+Result:
+```json
+{
+  "docID": "bae-ff3ceb1c-b5c0-5e86-a024-dd1b16a4261c",
+  "error": ""
+}
+```
+
+Another actor can not:
+```sh
+defradb client collection docIDs --identity 4d092126012ebaf56161716018a71630d99443d9d5217e9d8502bb5c5456f2c5
+```
+
+**Result is empty from the above command**
+
+
+Now let's make the other actor a reader of the document by adding a relationship:
+```sh
+defradb client acp relationship add \
+--collection Users \
+--docID bae-ff3ceb1c-b5c0-5e86-a024-dd1b16a4261c \
+--relation reader \
+--actor did:key:z7r8os2G88XXBNBTLj3kFR5rzUJ4VAesbX7PgsA68ak9B5RYcXF5EZEmjRzzinZndPSSwujXb4XKHG6vmKEFG6ZfsfcQn \
+--identity e3b722906ee4e56368f581cd8b18ab0f48af1ea53e635e3f7b8acd076676f6ac
+```
+
+Result:
+```json
+{
+  "ExistedAlready": false
+}
+```
+
+**Note: If the same relationship is created again the `ExistedAlready` would then be true, indicating no-op**
+
+Now the other actor can read:
+```sh
+defradb client collection docIDs --identity 4d092126012ebaf56161716018a71630d99443d9d5217e9d8502bb5c5456f2c5
+```
+
+Result:
+```json
+{
+  "docID": "bae-ff3ceb1c-b5c0-5e86-a024-dd1b16a4261c",
+  "error": ""
+}
+```
+
+But, they still can not perform an update as they were only granted a read permission (through `reader` relation):
+```sh
+defradb client collection update --name Users --docID "bae-ff3ceb1c-b5c0-5e86-a024-dd1b16a4261c" \
+--identity 4d092126012ebaf56161716018a71630d99443d9d5217e9d8502bb5c5456f2c5 '{ "name": "SecretUpdatedShahzad" }'
+```
+
+Result:
+```sh
+Error: document not found or not authorized to access
+```
 
 ## DAC Usage HTTP:
 
diff --git a/acp/acp.go b/acp/acp.go
index 973181ae91..c7ae5936e6 100644
--- a/acp/acp.go
+++ b/acp/acp.go
@@ -99,6 +99,22 @@ type ACP interface {
 		docID string,
 	) (bool, error)
 
+	// AddDocActorRelationship creates a relationship between document and the target actor.
+	//
+	// If failure occurs, the result will return an error. Upon success the boolean value will
+	// be true if the relationship already existed (no-op), and false if a new relationship was made.
+	//
+	// Note: The request actor must either be the owner or manager of the document.
+	AddDocActorRelationship(
+		ctx context.Context,
+		policyID string,
+		resourceName string,
+		docID string,
+		relation string,
+		requestActor identity.Identity,
+		targetActor string,
+	) (bool, error)
+
 	// SupportsP2P returns true if the implementation supports ACP across a peer network.
 	SupportsP2P() bool
 }
diff --git a/acp/acp_local.go b/acp/acp_local.go
index 97e7a67cce..6e85ac9313 100644
--- a/acp/acp_local.go
+++ b/acp/acp_local.go
@@ -236,3 +236,34 @@ func (l *ACPLocal) VerifyAccessRequest(
 
 	return resp.Valid, nil
 }
+
+func (l *ACPLocal) AddActorRelationship(
+	ctx context.Context,
+	policyID string,
+	resourceName string,
+	objectID string,
+	relation string,
+	requester identity.Identity,
+	targetActor string,
+	creationTime *protoTypes.Timestamp,
+) (bool, error) {
+	principal, err := auth.NewDIDPrincipal(requester.DID)
+	if err != nil {
+		return false, newErrInvalidActorID(err, requester.DID)
+	}
+
+	ctx = auth.InjectPrincipal(ctx, principal)
+
+	setRelationshipRequest := types.SetRelationshipRequest{
+		PolicyId:     policyID,
+		Relationship: types.NewActorRelationship(resourceName, objectID, relation, targetActor),
+		CreationTime: creationTime,
+	}
+
+	setRelationshipResponse, err := l.engine.SetRelationship(ctx, &setRelationshipRequest)
+	if err != nil {
+		return false, err
+	}
+
+	return setRelationshipResponse.RecordExisted, nil
+}
diff --git a/acp/acp_local_test.go b/acp/acp_local_test.go
index 9dbf0b36e8..7b30b44cbb 100644
--- a/acp/acp_local_test.go
+++ b/acp/acp_local_test.go
@@ -663,6 +663,197 @@ func Test_LocalACP_PersistentMemory_CheckDocAccess_TrueIfHaveAccessFalseIfNotErr
 	require.Nil(t, errClose)
 }
 
+func Test_LocalACP_InMemory_AddDocActorRelationship_FalseIfExistsBeforeTrueIfNoOp(t *testing.T) {
+	ctx := context.Background()
+	localACP := NewLocalACP()
+
+	localACP.Init(ctx, "")
+	errStart := localACP.Start(ctx)
+	require.Nil(t, errStart)
+
+	policyID, errAddPolicy := localACP.AddPolicy(
+		ctx,
+		identity1,
+		validPolicy,
+	)
+	require.Nil(t, errAddPolicy)
+	require.Equal(
+		t,
+		validPolicyID,
+		policyID,
+	)
+
+	// Register a document.
+	errRegisterDoc := localACP.RegisterDocObject(
+		ctx,
+		identity1,
+		validPolicyID,
+		"users",
+		"documentID_XYZ",
+	)
+	require.Nil(t, errRegisterDoc)
+
+	// Other identity does not have access yet.
+	hasAccess, errCheckDocAccess := localACP.CheckDocAccess(
+		ctx,
+		ReadPermission,
+		identity2.DID,
+		validPolicyID,
+		"users",
+		"documentID_XYZ",
+	)
+	require.Nil(t, errCheckDocAccess)
+	require.False(t, hasAccess)
+
+	// Grant other identity access.
+	exists, errAddDocActorRelationship := localACP.AddDocActorRelationship(
+		ctx,
+		validPolicyID,
+		"users",
+		"documentID_XYZ",
+		"reader",
+		identity1,
+		identity2.DID,
+	)
+	require.Nil(t, errAddDocActorRelationship)
+	require.False(t, exists)
+
+	// Granting again will be no-op
+	exists, errAddDocActorRelationship = localACP.AddDocActorRelationship(
+		ctx,
+		validPolicyID,
+		"users",
+		"documentID_XYZ",
+		"reader",
+		identity1,
+		identity2.DID,
+	)
+	require.Nil(t, errAddDocActorRelationship)
+	require.True(t, exists) // Exists already this time
+
+	// Now the other identity has access.
+	hasAccess, errCheckDocAccess = localACP.CheckDocAccess(
+		ctx,
+		ReadPermission,
+		identity2.DID,
+		validPolicyID,
+		"users",
+		"documentID_XYZ",
+	)
+	require.Nil(t, errCheckDocAccess)
+	require.True(t, hasAccess)
+
+	errClose := localACP.Close()
+	require.Nil(t, errClose)
+}
+
+func Test_LocalACP_PersistentMemory_AddDocActorRelationship_FalseIfExistsBeforeTrueIfNoOp(t *testing.T) {
+	acpPath := t.TempDir()
+	require.NotEqual(t, "", acpPath)
+
+	ctx := context.Background()
+	localACP := NewLocalACP()
+
+	localACP.Init(ctx, acpPath)
+	errStart := localACP.Start(ctx)
+	require.Nil(t, errStart)
+
+	policyID, errAddPolicy := localACP.AddPolicy(
+		ctx,
+		identity1,
+		validPolicy,
+	)
+	require.Nil(t, errAddPolicy)
+	require.Equal(
+		t,
+		validPolicyID,
+		policyID,
+	)
+
+	// Register a document.
+	errRegisterDoc := localACP.RegisterDocObject(
+		ctx,
+		identity1,
+		validPolicyID,
+		"users",
+		"documentID_XYZ",
+	)
+	require.Nil(t, errRegisterDoc)
+
+	// Other identity does not have access yet.
+	hasAccess, errCheckDocAccess := localACP.CheckDocAccess(
+		ctx,
+		ReadPermission,
+		identity2.DID,
+		validPolicyID,
+		"users",
+		"documentID_XYZ",
+	)
+	require.Nil(t, errCheckDocAccess)
+	require.False(t, hasAccess)
+
+	// Grant other identity access.
+	exists, errAddDocActorRelationship := localACP.AddDocActorRelationship(
+		ctx,
+		validPolicyID,
+		"users",
+		"documentID_XYZ",
+		"reader",
+		identity1,
+		identity2.DID,
+	)
+	require.Nil(t, errAddDocActorRelationship)
+	require.False(t, exists)
+
+	// Granting again will be no-op
+	exists, errAddDocActorRelationship = localACP.AddDocActorRelationship(
+		ctx,
+		validPolicyID,
+		"users",
+		"documentID_XYZ",
+		"reader",
+		identity1,
+		identity2.DID,
+	)
+	require.Nil(t, errAddDocActorRelationship)
+	require.True(t, exists) // Exists already this time
+
+	// Now the other identity has access.
+	hasAccess, errCheckDocAccess = localACP.CheckDocAccess(
+		ctx,
+		ReadPermission,
+		identity2.DID,
+		validPolicyID,
+		"users",
+		"documentID_XYZ",
+	)
+	require.Nil(t, errCheckDocAccess)
+	require.True(t, hasAccess)
+
+	// Should continue having their correct behaviour and access even after a restart.
+	errClose := localACP.Close()
+	require.Nil(t, errClose)
+
+	localACP.Init(ctx, acpPath)
+	errStart = localACP.Start(ctx)
+	require.Nil(t, errStart)
+
+	// Now check again after the restart that the second identity still has access.
+	hasAccess, errCheckDocAccess = localACP.CheckDocAccess(
+		ctx,
+		ReadPermission,
+		identity2.DID,
+		validPolicyID,
+		"users",
+		"documentID_XYZ",
+	)
+	require.Nil(t, errCheckDocAccess)
+	require.True(t, hasAccess)
+
+	errClose = localACP.Close()
+	require.Nil(t, errClose)
+}
+
 func Test_LocalACP_InMemory_AddPolicy_InvalidCreatorIDReturnsError(t *testing.T) {
 	ctx := context.Background()
 	localACP := NewLocalACP()
@@ -684,6 +875,30 @@ func Test_LocalACP_InMemory_AddPolicy_InvalidCreatorIDReturnsError(t *testing.T)
 	require.NoError(t, err)
 }
 
+func Test_LocalACP_Persistent_AddPolicy_InvalidCreatorIDReturnsError(t *testing.T) {
+	acpPath := t.TempDir()
+	require.NotEqual(t, "", acpPath)
+
+	ctx := context.Background()
+	localACP := NewLocalACP()
+
+	localACP.Init(ctx, acpPath)
+	err := localACP.Start(ctx)
+	require.Nil(t, err)
+
+	policyID, err := localACP.AddPolicy(
+		ctx,
+		invalidIdentity,
+		validPolicy,
+	)
+
+	require.ErrorIs(t, err, ErrInvalidActorID)
+	require.Empty(t, policyID)
+
+	err = localACP.Close()
+	require.NoError(t, err)
+}
+
 func Test_LocalACP_InMemory_RegisterObject_InvalidCreatorIDReturnsError(t *testing.T) {
 	ctx := context.Background()
 	localACP := NewLocalACP()
@@ -706,7 +921,7 @@ func Test_LocalACP_InMemory_RegisterObject_InvalidCreatorIDReturnsError(t *testi
 	require.NoError(t, err)
 }
 
-func Test_LocalACP_Persistent_AddPolicy_InvalidCreatorIDReturnsError(t *testing.T) {
+func Test_LocalACP_Persistent_RegisterObject_InvalidCreatorIDReturnsError(t *testing.T) {
 	acpPath := t.TempDir()
 	require.NotEqual(t, "", acpPath)
 
@@ -717,20 +932,59 @@ func Test_LocalACP_Persistent_AddPolicy_InvalidCreatorIDReturnsError(t *testing.
 	err := localACP.Start(ctx)
 	require.Nil(t, err)
 
-	policyID, err := localACP.AddPolicy(
+	err = localACP.RegisterDocObject(
 		ctx,
 		invalidIdentity,
-		validPolicy,
+		validPolicyID,
+		"users",
+		"documentID_XYZ",
 	)
 
 	require.ErrorIs(t, err, ErrInvalidActorID)
-	require.Empty(t, policyID)
 
 	err = localACP.Close()
 	require.NoError(t, err)
 }
 
-func Test_LocalACP_Persistent_RegisterObject_InvalidCreatorIDReturnsError(t *testing.T) {
+func Test_LocalACP_InMemory_AddDocActorRelationship_InvalidIdentitiesReturnError(t *testing.T) {
+	ctx := context.Background()
+	localACP := NewLocalACP()
+
+	localACP.Init(ctx, "")
+	err := localACP.Start(ctx)
+	require.Nil(t, err)
+
+	// Invalid requesting identity.
+	exists, err := localACP.AddDocActorRelationship(
+		ctx,
+		validPolicyID,
+		"users",
+		"documentID_XYZ",
+		"reader",
+		invalidIdentity,
+		identity2.DID,
+	)
+	require.False(t, exists)
+	require.ErrorIs(t, err, ErrInvalidActorID)
+
+	// Invalid target actor.
+	exists, err = localACP.AddDocActorRelationship(
+		ctx,
+		validPolicyID,
+		"users",
+		"documentID_XYZ",
+		"reader",
+		identity1,
+		invalidIdentity.DID,
+	)
+	require.False(t, exists)
+	require.ErrorIs(t, err, ErrFailedToAddDocActorRelationshipWithACP)
+
+	err = localACP.Close()
+	require.NoError(t, err)
+}
+
+func Test_LocalACP_Persistent_AddDocActorRelationship_InvalidIdentitiesReturnError(t *testing.T) {
 	acpPath := t.TempDir()
 	require.NotEqual(t, "", acpPath)
 
@@ -741,16 +995,32 @@ func Test_LocalACP_Persistent_RegisterObject_InvalidCreatorIDReturnsError(t *tes
 	err := localACP.Start(ctx)
 	require.Nil(t, err)
 
-	err = localACP.RegisterDocObject(
+	// Invalid requesting identity.
+	exists, err := localACP.AddDocActorRelationship(
 		ctx,
-		invalidIdentity,
 		validPolicyID,
 		"users",
 		"documentID_XYZ",
+		"reader",
+		invalidIdentity,
+		identity2.DID,
 	)
-
+	require.False(t, exists)
 	require.ErrorIs(t, err, ErrInvalidActorID)
 
+	// Invalid target actor.
+	exists, err = localACP.AddDocActorRelationship(
+		ctx,
+		validPolicyID,
+		"users",
+		"documentID_XYZ",
+		"reader",
+		identity1,
+		invalidIdentity.DID,
+	)
+	require.False(t, exists)
+	require.ErrorIs(t, err, ErrFailedToAddDocActorRelationshipWithACP)
+
 	err = localACP.Close()
 	require.NoError(t, err)
 }
diff --git a/acp/acp_source_hub.go b/acp/acp_source_hub.go
index 4dfb26c090..d0c4fb6b89 100644
--- a/acp/acp_source_hub.go
+++ b/acp/acp_source_hub.go
@@ -261,3 +261,53 @@ func (a *acpSourceHub) VerifyAccessRequest(
 func (a *acpSourceHub) Close() error {
 	return nil
 }
+
+func (a *acpSourceHub) AddActorRelationship(
+	ctx context.Context,
+	policyID string,
+	resourceName string,
+	objectID string,
+	relation string,
+	requester identity.Identity,
+	targetActor string,
+	creationTime *protoTypes.Timestamp,
+) (bool, error) {
+	msgSet := sourcehub.MsgSet{}
+	cmdMapper := msgSet.WithBearerPolicyCmd(&acptypes.MsgBearerPolicyCmd{
+		Creator:     a.signer.GetAccAddress(),
+		BearerToken: requester.BearerToken,
+		PolicyId:    policyID,
+		Cmd: acptypes.NewSetRelationshipCmd(
+			acptypes.NewActorRelationship(
+				resourceName,
+				objectID,
+				relation,
+				targetActor,
+			),
+		),
+		CreationTime: creationTime,
+	})
+	tx, err := a.txBuilder.Build(ctx, a.signer, &msgSet)
+	if err != nil {
+		return false, err
+	}
+	resp, err := a.client.BroadcastTx(ctx, tx)
+	if err != nil {
+		return false, err
+	}
+
+	result, err := a.client.AwaitTx(ctx, resp.TxHash)
+	if err != nil {
+		return false, err
+	}
+	if result.Error() != nil {
+		return false, result.Error()
+	}
+
+	cmdResult, err := cmdMapper.Map(result.TxPayload())
+	if err != nil {
+		return false, err
+	}
+
+	return cmdResult.GetResult().GetSetRelationshipResult().RecordExisted, nil
+}
diff --git a/acp/errors.go b/acp/errors.go
index 5ff4eee302..e0717f15dd 100644
--- a/acp/errors.go
+++ b/acp/errors.go
@@ -15,12 +15,14 @@ import (
 )
 
 const (
-	errInitializationOfACPFailed             = "initialization of acp failed"
-	errStartingACPInEmptyPath                = "starting acp in an empty path"
-	errFailedToAddPolicyWithACP              = "failed to add policy with acp"
-	errFailedToRegisterDocWithACP            = "failed to register document with acp"
-	errFailedToCheckIfDocIsRegisteredWithACP = "failed to check if doc is registered with acp"
-	errFailedToVerifyDocAccessWithACP        = "failed to verify doc access with acp"
+	errInitializationOfACPFailed                   = "initialization of acp failed"
+	errStartingACPInEmptyPath                      = "starting acp in an empty path"
+	errFailedToAddPolicyWithACP                    = "failed to add policy with acp"
+	errFailedToRegisterDocWithACP                  = "failed to register document with acp"
+	errFailedToCheckIfDocIsRegisteredWithACP       = "failed to check if doc is registered with acp"
+	errFailedToVerifyDocAccessWithACP              = "failed to verify doc access with acp"
+	errFailedToAddDocActorRelationshipWithACP      = "failed to add document actor relationship with acp"
+	errMissingRequiredArgToAddDocActorRelationship = "missing a required argument needed to add doc actor relationship"
 
 	errObjectDidNotRegister = "no-op while registering object (already exists or error) with acp"
 	errNoPolicyArgs         = "missing policy arguments, must have both id and resource"
@@ -40,12 +42,13 @@ const (
 )
 
 var (
-	ErrInitializationOfACPFailed             = errors.New(errInitializationOfACPFailed)
-	ErrFailedToAddPolicyWithACP              = errors.New(errFailedToAddPolicyWithACP)
-	ErrFailedToRegisterDocWithACP            = errors.New(errFailedToRegisterDocWithACP)
-	ErrFailedToCheckIfDocIsRegisteredWithACP = errors.New(errFailedToCheckIfDocIsRegisteredWithACP)
-	ErrFailedToVerifyDocAccessWithACP        = errors.New(errFailedToVerifyDocAccessWithACP)
-	ErrPolicyDoesNotExistWithACP             = errors.New(errPolicyDoesNotExistWithACP)
+	ErrInitializationOfACPFailed              = errors.New(errInitializationOfACPFailed)
+	ErrFailedToAddPolicyWithACP               = errors.New(errFailedToAddPolicyWithACP)
+	ErrFailedToRegisterDocWithACP             = errors.New(errFailedToRegisterDocWithACP)
+	ErrFailedToCheckIfDocIsRegisteredWithACP  = errors.New(errFailedToCheckIfDocIsRegisteredWithACP)
+	ErrFailedToVerifyDocAccessWithACP         = errors.New(errFailedToVerifyDocAccessWithACP)
+	ErrFailedToAddDocActorRelationshipWithACP = errors.New(errFailedToAddDocActorRelationshipWithACP)
+	ErrPolicyDoesNotExistWithACP              = errors.New(errPolicyDoesNotExistWithACP)
 
 	ErrResourceDoesNotExistOnTargetPolicy = errors.New(errResourceDoesNotExistOnTargetPolicy)
 
@@ -139,6 +142,29 @@ func NewErrFailedToVerifyDocAccessWithACP(
 	)
 }
 
+func NewErrFailedToAddDocActorRelationshipWithACP(
+	inner error,
+	Type string,
+	policyID string,
+	resourceName string,
+	docID string,
+	relation string,
+	requestActor string,
+	targetActor string,
+) error {
+	return errors.Wrap(
+		errFailedToAddDocActorRelationshipWithACP,
+		inner,
+		errors.NewKV("Type", Type),
+		errors.NewKV("PolicyID", policyID),
+		errors.NewKV("ResourceName", resourceName),
+		errors.NewKV("DocID", docID),
+		errors.NewKV("Relation", relation),
+		errors.NewKV("RequestActor", requestActor),
+		errors.NewKV("TargetActor", targetActor),
+	)
+}
+
 func newErrPolicyDoesNotExistWithACP(
 	inner error,
 	policyID string,
@@ -209,6 +235,25 @@ func newErrExprOfRequiredPermissionHasInvalidChar(
 	)
 }
 
+func NewErrMissingRequiredArgToAddDocActorRelationship(
+	policyID string,
+	resourceName string,
+	docID string,
+	relation string,
+	requestActor string,
+	targetActor string,
+) error {
+	return errors.New(
+		errMissingRequiredArgToAddDocActorRelationship,
+		errors.NewKV("PolicyID", policyID),
+		errors.NewKV("ResourceName", resourceName),
+		errors.NewKV("DocID", docID),
+		errors.NewKV("Relation", relation),
+		errors.NewKV("RequestActor", requestActor),
+		errors.NewKV("TargetActor", targetActor),
+	)
+}
+
 func newErrInvalidActorID(
 	inner error,
 	id string,
diff --git a/acp/source_hub_client.go b/acp/source_hub_client.go
index 0bf344afb8..0bfbae72b1 100644
--- a/acp/source_hub_client.go
+++ b/acp/source_hub_client.go
@@ -85,6 +85,27 @@ type sourceHubClient interface {
 		docID string,
 	) (bool, error)
 
+	// AddActorRelationship creates a relationship within a policy which ties the target actor
+	// with the specified object, which means that the set of high level rules defined in the
+	// policy will now apply to target actor as well.
+	//
+	// If failure occurs, the result will return an error. Upon success the boolean value will
+	// be true if the relationship with actor already existed (no-op), and false if a new
+	// relationship was made.
+	//
+	// Note: The requester identity must either be the owner of the object (being shared) or
+	//       the manager (i.e. the relation has `manages` defined in the policy).
+	AddActorRelationship(
+		ctx context.Context,
+		policyID string,
+		resourceName string,
+		objectID string,
+		relation string,
+		requester identity.Identity,
+		targetActor string,
+		creationTime *protoTypes.Timestamp,
+	) (bool, error)
+
 	// Close closes any resources in use by acp.
 	Close() error
 }
@@ -335,6 +356,70 @@ func (a *sourceHubBridge) CheckDocAccess(
 	}
 }
 
+func (a *sourceHubBridge) AddDocActorRelationship(
+	ctx context.Context,
+	policyID string,
+	resourceName string,
+	docID string,
+	relation string,
+	requestActor identity.Identity,
+	targetActor string,
+) (bool, error) {
+	if policyID == "" ||
+		resourceName == "" ||
+		docID == "" ||
+		relation == "" ||
+		requestActor == (identity.Identity{}) ||
+		targetActor == "" {
+		return false, NewErrMissingRequiredArgToAddDocActorRelationship(
+			policyID,
+			resourceName,
+			docID,
+			relation,
+			requestActor.DID,
+			targetActor,
+		)
+	}
+
+	exists, err := a.client.AddActorRelationship(
+		ctx,
+		policyID,
+		resourceName,
+		docID,
+		relation,
+		requestActor,
+		targetActor,
+		protoTypes.TimestampNow(),
+	)
+
+	if err != nil {
+		return false, NewErrFailedToAddDocActorRelationshipWithACP(
+			err,
+			"Local",
+			policyID,
+			resourceName,
+			docID,
+			relation,
+			requestActor.DID,
+			targetActor,
+		)
+	}
+
+	log.InfoContext(
+		ctx,
+		"Document and actor relationship set",
+		corelog.Any("PolicyID", policyID),
+		corelog.Any("ResourceName", resourceName),
+		corelog.Any("DocID", docID),
+		corelog.Any("Relation", relation),
+		corelog.Any("RequestActor", requestActor.DID),
+		corelog.Any("TargetActor", targetActor),
+		corelog.Any("Existed", exists),
+	)
+
+	return exists, nil
+}
+
 func (a *sourceHubBridge) SupportsP2P() bool {
 	_, ok := a.client.(*acpSourceHub)
 	return ok
diff --git a/cli/acp_relationship.go b/cli/acp_relationship.go
new file mode 100644
index 0000000000..a2a5f3cb64
--- /dev/null
+++ b/cli/acp_relationship.go
@@ -0,0 +1,25 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package cli
+
+import (
+	"github.com/spf13/cobra"
+)
+
+func MakeACPRelationshipCommand() *cobra.Command {
+	var cmd = &cobra.Command{
+		Use:   "relationship",
+		Short: "Interact with the acp relationship features of DefraDB instance",
+		Long:  `Interact with the acp relationship features of DefraDB instance`,
+	}
+
+	return cmd
+}
diff --git a/cli/acp_relationship_add.go b/cli/acp_relationship_add.go
new file mode 100644
index 0000000000..9733732af8
--- /dev/null
+++ b/cli/acp_relationship_add.go
@@ -0,0 +1,130 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package cli
+
+import (
+	"github.com/spf13/cobra"
+)
+
+func MakeACPRelationshipAddCommand() *cobra.Command {
+	const (
+		collectionFlagLong  string = "collection"
+		collectionFlagShort string = "c"
+
+		relationFlagLong  string = "relation"
+		relationFlagShort string = "r"
+
+		targetActorFlagLong  string = "actor"
+		targetActorFlagShort string = "a"
+
+		docIDFlag string = "docID"
+	)
+
+	var (
+		collectionArg  string
+		relationArg    string
+		targetActorArg string
+		docIDArg       string
+	)
+
+	var cmd = &cobra.Command{
+		Use:   "add [--docID] [-c --collection] [-r --relation] [-a --actor] [-i --identity]",
+		Short: "Add new relationship",
+		Long: `Add new relationship
+
+To share a document (or grant a more restricted access) with another actor, we must add a relationship between the
+actor and the document. Inorder to make the relationship we require all of the following:
+1) Target DocID: The docID of the document we want to make a relationship for.
+2) Collection Name: The name of the collection that has the Target DocID.
+3) Relation Name: The type of relation (name must be defined within the linked policy on collection).
+4) Target Identity: The identity of the actor the relationship is being made with.
+5) Requesting Identity: The identity of the actor that is making the request.
+
+Notes:
+  - ACP must be available (i.e. ACP can not be disabled).
+  - The target document must be registered with ACP already (policy & resource specified).
+  - The requesting identity MUST either be the owner OR the manager (manages the relation) of the resource.
+  - If the specified relation was not granted the miminum DPI permissions (read or write) within the policy,
+  and a relationship is formed, the subject/actor will still not be able to access (read or write) the resource.
+  - Learn more about [ACP & DPI Rules](/acp/README.md)
+
+Example: Let another actor (4d092126012ebaf56161716018a71630d99443d9d5217e9d8502bb5c5456f2c5) read a private document:
+  defradb client acp relationship add \
+	--collection Users \
+	--docID bae-ff3ceb1c-b5c0-5e86-a024-dd1b16a4261c \
+	--relation reader \
+	--actor did:key:z7r8os2G88XXBNBTLj3kFR5rzUJ4VAesbX7PgsA68ak9B5RYcXF5EZEmjRzzinZndPSSwujXb4XKHG6vmKEFG6ZfsfcQn \
+	--identity e3b722906ee4e56368f581cd8b18ab0f48af1ea53e635e3f7b8acd076676f6ac
+
+Example: Creating a dummy relationship does nothing (from database prespective):
+  defradb client acp relationship add \
+	-c Users \
+	--docID bae-ff3ceb1c-b5c0-5e86-a024-dd1b16a4261c \
+	-r dummy \
+	-a did:key:z7r8os2G88XXBNBTLj3kFR5rzUJ4VAesbX7PgsA68ak9B5RYcXF5EZEmjRzzinZndPSSwujXb4XKHG6vmKEFG6ZfsfcQn \
+	-i e3b722906ee4e56368f581cd8b18ab0f48af1ea53e635e3f7b8acd076676f6ac
+`,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			db := mustGetContextDB(cmd)
+			exists, err := db.AddDocActorRelationship(
+				cmd.Context(),
+				collectionArg,
+				docIDArg,
+				relationArg,
+				targetActorArg,
+			)
+
+			if err != nil {
+				return err
+			}
+
+			return writeJSON(cmd, exists)
+		},
+	}
+
+	cmd.Flags().StringVarP(
+		&collectionArg,
+		collectionFlagLong,
+		collectionFlagShort,
+		"",
+		"Collection that has the resource and policy for object",
+	)
+	_ = cmd.MarkFlagRequired(collectionFlagLong)
+
+	cmd.Flags().StringVarP(
+		&relationArg,
+		relationFlagLong,
+		relationFlagShort,
+		"",
+		"Relation that needs to be set for the relationship",
+	)
+	_ = cmd.MarkFlagRequired(relationFlagLong)
+
+	cmd.Flags().StringVarP(
+		&targetActorArg,
+		targetActorFlagLong,
+		targetActorFlagShort,
+		"",
+		"Actor to add relationship with",
+	)
+	_ = cmd.MarkFlagRequired(targetActorFlagLong)
+
+	cmd.Flags().StringVarP(
+		&docIDArg,
+		docIDFlag,
+		"",
+		"",
+		"Document Identifier (ObjectID) to make relationship for",
+	)
+	_ = cmd.MarkFlagRequired(docIDFlag)
+
+	return cmd
+}
diff --git a/cli/cli.go b/cli/cli.go
index 4453cbaafb..61d1fd51cf 100644
--- a/cli/cli.go
+++ b/cli/cli.go
@@ -62,14 +62,20 @@ func NewDefraCommand() *cobra.Command {
 		schema_migrate,
 	)
 
-	policy := MakeACPPolicyCommand()
-	policy.AddCommand(
+	acp_policy := MakeACPPolicyCommand()
+	acp_policy.AddCommand(
 		MakeACPPolicyAddCommand(),
 	)
 
+	acp_relationship := MakeACPRelationshipCommand()
+	acp_relationship.AddCommand(
+		MakeACPRelationshipAddCommand(),
+	)
+
 	acp := MakeACPCommand()
 	acp.AddCommand(
-		policy,
+		acp_policy,
+		acp_relationship,
 	)
 
 	view := MakeViewCommand()
diff --git a/client/policy.go b/client/acp.go
similarity index 80%
rename from client/policy.go
rename to client/acp.go
index 5b877696c2..7795369c8f 100644
--- a/client/policy.go
+++ b/client/acp.go
@@ -29,3 +29,10 @@ type AddPolicyResult struct {
 	// upon successful creation of a policy.
 	PolicyID string
 }
+
+// AddDocActorRelationshipResult wraps the result of making a document-actor relationship.
+type AddDocActorRelationshipResult struct {
+	// ExistedAlready is true if the relationship existed already (no-op), and
+	// it is false if a new relationship was created.
+	ExistedAlready bool
+}
diff --git a/client/db.go b/client/db.go
index b8f5e91e35..e28d21df02 100644
--- a/client/db.go
+++ b/client/db.go
@@ -106,6 +106,20 @@ type DB interface {
 	//
 	// Note: A policy can not be added without the creatorID (identity).
 	AddPolicy(ctx context.Context, policy string) (AddPolicyResult, error)
+
+	// AddDocActorRelationship creates a relationship between document and the target actor.
+	//
+	// If failure occurs, the result will return an error. Upon success the boolean value will
+	// be true if the relationship already existed (no-op), and false if a new relationship was made.
+	//
+	// Note: The request actor must either be the owner or manager of the document.
+	AddDocActorRelationship(
+		ctx context.Context,
+		collectionName string,
+		docID string,
+		relation string,
+		targetActor string,
+	) (AddDocActorRelationshipResult, error)
 }
 
 // Store contains the core DefraDB read-write operations.
diff --git a/client/errors.go b/client/errors.go
index 866ad98ec4..ceb526b35e 100644
--- a/client/errors.go
+++ b/client/errors.go
@@ -41,25 +41,26 @@ const (
 // This list is incomplete and undefined errors may also be returned.
 // Errors returned from this package may be tested against these errors with errors.Is.
 var (
-	ErrFieldNotExist                       = errors.New(errFieldNotExist)
-	ErrUnexpectedType                      = errors.New(errUnexpectedType)
-	ErrFailedToUnmarshalCollection         = errors.New(errFailedToUnmarshalCollection)
-	ErrOperationNotPermittedOnNamelessCols = errors.New(errOperationNotPermittedOnNamelessCols)
-	ErrFieldNotObject                      = errors.New("trying to access field on a non object type")
-	ErrValueTypeMismatch                   = errors.New("value does not match indicated type")
-	ErrDocumentNotFoundOrNotAuthorized     = errors.New("document not found or not authorized to access")
-	ErrPolicyAddFailureNoACP               = errors.New("failure adding policy because ACP was not available")
-	ErrInvalidUpdateTarget                 = errors.New("the target document to update is of invalid type")
-	ErrInvalidUpdater                      = errors.New("the updater of a document is of invalid type")
-	ErrInvalidDeleteTarget                 = errors.New("the target document to delete is of invalid type")
-	ErrMalformedDocID                      = errors.New("malformed document ID, missing either version or cid")
-	ErrInvalidDocIDVersion                 = errors.New("invalid document ID version")
-	ErrInvalidJSONPayload                  = errors.New(errInvalidJSONPayload)
-	ErrCanNotNormalizeValue                = errors.New(errCanNotNormalizeValue)
-	ErrCanNotTurnNormalValueIntoArray      = errors.New(errCanNotTurnNormalValueIntoArray)
-	ErrCanNotMakeNormalNilFromFieldKind    = errors.New(errCanNotMakeNormalNilFromFieldKind)
-	ErrCollectionNotFound                  = errors.New(errCollectionNotFound)
-	ErrFailedToParseKind                   = errors.New(errFailedToParseKind)
+	ErrFieldNotExist                        = errors.New(errFieldNotExist)
+	ErrUnexpectedType                       = errors.New(errUnexpectedType)
+	ErrFailedToUnmarshalCollection          = errors.New(errFailedToUnmarshalCollection)
+	ErrOperationNotPermittedOnNamelessCols  = errors.New(errOperationNotPermittedOnNamelessCols)
+	ErrFieldNotObject                       = errors.New("trying to access field on a non object type")
+	ErrValueTypeMismatch                    = errors.New("value does not match indicated type")
+	ErrDocumentNotFoundOrNotAuthorized      = errors.New("document not found or not authorized to access")
+	ErrACPOperationButACPNotAvailable       = errors.New("operation requires ACP, but ACP not available")
+	ErrACPOperationButCollectionHasNoPolicy = errors.New("operation requires ACP, but collection has no policy")
+	ErrInvalidUpdateTarget                  = errors.New("the target document to update is of invalid type")
+	ErrInvalidUpdater                       = errors.New("the updater of a document is of invalid type")
+	ErrInvalidDeleteTarget                  = errors.New("the target document to delete is of invalid type")
+	ErrMalformedDocID                       = errors.New("malformed document ID, missing either version or cid")
+	ErrInvalidDocIDVersion                  = errors.New("invalid document ID version")
+	ErrInvalidJSONPayload                   = errors.New(errInvalidJSONPayload)
+	ErrCanNotNormalizeValue                 = errors.New(errCanNotNormalizeValue)
+	ErrCanNotTurnNormalValueIntoArray       = errors.New(errCanNotTurnNormalValueIntoArray)
+	ErrCanNotMakeNormalNilFromFieldKind     = errors.New(errCanNotMakeNormalNilFromFieldKind)
+	ErrCollectionNotFound                   = errors.New(errCollectionNotFound)
+	ErrFailedToParseKind                    = errors.New(errFailedToParseKind)
 )
 
 // NewErrFieldNotExist returns an error indicating that the given field does not exist.
diff --git a/client/mocks/db.go b/client/mocks/db.go
index 8923e63d78..1297870e15 100644
--- a/client/mocks/db.go
+++ b/client/mocks/db.go
@@ -35,6 +35,66 @@ func (_m *DB) EXPECT() *DB_Expecter {
 	return &DB_Expecter{mock: &_m.Mock}
 }
 
+// AddDocActorRelationship provides a mock function with given fields: ctx, collectionName, docID, relation, targetActor
+func (_m *DB) AddDocActorRelationship(ctx context.Context, collectionName string, docID string, relation string, targetActor string) (client.AddDocActorRelationshipResult, error) {
+	ret := _m.Called(ctx, collectionName, docID, relation, targetActor)
+
+	if len(ret) == 0 {
+		panic("no return value specified for AddDocActorRelationship")
+	}
+
+	var r0 client.AddDocActorRelationshipResult
+	var r1 error
+	if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) (client.AddDocActorRelationshipResult, error)); ok {
+		return rf(ctx, collectionName, docID, relation, targetActor)
+	}
+	if rf, ok := ret.Get(0).(func(context.Context, string, string, string, string) client.AddDocActorRelationshipResult); ok {
+		r0 = rf(ctx, collectionName, docID, relation, targetActor)
+	} else {
+		r0 = ret.Get(0).(client.AddDocActorRelationshipResult)
+	}
+
+	if rf, ok := ret.Get(1).(func(context.Context, string, string, string, string) error); ok {
+		r1 = rf(ctx, collectionName, docID, relation, targetActor)
+	} else {
+		r1 = ret.Error(1)
+	}
+
+	return r0, r1
+}
+
+// DB_AddDocActorRelationship_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'AddDocActorRelationship'
+type DB_AddDocActorRelationship_Call struct {
+	*mock.Call
+}
+
+// AddDocActorRelationship is a helper method to define mock.On call
+//   - ctx context.Context
+//   - collectionName string
+//   - docID string
+//   - relation string
+//   - targetActor string
+func (_e *DB_Expecter) AddDocActorRelationship(ctx interface{}, collectionName interface{}, docID interface{}, relation interface{}, targetActor interface{}) *DB_AddDocActorRelationship_Call {
+	return &DB_AddDocActorRelationship_Call{Call: _e.mock.On("AddDocActorRelationship", ctx, collectionName, docID, relation, targetActor)}
+}
+
+func (_c *DB_AddDocActorRelationship_Call) Run(run func(ctx context.Context, collectionName string, docID string, relation string, targetActor string)) *DB_AddDocActorRelationship_Call {
+	_c.Call.Run(func(args mock.Arguments) {
+		run(args[0].(context.Context), args[1].(string), args[2].(string), args[3].(string), args[4].(string))
+	})
+	return _c
+}
+
+func (_c *DB_AddDocActorRelationship_Call) Return(_a0 client.AddDocActorRelationshipResult, _a1 error) *DB_AddDocActorRelationship_Call {
+	_c.Call.Return(_a0, _a1)
+	return _c
+}
+
+func (_c *DB_AddDocActorRelationship_Call) RunAndReturn(run func(context.Context, string, string, string, string) (client.AddDocActorRelationshipResult, error)) *DB_AddDocActorRelationship_Call {
+	_c.Call.Return(run)
+	return _c
+}
+
 // AddP2PCollections provides a mock function with given fields: ctx, collectionIDs
 func (_m *DB) AddP2PCollections(ctx context.Context, collectionIDs []string) error {
 	ret := _m.Called(ctx, collectionIDs)
diff --git a/docs/website/references/cli/defradb_client_acp.md b/docs/website/references/cli/defradb_client_acp.md
index 5a9c9aef80..d2ffce5036 100644
--- a/docs/website/references/cli/defradb_client_acp.md
+++ b/docs/website/references/cli/defradb_client_acp.md
@@ -42,4 +42,5 @@ Learn more about [ACP](/acp/README.md)
 
 * [defradb client](defradb_client.md)	 - Interact with a DefraDB node
 * [defradb client acp policy](defradb_client_acp_policy.md)	 - Interact with the acp policy features of DefraDB instance
+* [defradb client acp relationship](defradb_client_acp_relationship.md)	 - Interact with the acp relationship features of DefraDB instance
 
diff --git a/docs/website/references/cli/defradb_client_acp_relationship.md b/docs/website/references/cli/defradb_client_acp_relationship.md
new file mode 100644
index 0000000000..4c204d0ccd
--- /dev/null
+++ b/docs/website/references/cli/defradb_client_acp_relationship.md
@@ -0,0 +1,41 @@
+## defradb client acp relationship
+
+Interact with the acp relationship features of DefraDB instance
+
+### Synopsis
+
+Interact with the acp relationship features of DefraDB instance
+
+### Options
+
+```
+  -h, --help   help for relationship
+```
+
+### Options inherited from parent commands
+
+```
+  -i, --identity string             Hex formatted private key used to authenticate with ACP
+      --keyring-backend string      Keyring backend to use. Options are file or system (default "file")
+      --keyring-namespace string    Service name to use when using the system backend (default "defradb")
+      --keyring-path string         Path to store encrypted keys when using the file backend (default "keys")
+      --log-format string           Log format to use. Options are text or json (default "text")
+      --log-level string            Log level to use. Options are debug, info, error, fatal (default "info")
+      --log-output string           Log output path. Options are stderr or stdout. (default "stderr")
+      --log-overrides string        Logger config overrides. Format <name>,<key>=<val>,...;<name>,...
+      --log-source                  Include source location in logs
+      --log-stacktrace              Include stacktrace in error and fatal logs
+      --no-keyring                  Disable the keyring and generate ephemeral keys
+      --no-log-color                Disable colored log output
+      --rootdir string              Directory for persistent data (default: $HOME/.defradb)
+      --secret-file string          Path to the file containing secrets (default ".env")
+      --source-hub-address string   The SourceHub address authorized by the client to make SourceHub transactions on behalf of the actor
+      --tx uint                     Transaction ID
+      --url string                  URL of HTTP endpoint to listen on or connect to (default "127.0.0.1:9181")
+```
+
+### SEE ALSO
+
+* [defradb client acp](defradb_client_acp.md)	 - Interact with the access control system of a DefraDB node
+* [defradb client acp relationship add](defradb_client_acp_relationship_add.md)	 - Add new relationship
+
diff --git a/docs/website/references/cli/defradb_client_acp_relationship_add.md b/docs/website/references/cli/defradb_client_acp_relationship_add.md
new file mode 100644
index 0000000000..ba5647c163
--- /dev/null
+++ b/docs/website/references/cli/defradb_client_acp_relationship_add.md
@@ -0,0 +1,81 @@
+## defradb client acp relationship add
+
+Add new relationship
+
+### Synopsis
+
+Add new relationship
+
+To share a document (or grant a more restricted access) with another actor, we must add a relationship between the
+actor and the document. Inorder to make the relationship we require all of the following:
+1) Target DocID: The docID of the document we want to make a relationship for.
+2) Collection Name: The name of the collection that has the Target DocID.
+3) Relation Name: The type of relation (name must be defined within the linked policy on collection).
+4) Target Identity: The identity of the actor the relationship is being made with.
+5) Requesting Identity: The identity of the actor that is making the request.
+
+Notes:
+  - ACP must be available (i.e. ACP can not be disabled).
+  - The target document must be registered with ACP already (policy & resource specified).
+  - The requesting identity MUST either be the owner OR the manager (manages the relation) of the resource.
+  - If the specified relation was not granted the miminum DPI permissions (read or write) within the policy,
+  and a relationship is formed, the subject/actor will still not be able to access (read or write) the resource.
+  - Learn more about [ACP & DPI Rules](/acp/README.md)
+
+Example: Let another actor (4d092126012ebaf56161716018a71630d99443d9d5217e9d8502bb5c5456f2c5) read a private document:
+  defradb client acp relationship add \
+	--collection Users \
+	--docID bae-ff3ceb1c-b5c0-5e86-a024-dd1b16a4261c \
+	--relation reader \
+	--actor did:key:z7r8os2G88XXBNBTLj3kFR5rzUJ4VAesbX7PgsA68ak9B5RYcXF5EZEmjRzzinZndPSSwujXb4XKHG6vmKEFG6ZfsfcQn \
+	--identity e3b722906ee4e56368f581cd8b18ab0f48af1ea53e635e3f7b8acd076676f6ac
+
+Example: Creating a dummy relationship does nothing (from database prespective):
+  defradb client acp relationship add \
+	-c Users \
+	--docID bae-ff3ceb1c-b5c0-5e86-a024-dd1b16a4261c \
+	-r dummy \
+	-a did:key:z7r8os2G88XXBNBTLj3kFR5rzUJ4VAesbX7PgsA68ak9B5RYcXF5EZEmjRzzinZndPSSwujXb4XKHG6vmKEFG6ZfsfcQn \
+	-i e3b722906ee4e56368f581cd8b18ab0f48af1ea53e635e3f7b8acd076676f6ac
+
+
+```
+defradb client acp relationship add [--docID] [-c --collection] [-r --relation] [-a --actor] [-i --identity] [flags]
+```
+
+### Options
+
+```
+  -a, --actor string        Actor to add relationship with
+  -c, --collection string   Collection that has the resource and policy for object
+      --docID string        Document Identifier (ObjectID) to make relationship for
+  -h, --help                help for add
+  -r, --relation string     Relation that needs to be set for the relationship
+```
+
+### Options inherited from parent commands
+
+```
+  -i, --identity string             Hex formatted private key used to authenticate with ACP
+      --keyring-backend string      Keyring backend to use. Options are file or system (default "file")
+      --keyring-namespace string    Service name to use when using the system backend (default "defradb")
+      --keyring-path string         Path to store encrypted keys when using the file backend (default "keys")
+      --log-format string           Log format to use. Options are text or json (default "text")
+      --log-level string            Log level to use. Options are debug, info, error, fatal (default "info")
+      --log-output string           Log output path. Options are stderr or stdout. (default "stderr")
+      --log-overrides string        Logger config overrides. Format <name>,<key>=<val>,...;<name>,...
+      --log-source                  Include source location in logs
+      --log-stacktrace              Include stacktrace in error and fatal logs
+      --no-keyring                  Disable the keyring and generate ephemeral keys
+      --no-log-color                Disable colored log output
+      --rootdir string              Directory for persistent data (default: $HOME/.defradb)
+      --secret-file string          Path to the file containing secrets (default ".env")
+      --source-hub-address string   The SourceHub address authorized by the client to make SourceHub transactions on behalf of the actor
+      --tx uint                     Transaction ID
+      --url string                  URL of HTTP endpoint to listen on or connect to (default "127.0.0.1:9181")
+```
+
+### SEE ALSO
+
+* [defradb client acp relationship](defradb_client_acp_relationship.md)	 - Interact with the acp relationship features of DefraDB instance
+
diff --git a/docs/website/references/http/openapi.json b/docs/website/references/http/openapi.json
index 6b7686c7c1..c0a7898364 100644
--- a/docs/website/references/http/openapi.json
+++ b/docs/website/references/http/openapi.json
@@ -588,6 +588,36 @@
                 ]
             }
         },
+        "/acp/relationship": {
+            "post": {
+                "description": "Add an actor relationship using acp system",
+                "operationId": "add relationship",
+                "requestBody": {
+                    "content": {
+                        "text/plain": {
+                            "schema": {
+                                "type": "string"
+                            }
+                        }
+                    },
+                    "required": true
+                },
+                "responses": {
+                    "200": {
+                        "$ref": "#/components/responses/success"
+                    },
+                    "400": {
+                        "$ref": "#/components/responses/error"
+                    },
+                    "default": {
+                        "description": ""
+                    }
+                },
+                "tags": [
+                    "acp_relationship"
+                ]
+            }
+        },
         "/backup/export": {
             "post": {
                 "description": "Export a database backup to file",
diff --git a/examples/dpi_policy/user_dpi_policy.json b/examples/dpi_policy/user_dpi_policy.json
index 74028d8ee6..96c794b490 100644
--- a/examples/dpi_policy/user_dpi_policy.json
+++ b/examples/dpi_policy/user_dpi_policy.json
@@ -1,4 +1,5 @@
 {
+  "name": "An Example Policy",
   "description": "A Valid Defra Policy Interface (DPI)",
   "actor": {
     "name": "actor"
diff --git a/examples/dpi_policy/user_dpi_policy.yml b/examples/dpi_policy/user_dpi_policy.yml
index fafae06957..1b1df1e0b9 100644
--- a/examples/dpi_policy/user_dpi_policy.yml
+++ b/examples/dpi_policy/user_dpi_policy.yml
@@ -7,6 +7,8 @@
 #
 # Learn more about the DefraDB Policy Interface [DPI](/acp/README.md)
 
+name: An Example Policy
+
 description: A Valid DefraDB Policy Interface (DPI)
 
 actor:
diff --git a/examples/dpi_policy/user_dpi_policy_with_manages.yml b/examples/dpi_policy/user_dpi_policy_with_manages.yml
new file mode 100644
index 0000000000..4667660136
--- /dev/null
+++ b/examples/dpi_policy/user_dpi_policy_with_manages.yml
@@ -0,0 +1,49 @@
+# The below policy contains an example with valid DPI compliant resource that can be linked to a collection
+# object during the schema add command to have access control enabled for documents of that collection.
+#
+# This policy specifically has the manages attribute defined under admin relation which gives admin
+# of a resource, the ability to add/remove relationships with `reader` relation name.
+#
+# Learn more about the DefraDB Policy Interface [DPI](/acp/README.md)
+
+name: An Example Policy
+
+description: A Policy
+
+actor:
+  name: actor
+
+resources:
+  users:
+    permissions:
+      read:
+        expr: owner + reader + writer
+
+      write:
+        expr: owner + writer
+
+      nothing:
+        expr: dummy
+
+    relations:
+      owner:
+        types:
+          - actor
+
+      reader:
+        types:
+          - actor
+
+      writer:
+        types:
+          - actor
+
+      admin:
+        manages:
+          - reader
+        types:
+          - actor
+
+      dummy:
+        types:
+          - actor
diff --git a/http/client_acp.go b/http/client_acp.go
index a0140cf437..d4f1ed02e5 100644
--- a/http/client_acp.go
+++ b/http/client_acp.go
@@ -11,7 +11,9 @@
 package http
 
 import (
+	"bytes"
 	"context"
+	"encoding/json"
 	"net/http"
 	"strings"
 
@@ -42,3 +44,51 @@ func (c *Client) AddPolicy(
 
 	return policyResult, nil
 }
+
+type addDocActorRelationshipRequest struct {
+	CollectionName string
+	DocID          string
+	Relation       string
+	TargetActor    string
+}
+
+func (c *Client) AddDocActorRelationship(
+	ctx context.Context,
+	collectionName string,
+	docID string,
+	relation string,
+	targetActor string,
+) (client.AddDocActorRelationshipResult, error) {
+	methodURL := c.http.baseURL.JoinPath("acp", "relationship")
+
+	body, err := json.Marshal(
+		addDocActorRelationshipRequest{
+			CollectionName: collectionName,
+			DocID:          docID,
+			Relation:       relation,
+			TargetActor:    targetActor,
+		},
+	)
+
+	if err != nil {
+		return client.AddDocActorRelationshipResult{}, err
+	}
+
+	req, err := http.NewRequestWithContext(
+		ctx,
+		http.MethodPost,
+		methodURL.String(),
+		bytes.NewBuffer(body),
+	)
+
+	if err != nil {
+		return client.AddDocActorRelationshipResult{}, err
+	}
+
+	var addDocActorRelResult client.AddDocActorRelationshipResult
+	if err := c.http.requestJson(req, &addDocActorRelResult); err != nil {
+		return client.AddDocActorRelationshipResult{}, err
+	}
+
+	return addDocActorRelResult, nil
+}
diff --git a/http/handler_acp.go b/http/handler_acp.go
index c3c5985c71..e9bdf2ce0e 100644
--- a/http/handler_acp.go
+++ b/http/handler_acp.go
@@ -46,6 +46,35 @@ func (s *acpHandler) AddPolicy(rw http.ResponseWriter, req *http.Request) {
 	responseJSON(rw, http.StatusOK, addPolicyResult)
 }
 
+func (s *acpHandler) AddDocActorRelationship(rw http.ResponseWriter, req *http.Request) {
+	db, ok := req.Context().Value(dbContextKey).(client.DB)
+	if !ok {
+		responseJSON(rw, http.StatusBadRequest, errorResponse{NewErrFailedToGetContext("db")})
+		return
+	}
+
+	var message addDocActorRelationshipRequest
+	err := requestJSON(req, &message)
+	if err != nil {
+		responseJSON(rw, http.StatusBadRequest, errorResponse{err})
+		return
+	}
+
+	addDocActorRelResult, err := db.AddDocActorRelationship(
+		req.Context(),
+		message.CollectionName,
+		message.DocID,
+		message.Relation,
+		message.TargetActor,
+	)
+	if err != nil {
+		responseJSON(rw, http.StatusBadRequest, errorResponse{err})
+		return
+	}
+
+	responseJSON(rw, http.StatusOK, addDocActorRelResult)
+}
+
 func (h *acpHandler) bindRoutes(router *Router) {
 	successResponse := &openapi3.ResponseRef{
 		Ref: "#/components/responses/success",
@@ -69,5 +98,21 @@ func (h *acpHandler) bindRoutes(router *Router) {
 		Value: acpAddPolicyRequest,
 	}
 
+	acpAddDocActorRelationshipRequest := openapi3.NewRequestBody().
+		WithRequired(true).
+		WithContent(openapi3.NewContentWithSchema(openapi3.NewStringSchema(), []string{"text/plain"}))
+
+	acpAddDocActorRelationship := openapi3.NewOperation()
+	acpAddDocActorRelationship.OperationID = "add relationship"
+	acpAddDocActorRelationship.Description = "Add an actor relationship using acp system"
+	acpAddDocActorRelationship.Tags = []string{"acp_relationship"}
+	acpAddDocActorRelationship.Responses = openapi3.NewResponses()
+	acpAddDocActorRelationship.Responses.Set("200", successResponse)
+	acpAddDocActorRelationship.Responses.Set("400", errorResponse)
+	acpAddDocActorRelationship.RequestBody = &openapi3.RequestBodyRef{
+		Value: acpAddDocActorRelationshipRequest,
+	}
+
 	router.AddRoute("/acp/policy", http.MethodPost, acpAddPolicy, h.AddPolicy)
+	router.AddRoute("/acp/relationship", http.MethodPost, acpAddDocActorRelationship, h.AddDocActorRelationship)
 }
diff --git a/internal/db/db.go b/internal/db/db.go
index d88c5920bc..73165c239a 100644
--- a/internal/db/db.go
+++ b/internal/db/db.go
@@ -31,6 +31,7 @@ import (
 	"github.com/sourcenetwork/defradb/errors"
 	"github.com/sourcenetwork/defradb/event"
 	"github.com/sourcenetwork/defradb/internal/core"
+	"github.com/sourcenetwork/defradb/internal/db/permission"
 	"github.com/sourcenetwork/defradb/internal/request/graphql"
 )
 
@@ -190,8 +191,9 @@ func (db *db) AddPolicy(
 	policy string,
 ) (client.AddPolicyResult, error) {
 	if !db.acp.HasValue() {
-		return client.AddPolicyResult{}, client.ErrPolicyAddFailureNoACP
+		return client.AddPolicyResult{}, client.ErrACPOperationButACPNotAvailable
 	}
+
 	identity := GetContextIdentity(ctx)
 
 	policyID, err := db.acp.Value().AddPolicy(
@@ -206,6 +208,46 @@ func (db *db) AddPolicy(
 	return client.AddPolicyResult{PolicyID: policyID}, nil
 }
 
+func (db *db) AddDocActorRelationship(
+	ctx context.Context,
+	collectionName string,
+	docID string,
+	relation string,
+	targetActor string,
+) (client.AddDocActorRelationshipResult, error) {
+	if !db.acp.HasValue() {
+		return client.AddDocActorRelationshipResult{}, client.ErrACPOperationButACPNotAvailable
+	}
+
+	collection, err := db.GetCollectionByName(ctx, collectionName)
+	if err != nil {
+		return client.AddDocActorRelationshipResult{}, err
+	}
+
+	policyID, resourceName, hasPolicy := permission.IsPermissioned(collection)
+	if !hasPolicy {
+		return client.AddDocActorRelationshipResult{}, client.ErrACPOperationButCollectionHasNoPolicy
+	}
+
+	identity := GetContextIdentity(ctx)
+
+	exists, err := db.acp.Value().AddDocActorRelationship(
+		ctx,
+		policyID,
+		resourceName,
+		docID,
+		relation,
+		identity.Value(),
+		targetActor,
+	)
+
+	if err != nil {
+		return client.AddDocActorRelationshipResult{}, err
+	}
+
+	return client.AddDocActorRelationshipResult{ExistedAlready: exists}, nil
+}
+
 // Initialize is called when a database is first run and creates all the db global meta data
 // like Collection ID counters.
 func (db *db) initialize(ctx context.Context) error {
diff --git a/internal/db/permission/check.go b/internal/db/permission/check.go
index 9d3d8a587b..b19500f41b 100644
--- a/internal/db/permission/check.go
+++ b/internal/db/permission/check.go
@@ -43,7 +43,7 @@ func CheckAccessOfDocOnCollectionWithACP(
 ) (bool, error) {
 	// Even if acp exists, but there is no policy on the collection (unpermissioned collection)
 	// then we still have unrestricted access.
-	policyID, resourceName, hasPolicy := isPermissioned(collection)
+	policyID, resourceName, hasPolicy := IsPermissioned(collection)
 	if !hasPolicy {
 		return true, nil
 	}
diff --git a/internal/db/permission/permission.go b/internal/db/permission/permission.go
index 3b365cba75..a91d346a6f 100644
--- a/internal/db/permission/permission.go
+++ b/internal/db/permission/permission.go
@@ -14,13 +14,13 @@ import (
 	"github.com/sourcenetwork/defradb/client"
 )
 
-// isPermissioned returns true if the collection has a policy, otherwise returns false.
+// IsPermissioned returns true if the collection has a policy, otherwise returns false.
 //
 // This tells us if access control is enabled for this collection or not.
 //
 // When there is a policy, in addition to returning true in the last return value, the
 // first returned value is policyID, second is the resource name.
-func isPermissioned(collection client.Collection) (string, string, bool) {
+func IsPermissioned(collection client.Collection) (string, string, bool) {
 	policy := collection.Definition().Description.Policy
 	if policy.HasValue() &&
 		policy.Value().ID != "" &&
diff --git a/internal/db/permission/register.go b/internal/db/permission/register.go
index dedbdd8d63..5e03967fb4 100644
--- a/internal/db/permission/register.go
+++ b/internal/db/permission/register.go
@@ -37,7 +37,7 @@ func RegisterDocOnCollectionWithACP(
 	docID string,
 ) error {
 	// An identity exists and the collection has a policy.
-	if policyID, resourceName, hasPolicy := isPermissioned(collection); hasPolicy && identity.HasValue() {
+	if policyID, resourceName, hasPolicy := IsPermissioned(collection); hasPolicy && identity.HasValue() {
 		return acpSystem.RegisterDocObject(
 			ctx,
 			identity.Value(),
diff --git a/tests/clients/cli/wrapper.go b/tests/clients/cli/wrapper.go
index 7a2f28fd4a..b3261f09a8 100644
--- a/tests/clients/cli/wrapper.go
+++ b/tests/clients/cli/wrapper.go
@@ -175,26 +175,6 @@ func (w *Wrapper) BasicExport(ctx context.Context, config *client.BackupConfig)
 	return err
 }
 
-func (w *Wrapper) AddPolicy(
-	ctx context.Context,
-	policy string,
-) (client.AddPolicyResult, error) {
-	args := []string{"client", "acp", "policy", "add"}
-	args = append(args, policy)
-
-	data, err := w.cmd.execute(ctx, args)
-	if err != nil {
-		return client.AddPolicyResult{}, err
-	}
-
-	var addPolicyResult client.AddPolicyResult
-	if err := json.Unmarshal(data, &addPolicyResult); err != nil {
-		return client.AddPolicyResult{}, err
-	}
-
-	return addPolicyResult, err
-}
-
 func (w *Wrapper) AddSchema(ctx context.Context, schema string) ([]client.CollectionDescription, error) {
 	args := []string{"client", "schema", "add"}
 	args = append(args, schema)
diff --git a/tests/clients/cli/wrapper_acp.go b/tests/clients/cli/wrapper_acp.go
new file mode 100644
index 0000000000..f76aad3cdf
--- /dev/null
+++ b/tests/clients/cli/wrapper_acp.go
@@ -0,0 +1,66 @@
+// Copyright 2023 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package cli
+
+import (
+	"context"
+	"encoding/json"
+
+	"github.com/sourcenetwork/defradb/client"
+)
+
+func (w *Wrapper) AddPolicy(
+	ctx context.Context,
+	policy string,
+) (client.AddPolicyResult, error) {
+	args := []string{"client", "acp", "policy", "add"}
+	args = append(args, policy)
+
+	data, err := w.cmd.execute(ctx, args)
+	if err != nil {
+		return client.AddPolicyResult{}, err
+	}
+
+	var addPolicyResult client.AddPolicyResult
+	if err := json.Unmarshal(data, &addPolicyResult); err != nil {
+		return client.AddPolicyResult{}, err
+	}
+
+	return addPolicyResult, err
+}
+
+func (w *Wrapper) AddDocActorRelationship(
+	ctx context.Context,
+	collectionName string,
+	docID string,
+	relation string,
+	targetActor string,
+) (client.AddDocActorRelationshipResult, error) {
+	args := []string{
+		"client", "acp", "relationship", "add",
+		"--collection", collectionName,
+		"--docID", docID,
+		"--relation", relation,
+		"--actor", targetActor,
+	}
+
+	data, err := w.cmd.execute(ctx, args)
+	if err != nil {
+		return client.AddDocActorRelationshipResult{}, err
+	}
+
+	var exists client.AddDocActorRelationshipResult
+	if err := json.Unmarshal(data, &exists); err != nil {
+		return client.AddDocActorRelationshipResult{}, err
+	}
+
+	return exists, err
+}
diff --git a/tests/clients/http/wrapper.go b/tests/clients/http/wrapper.go
index 2b84bfc701..81ed74b095 100644
--- a/tests/clients/http/wrapper.go
+++ b/tests/clients/http/wrapper.go
@@ -105,6 +105,22 @@ func (w *Wrapper) AddPolicy(
 	return w.client.AddPolicy(ctx, policy)
 }
 
+func (w *Wrapper) AddDocActorRelationship(
+	ctx context.Context,
+	collectionName string,
+	docID string,
+	relation string,
+	targetActor string,
+) (client.AddDocActorRelationshipResult, error) {
+	return w.client.AddDocActorRelationship(
+		ctx,
+		collectionName,
+		docID,
+		relation,
+		targetActor,
+	)
+}
+
 func (w *Wrapper) PatchSchema(
 	ctx context.Context,
 	patch string,
diff --git a/tests/integration/acp.go b/tests/integration/acp.go
index a6efd64110..a8f41e5f41 100644
--- a/tests/integration/acp.go
+++ b/tests/integration/acp.go
@@ -133,14 +133,192 @@ func addPolicyACP(
 	}
 }
 
+// AddDocActorRelationship will attempt to create a new relationship for a document with an actor.
+type AddDocActorRelationship struct {
+	// NodeID may hold the ID (index) of the node we want to add doc actor relationship on.
+	//
+	// If a value is not provided the relationship will be added in all nodes, unless testing with
+	// sourcehub ACP, in which case the relationship will only be defined once.
+	NodeID immutable.Option[int]
+
+	// The collection in which this document we want to add a relationship for exists.
+	//
+	// This is a required field. To test the invalid usage of not having this arg, use -1 index.
+	CollectionID int
+
+	// The index-identifier of the document within the collection.  This is based on
+	// the order in which it was created, not the ordering of the document within the
+	// database.
+	//
+	// This is a required field. To test the invalid usage of not having this arg, use -1 index.
+	DocID int
+
+	// The name of the relation to set between document and target actor (should be defined in the policy).
+	//
+	// This is a required field.
+	Relation string
+
+	// The target public identity, i.e. the identity of the actor to tie the document's relation with.
+	//
+	// This is a required field. To test the invalid usage of not having this arg, use -1 index.
+	TargetIdentity int
+
+	// The requestor identity, i.e. identity of the actor creating the relationship.
+	// Note: This identity must either own or have managing access defined in the policy.
+	//
+	// This is a required field. To test the invalid usage of not having this arg, use -1 index.
+	RequestorIdentity int
+
+	// Result returns true if it was a no-op due to existing before, and false if a new relationship was made.
+	ExpectedExistence bool
+
+	// Any error expected from the action. Optional.
+	//
+	// String can be a partial, and the test will pass if an error is returned that
+	// contains this string.
+	ExpectedError string
+}
+
+func addDocActorRelationshipACP(
+	s *state,
+	action AddDocActorRelationship,
+) {
+	if action.NodeID.HasValue() {
+		nodeID := action.NodeID.Value()
+		collections := s.collections[nodeID]
+		node := s.nodes[nodeID]
+
+		var collectionName string
+		if action.CollectionID == -1 {
+			collectionName = ""
+		} else {
+			collection := collections[action.CollectionID]
+			if !collection.Description().Name.HasValue() {
+				require.Fail(s.t, "Expected non-empty collection name, but it was empty.", s.testCase.Description)
+			}
+			collectionName = collection.Description().Name.Value()
+		}
+
+		var docID string
+		if action.DocID == -1 || action.CollectionID == -1 {
+			docID = ""
+		} else {
+			docID = s.docIDs[action.CollectionID][action.DocID].String()
+		}
+
+		var targetIdentity string
+		if action.TargetIdentity == -1 {
+			targetIdentity = ""
+		} else {
+			optionalTargetIdentity := getIdentity(s, nodeID, immutable.Some(action.TargetIdentity))
+			if !optionalTargetIdentity.HasValue() {
+				require.Fail(s.t, "Expected non-empty target identity, but it was empty.", s.testCase.Description)
+			}
+			targetIdentity = optionalTargetIdentity.Value().DID
+		}
+
+		var requestorIdentity immutable.Option[acpIdentity.Identity]
+		if action.RequestorIdentity == -1 {
+			requestorIdentity = acpIdentity.None
+		} else {
+			requestorIdentity = getIdentity(s, nodeID, immutable.Some(action.RequestorIdentity))
+			if !requestorIdentity.HasValue() {
+				require.Fail(s.t, "Expected non-empty requestor identity, but it was empty.", s.testCase.Description)
+			}
+		}
+		ctx := db.SetContextIdentity(s.ctx, requestorIdentity)
+
+		exists, err := node.AddDocActorRelationship(
+			ctx,
+			collectionName,
+			docID,
+			action.Relation,
+			targetIdentity,
+		)
+
+		if err == nil {
+			require.Equal(s.t, action.ExpectedError, "")
+			require.Equal(s.t, action.ExpectedExistence, exists.ExistedAlready)
+		}
+
+		expectedErrorRaised := AssertError(s.t, s.testCase.Description, err, action.ExpectedError)
+		assertExpectedErrorRaised(s.t, s.testCase.Description, action.ExpectedError, expectedErrorRaised)
+	} else {
+		for i, node := range getNodes(action.NodeID, s.nodes) {
+			var collectionName string
+			if action.CollectionID == -1 {
+				collectionName = ""
+			} else {
+				collection := s.collections[i][action.CollectionID]
+				if !collection.Description().Name.HasValue() {
+					require.Fail(s.t, "Expected non-empty collection name, but it was empty.", s.testCase.Description)
+				}
+				collectionName = collection.Description().Name.Value()
+			}
+
+			var docID string
+			if action.DocID == -1 || action.CollectionID == -1 {
+				docID = ""
+			} else {
+				docID = s.docIDs[action.CollectionID][action.DocID].String()
+			}
+
+			var targetIdentity string
+			if action.TargetIdentity == -1 {
+				targetIdentity = ""
+			} else {
+				optionalTargetIdentity := getIdentity(s, i, immutable.Some(action.TargetIdentity))
+				if !optionalTargetIdentity.HasValue() {
+					require.Fail(s.t, "Expected non-empty target identity, but it was empty.", s.testCase.Description)
+				}
+				targetIdentity = optionalTargetIdentity.Value().DID
+			}
+
+			var requestorIdentity immutable.Option[acpIdentity.Identity]
+			if action.RequestorIdentity == -1 {
+				requestorIdentity = acpIdentity.None
+			} else {
+				requestorIdentity = getIdentity(s, i, immutable.Some(action.RequestorIdentity))
+				if !requestorIdentity.HasValue() {
+					require.Fail(s.t, "Expected non-empty requestor identity, but it was empty.", s.testCase.Description)
+				}
+			}
+			ctx := db.SetContextIdentity(s.ctx, requestorIdentity)
+
+			exists, err := node.AddDocActorRelationship(
+				ctx,
+				collectionName,
+				docID,
+				action.Relation,
+				targetIdentity,
+			)
+
+			if err == nil {
+				require.Equal(s.t, action.ExpectedError, "")
+				require.Equal(s.t, action.ExpectedExistence, exists.ExistedAlready)
+			}
+
+			expectedErrorRaised := AssertError(s.t, s.testCase.Description, err, action.ExpectedError)
+			assertExpectedErrorRaised(s.t, s.testCase.Description, action.ExpectedError, expectedErrorRaised)
+
+			// The relationship should only be added to a SourceHub chain once - there is no need to loop through
+			// the nodes.
+			if acpType == SourceHubACPType {
+				break
+			}
+		}
+	}
+}
+
 func setupSourceHub(s *state) ([]node.ACPOpt, error) {
 	var isACPTest bool
 	for _, a := range s.testCase.Actions {
-		if _, ok := a.(AddPolicy); ok {
+		switch a.(type) {
+		case AddPolicy, AddDocActorRelationship:
 			isACPTest = true
-			break
 		}
 	}
+
 	if !isACPTest {
 		// Spinning up SourceHub instances is a bit slow, so we should be quite aggressive in trimming down the
 		// runtime of the test suite when SourceHub ACP is selected.
@@ -405,6 +583,37 @@ func crossLock(port uint16) (func(), error) {
 		nil
 }
 
+// Generate the keys using the index as the seed so that multiple
+// runs yield the same private key.  This is important for stuff like
+// the change detector.
+func generateIdentity(s *state, seedIndex int, nodeIndex int) (acpIdentity.Identity, error) {
+	var audience immutable.Option[string]
+	switch client := s.nodes[nodeIndex].(type) {
+	case *http.Wrapper:
+		audience = immutable.Some(strings.TrimPrefix(client.Host(), "http://"))
+	case *cli.Wrapper:
+		audience = immutable.Some(strings.TrimPrefix(client.Host(), "http://"))
+	}
+
+	source := rand.NewSource(int64(seedIndex))
+	r := rand.New(source)
+
+	privateKey, err := secp256k1.GeneratePrivateKeyFromRand(r)
+	require.NoError(s.t, err)
+
+	identity, err := acpIdentity.FromPrivateKey(
+		privateKey,
+		authTokenExpiration,
+		audience,
+		immutable.Some(s.sourcehubAddress),
+		// Creating and signing the bearer token is slow, so we skip it if it not
+		// required.
+		!(acpType == SourceHubACPType || audience.HasValue()),
+	)
+
+	return identity, err
+}
+
 func getIdentity(s *state, nodeIndex int, index immutable.Option[int]) immutable.Option[acpIdentity.Identity] {
 	if !index.HasValue() {
 		return immutable.None[acpIdentity.Identity]()
@@ -419,40 +628,18 @@ func getIdentity(s *state, nodeIndex int, index immutable.Option[int]) immutable
 
 	if len(nodeIdentities) <= index.Value() {
 		identities := make([]acpIdentity.Identity, index.Value()+1)
-		copy(identities, nodeIdentities)
-		nodeIdentities = identities
-		s.identities[nodeIndex] = nodeIdentities
-
-		var audience immutable.Option[string]
-		switch client := s.nodes[nodeIndex].(type) {
-		case *http.Wrapper:
-			audience = immutable.Some(strings.TrimPrefix(client.Host(), "http://"))
-		case *cli.Wrapper:
-			audience = immutable.Some(strings.TrimPrefix(client.Host(), "http://"))
+		// Fill any empty identities up to the index.
+		for i := range identities {
+			if i < len(nodeIdentities) && nodeIdentities[i] != (acpIdentity.Identity{}) {
+				identities[i] = nodeIdentities[i]
+				continue
+			}
+			newIdentity, err := generateIdentity(s, i, nodeIndex)
+			require.NoError(s.t, err)
+			identities[i] = newIdentity
 		}
-
-		// Generate the keys using the index as the seed so that multiple
-		// runs yield the same private key.  This is important for stuff like
-		// the change detector.
-		source := rand.NewSource(int64(index.Value()))
-		r := rand.New(source)
-
-		privateKey, err := secp256k1.GeneratePrivateKeyFromRand(r)
-		require.NoError(s.t, err)
-
-		identity, err := acpIdentity.FromPrivateKey(
-			privateKey,
-			authTokenExpiration,
-			audience,
-			immutable.Some(s.sourcehubAddress),
-			// Creating and signing the bearer token is slow, so we skip it if it not
-			// required.
-			!(acpType == SourceHubACPType || audience.HasValue()),
-		)
-		require.NoError(s.t, err)
-
-		nodeIdentities[index.Value()] = identity
-		return immutable.Some(identity)
+		s.identities[nodeIndex] = identities
+		return immutable.Some(identities[index.Value()])
 	} else {
 		return immutable.Some(nodeIdentities[index.Value()])
 	}
diff --git a/tests/integration/acp/p2p/replicator_with_doc_actor_relationship_test.go b/tests/integration/acp/p2p/replicator_with_doc_actor_relationship_test.go
new file mode 100644
index 0000000000..fe06e10061
--- /dev/null
+++ b/tests/integration/acp/p2p/replicator_with_doc_actor_relationship_test.go
@@ -0,0 +1,219 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package test_acp_p2p
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/sourcenetwork/immutable"
+
+	testUtils "github.com/sourcenetwork/defradb/tests/integration"
+)
+
+func TestACP_P2PReplicatorWithPermissionedCollectionCreateDocActorRelationship_SourceHubACP(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, p2p replicator with collection that has a policy, create a new doc-actor relationship",
+
+		SupportedACPTypes: immutable.Some(
+			[]testUtils.ACPType{
+				testUtils.SourceHubACPType,
+			},
+		),
+
+		Actions: []any{
+			testUtils.RandomNetworkingConfig(),
+
+			testUtils.RandomNetworkingConfig(),
+
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.ConfigureReplicator{
+				SourceNodeID: 0,
+
+				TargetNodeID: 1,
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				NodeID: immutable.Some(0),
+
+				CollectionID: 0,
+
+				DocMap: map[string]any{
+					"name": "Shahzad",
+				},
+			},
+
+			testUtils.WaitForSync{},
+
+			testUtils.Request{
+				// Ensure that the document is hidden on all nodes to an unauthorized actor
+				Identity: immutable.Some(2),
+
+				Request: `
+					query {
+						Users {
+							name
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{},
+				},
+			},
+
+			testUtils.AddDocActorRelationship{
+				NodeID: immutable.Some(0),
+
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.AddDocActorRelationship{
+				NodeID: immutable.Some(1), // Note: Different node than the previous
+
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: true, // Making the same relation through any node should be a no-op
+			},
+
+			testUtils.Request{
+				// Ensure that the document is now accessible on all nodes to the newly authorized actor.
+				Identity: immutable.Some(2),
+
+				Request: `
+					query {
+						Users {
+							name
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"name": "Shahzad",
+						},
+					},
+				},
+			},
+
+			testUtils.Request{
+				// Ensure that the document is still accessible on all nodes to the owner.
+				Identity: immutable.Some(1),
+
+				Request: `
+					query {
+						Users {
+							name
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"name": "Shahzad",
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
diff --git a/tests/integration/acp/p2p/subscribe_with_doc_actor_relationship_test.go b/tests/integration/acp/p2p/subscribe_with_doc_actor_relationship_test.go
new file mode 100644
index 0000000000..a55c5a333e
--- /dev/null
+++ b/tests/integration/acp/p2p/subscribe_with_doc_actor_relationship_test.go
@@ -0,0 +1,225 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package test_acp_p2p
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/sourcenetwork/immutable"
+
+	testUtils "github.com/sourcenetwork/defradb/tests/integration"
+)
+
+func TestACP_P2PSubscribeAddGetSingleWithPermissionedCollectionCreateDocActorRelationship_SourceHubACP(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, p2p subscribe collection that has a policy, and create a new doc-actor relationship",
+
+		SupportedACPTypes: immutable.Some(
+			[]testUtils.ACPType{
+				testUtils.SourceHubACPType,
+			},
+		),
+
+		Actions: []any{
+			testUtils.RandomNetworkingConfig(),
+
+			testUtils.RandomNetworkingConfig(),
+
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.ConnectPeers{
+				SourceNodeID: 1,
+
+				TargetNodeID: 0,
+			},
+
+			testUtils.SubscribeToCollection{
+				NodeID: 1,
+
+				CollectionIDs: []int{0},
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				NodeID: immutable.Some(0),
+
+				CollectionID: 0,
+
+				DocMap: map[string]any{
+					"name": "Shahzad",
+				},
+			},
+
+			testUtils.WaitForSync{},
+
+			testUtils.Request{
+				// Ensure that the document is hidden on all nodes to an unauthorized actor
+				Identity: immutable.Some(2),
+
+				Request: `
+					query {
+						Users {
+							name
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{},
+				},
+			},
+
+			testUtils.AddDocActorRelationship{
+				NodeID: immutable.Some(0),
+
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.AddDocActorRelationship{
+				NodeID: immutable.Some(1), // Note: Different node than the previous
+
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: true, // Making the same relation through any node should be a no-op
+			},
+
+			testUtils.Request{
+				// Ensure that the document is now accessible on all nodes to the newly authorized actor.
+				Identity: immutable.Some(2),
+
+				Request: `
+					query {
+						Users {
+							name
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"name": "Shahzad",
+						},
+					},
+				},
+			},
+
+			testUtils.Request{
+				// Ensure that the document is still accessible on all nodes to the owner.
+				Identity: immutable.Some(1),
+
+				Request: `
+					query {
+						Users {
+							name
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"name": "Shahzad",
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_collection_with_no_policy_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_collection_with_no_policy_test.go
new file mode 100644
index 0000000000..a614ef3ce9
--- /dev/null
+++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_collection_with_no_policy_test.go
@@ -0,0 +1,66 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package test_acp_relationship_add_docactor
+
+import (
+	"testing"
+
+	"github.com/sourcenetwork/immutable"
+
+	testUtils "github.com/sourcenetwork/defradb/tests/integration"
+)
+
+func TestACP_AddDocActorRelationshipWithCollectionThatHasNoPolicy_NotAllowedError(t *testing.T) {
+	test := testUtils.TestCase{
+
+		Description: "Test acp, add doc actor relationship on a collection with no policy, not allowed error",
+
+		Actions: []any{
+			testUtils.SchemaUpdate{
+				Schema: `
+					type Users {
+						name: String
+						age: Int
+					}
+				`,
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedError: "operation requires ACP, but collection has no policy", // Everything is public anyway
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_invalid_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_invalid_test.go
new file mode 100644
index 0000000000..cc0e0dac69
--- /dev/null
+++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_invalid_test.go
@@ -0,0 +1,545 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package test_acp_relationship_add_docactor
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/sourcenetwork/immutable"
+
+	testUtils "github.com/sourcenetwork/defradb/tests/integration"
+)
+
+func TestACP_AddDocActorRelationshipMissingDocID_Error(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, add doc actor relationship with docID missing, return error",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: -1,
+
+				Relation: "reader",
+
+				ExpectedError: "missing a required argument needed to add doc actor relationship.",
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_AddDocActorRelationshipMissingCollection_Error(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, add doc actor relationship with collection missing, return error",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: -1,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedError: "collection name can't be empty",
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_AddDocActorRelationshipMissingRelationName_Error(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, add doc actor relationship with relation name missing, return error",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "",
+
+				ExpectedError: "missing a required argument needed to add doc actor relationship.",
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_AddDocActorRelationshipMissingTargetActorName_Error(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, add doc actor relationship with target actor missing, return error",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: -1,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedError: "missing a required argument needed to add doc actor relationship.",
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_AddDocActorRelationshipMissingReqestingIdentityName_Error(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, add doc actor relationship with requesting identity missing, return error",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: -1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedError: "missing a required argument needed to add doc actor relationship.",
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_delete_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_delete_test.go
new file mode 100644
index 0000000000..9be3ace27d
--- /dev/null
+++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_delete_test.go
@@ -0,0 +1,505 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package test_acp_relationship_add_docactor
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/sourcenetwork/immutable"
+
+	testUtils "github.com/sourcenetwork/defradb/tests/integration"
+)
+
+func TestACP_OwnerGivesDeleteWriteAccessToAnotherActorTwice_ShowThatTheRelationshipAlreadyExists(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives write(delete) access to another actor twice, no-op",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can not delete yet.
+
+				DocID: 0,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: true, // is a no-op
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_OwnerGivesDeleteWriteAccessToAnotherActor_OtherActorCanDelete(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives write(delete) access to another actor",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can not delete yet.
+
+				DocID: 0,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can now read.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad",
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can now delete.
+
+				DocID: 0,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // Check if actually deleted.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{},
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_OwnerGivesDeleteWriteAccessToAnotherActor_OtherActorCanDeleteSoCanTheOwner(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives write(delete) access to another actor, both can read",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(1), // Owner can still also delete (ownership not transferred)
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad",
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(1), // Owner can still also delete.
+
+				DocID: 0,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(1), // Check if actually deleted.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{},
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_dummy_relation_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_dummy_relation_test.go
new file mode 100644
index 0000000000..66e17ba00a
--- /dev/null
+++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_dummy_relation_test.go
@@ -0,0 +1,302 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package test_acp_relationship_add_docactor
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/sourcenetwork/immutable"
+
+	testUtils "github.com/sourcenetwork/defradb/tests/integration"
+)
+
+func TestACP_AddDocActorRelationshipWithDummyRelationDefinedOnPolicy_NothingChanges(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, add doc actor relationship with a dummy relation defined on policy, nothing happens",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents
+				},
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "dummy", // Doesn't mean anything to the database.
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can still not read.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_AddDocActorRelationshipWithDummyRelationNotDefinedOnPolicy_Error(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, add doc actor relationship with an invalid relation (not defined on policy), error",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents
+				},
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "NotOnPolicy", // Doesn't mean anything to the database and not on policy either.
+
+				ExpectedError: "failed to add document actor relationship with acp",
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can still not read.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_manager_gql_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_manager_gql_test.go
new file mode 100644
index 0000000000..9c2280d6ce
--- /dev/null
+++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_manager_gql_test.go
@@ -0,0 +1,604 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package test_acp_relationship_add_docactor
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/sourcenetwork/immutable"
+
+	testUtils "github.com/sourcenetwork/defradb/tests/integration"
+)
+
+func TestACP_OwnerMakesAManagerThatGivesItSelfReadAndWriteAccess_GQL_ManagerCanReadAndWrite(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner makes a manager that gives itself read and write access",
+
+		SupportedMutationTypes: immutable.Some([]testUtils.MutationType{
+			// GQL mutation will return no error when wrong identity is used so test that separately.
+			testUtils.GQLRequestMutationType,
+		}),
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                              - writer
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity (to be manager) can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // Manager can't update yet.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				SkipLocalUpdateEvent: true,
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // Manager can't delete yet.
+
+				DocID: 0,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.AddDocActorRelationship{ // Make admin / manager
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "admin",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.AddDocActorRelationship{ // Manager makes itself a writer
+				RequestorIdentity: 2,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: false,
+			},
+
+			// Note: It is not neccesary to make itself a reader, as becoming a writer allows reading.
+			testUtils.AddDocActorRelationship{ // Manager makes itself a reader
+				RequestorIdentity: 2,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // Manager can now update.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // Manager can read now
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad Lone",
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // Manager can now delete.
+
+				DocID: 0,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // Make sure manager was able to delete the document.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{},
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_OwnerMakesManagerButManagerCanNotPerformOperations_GQL_ManagerCantReadOrWrite(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner makes a manager, manager can't read or write",
+
+		SupportedMutationTypes: immutable.Some([]testUtils.MutationType{
+			// GQL mutation will return no error when wrong identity is used so test that separately.
+			testUtils.GQLRequestMutationType,
+		}),
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.AddDocActorRelationship{ // Make admin / manager
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "admin",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // Manager can not read
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{},
+				},
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // Manager can not update.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				SkipLocalUpdateEvent: true,
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // Manager can not delete.
+
+				DocID: 0,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.AddDocActorRelationship{ // Manager can manage only.
+				RequestorIdentity: 2,
+
+				TargetIdentity: 3,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: false,
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_ManagerAddsRelationshipWithRelationItDoesNotManageAccordingToPolicy_GQL_Error(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, manager adds relationship with relation it does not manage according to policy, error",
+
+		SupportedMutationTypes: immutable.Some([]testUtils.MutationType{
+			// GQL mutation will return no error when wrong identity is used so test that separately.
+			testUtils.GQLRequestMutationType,
+		}),
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.AddDocActorRelationship{ // Make admin / manager
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "admin",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.AddDocActorRelationship{ // Admin tries to make another actor a writer
+				RequestorIdentity: 2,
+
+				TargetIdentity: 3,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedError: "acp protocol violation",
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(3), // The other actor can't read
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{},
+				},
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(3), // The other actor can not update
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				SkipLocalUpdateEvent: true,
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(3), // The other actor can not delete
+
+				DocID: 0,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_manager_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_manager_test.go
new file mode 100644
index 0000000000..4467aa1af9
--- /dev/null
+++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_manager_test.go
@@ -0,0 +1,1286 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package test_acp_relationship_add_docactor
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/sourcenetwork/immutable"
+
+	testUtils "github.com/sourcenetwork/defradb/tests/integration"
+)
+
+func TestACP_ManagerGivesReadAccessToAnotherActor_OtherActorCanRead(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives read access to another actor",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(3), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.AddDocActorRelationship{ // Make admin / manager
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "admin",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.AddDocActorRelationship{ // Admin makes another actor a reader
+				RequestorIdentity: 2,
+
+				TargetIdentity: 3,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(3), // The other actor can read
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad",
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(3), // The other actor can not update
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(3), // The other actor can not delete
+
+				DocID: 0,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_ManagerGivesWriteAccessToAnotherActor_OtherActorCanWrite(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives write access to another actor",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - writer
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(3), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.AddDocActorRelationship{ // Make admin / manager
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "admin",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.AddDocActorRelationship{ // Admin makes another actor a writer
+				RequestorIdentity: 2,
+
+				TargetIdentity: 3,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(3), // The other actor can update
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(3), // The other actor can read
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad Lone", // Updated name
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(3), // The other actor can delete
+
+				DocID: 0,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(3),
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{ // Check actually deleted
+					"Users": []map[string]any{},
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_OwnerMakesAManagerThatGivesItSelfReadAccess_ManagerCanRead(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner makes a manager that gives itself read access",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity (to be manager) can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.AddDocActorRelationship{ // Make admin / manager
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "admin",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.AddDocActorRelationship{ // Manager makes itself a reader
+				RequestorIdentity: 2,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // Manager can read now
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad",
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // Manager still can't update
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // Manager still can't delete
+
+				DocID: 0,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_OwnerMakesAManagerThatGivesItSelfReadAndWriteAccess_ManagerCanReadAndWrite(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner makes a manager that gives itself read and write access",
+
+		SupportedMutationTypes: immutable.Some([]testUtils.MutationType{
+			testUtils.CollectionNamedMutationType,
+			testUtils.CollectionSaveMutationType,
+		}),
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                              - writer
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity (to be manager) can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // Manager can't update yet.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // Manager can't delete yet.
+
+				DocID: 0,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.AddDocActorRelationship{ // Make admin / manager
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "admin",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.AddDocActorRelationship{ // Manager makes itself a writer
+				RequestorIdentity: 2,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: false,
+			},
+
+			// Note: It is not neccesary to make itself a reader, as becoming a writer allows reading.
+			testUtils.AddDocActorRelationship{ // Manager makes itself a reader
+				RequestorIdentity: 2,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // Manager can now update.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // Manager can read now
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad Lone",
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // Manager can now delete.
+
+				DocID: 0,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // Make sure manager was able to delete the document.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{},
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_ManagerAddsRelationshipWithRelationItDoesNotManageAccordingToPolicy_Error(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, manager adds relationship with relation it does not manage according to policy, error",
+
+		SupportedMutationTypes: immutable.Some([]testUtils.MutationType{
+			testUtils.CollectionNamedMutationType,
+			testUtils.CollectionSaveMutationType,
+		}),
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.AddDocActorRelationship{ // Make admin / manager
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "admin",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.AddDocActorRelationship{ // Admin tries to make another actor a writer
+				RequestorIdentity: 2,
+
+				TargetIdentity: 3,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedError: "acp protocol violation",
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(3), // The other actor can't read
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{},
+				},
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(3), // The other actor can not update
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(3), // The other actor can not delete
+
+				DocID: 0,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_OwnerMakesManagerButManagerCanNotPerformOperations_ManagerCantReadOrWrite(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner makes a manager, manager can't read or write",
+
+		SupportedMutationTypes: immutable.Some([]testUtils.MutationType{
+			testUtils.CollectionNamedMutationType,
+			testUtils.CollectionSaveMutationType,
+		}),
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.AddDocActorRelationship{ // Make admin / manager
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "admin",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // Manager can not read
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{},
+				},
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // Manager can not update.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // Manager can not delete.
+
+				DocID: 0,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.AddDocActorRelationship{ // Manager can manage only.
+				RequestorIdentity: 2,
+
+				TargetIdentity: 3,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: false,
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_CantMakeRelationshipIfNotOwnerOrManager_Error(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, cant make relation if identity doesn't own or manage object, return error",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 2, // This identity can not manage as not an admin yet
+
+				TargetIdentity: 3,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: false,
+
+				ExpectedError: "failed to add document actor relationship with acp",
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_only_write_gql_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_only_write_gql_test.go
new file mode 100644
index 0000000000..e3f3e62050
--- /dev/null
+++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_only_write_gql_test.go
@@ -0,0 +1,198 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package test_acp_relationship_add_docactor
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/sourcenetwork/immutable"
+
+	testUtils "github.com/sourcenetwork/defradb/tests/integration"
+)
+
+func TestACP_OwnerGivesUpdateWriteAccessToAnotherActorWithoutExplicitReadPerm_GQL_OtherActorCantUpdate(t *testing.T) {
+	expectedPolicyID := "0a243b1e61f990bccde41db7e81a915ffa1507c1403ae19727ce764d3b08846b"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives write(update) access to another actor, without explicit read permission",
+
+		SupportedMutationTypes: immutable.Some([]testUtils.MutationType{
+			// GQL mutation will return no error when wrong identity is used so test that separately.
+			testUtils.GQLRequestMutationType,
+		}),
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can not update yet.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				SkipLocalUpdateEvent: true,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can still not update.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				SkipLocalUpdateEvent: true,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can still not read.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{},
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_only_write_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_only_write_test.go
new file mode 100644
index 0000000000..e052d19afd
--- /dev/null
+++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_only_write_test.go
@@ -0,0 +1,359 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package test_acp_relationship_add_docactor
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/sourcenetwork/immutable"
+
+	testUtils "github.com/sourcenetwork/defradb/tests/integration"
+)
+
+func TestACP_OwnerGivesUpdateWriteAccessToAnotherActorWithoutExplicitReadPerm_OtherActorCantUpdate(t *testing.T) {
+	expectedPolicyID := "0a243b1e61f990bccde41db7e81a915ffa1507c1403ae19727ce764d3b08846b"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives write(update) access to another actor, without explicit read permission",
+
+		SupportedMutationTypes: immutable.Some([]testUtils.MutationType{
+			testUtils.CollectionNamedMutationType,
+			testUtils.CollectionSaveMutationType,
+		}),
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can not update yet.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can still not update.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can still not read.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{},
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_OwnerGivesDeleteWriteAccessToAnotherActorWithoutExplicitReadPerm_OtherActorCantDelete(t *testing.T) {
+	expectedPolicyID := "0a243b1e61f990bccde41db7e81a915ffa1507c1403ae19727ce764d3b08846b"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives write(delete) access to another actor, without explicit read permission",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can not delete yet.
+
+				DocID: 0,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can still not read.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{},
+				},
+			},
+
+			testUtils.DeleteDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can still not delete.
+
+				DocID: 0,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_public_document_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_public_document_test.go
new file mode 100644
index 0000000000..e134a821e4
--- /dev/null
+++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_public_document_test.go
@@ -0,0 +1,147 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package test_acp_relationship_add_docactor
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/sourcenetwork/immutable"
+
+	testUtils "github.com/sourcenetwork/defradb/tests/integration"
+)
+
+func TestACP_AddDocActorRelationshipWithPublicDocument_CanAlreadyAccess_Error(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, add doc actor relationship on a public document, return error",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{ // Note: Is a public document (without an identity).
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // Can read as it is a public document
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad",
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedError: "failed to add document actor relationship with acp",
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_reader_gql_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_reader_gql_test.go
new file mode 100644
index 0000000000..02a637833f
--- /dev/null
+++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_reader_gql_test.go
@@ -0,0 +1,204 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package test_acp_relationship_add_docactor
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/sourcenetwork/immutable"
+
+	testUtils "github.com/sourcenetwork/defradb/tests/integration"
+)
+
+func TestACP_OwnerGivesOnlyReadAccessToAnotherActor_GQL_OtherActorCanReadButNotUpdate(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives read access to another actor, but the other actor can't update",
+
+		SupportedMutationTypes: immutable.Some([]testUtils.MutationType{
+			// GQL mutation will return no error when wrong identity is used so test that separately.
+			testUtils.GQLRequestMutationType,
+		}),
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.UpdateDoc{ // Since it can't read, it can't update either.
+				CollectionID: 0,
+
+				Identity: immutable.Some(2),
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				SkipLocalUpdateEvent: true,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // Now this identity can read.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad",
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+
+			testUtils.UpdateDoc{ // But this actor still can't update.
+				CollectionID: 0,
+
+				Identity: immutable.Some(2),
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_reader_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_reader_test.go
new file mode 100644
index 0000000000..70a7676a96
--- /dev/null
+++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_reader_test.go
@@ -0,0 +1,810 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package test_acp_relationship_add_docactor
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/sourcenetwork/immutable"
+
+	testUtils "github.com/sourcenetwork/defradb/tests/integration"
+)
+
+func TestACP_OwnerGivesReadAccessToAnotherActorTwice_ShowThatTheRelationshipAlreadyExists(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives read access to another actor twice, no-op",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: true, // is a no-op
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_OwnerGivesReadAccessToAnotherActor_OtherActorCanRead(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives read access to another actor",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // Now this identity can read.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad",
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+// Note: Testing that owner can still read after the relationship was formed is to ensure
+// that no transfer of ownership has taken place.
+func TestACP_OwnerGivesReadAccessToAnotherActor_OtherActorCanReadSoCanTheOwner(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives read access to another actor, both can read",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // Now this identity can read.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad",
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(1), // And so can the owner (ownership not transferred).
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad",
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_OwnerGivesOnlyReadAccessToAnotherActor_OtherActorCanReadButNotUpdate(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives read access to another actor, but the other actor can't update",
+
+		SupportedMutationTypes: immutable.Some([]testUtils.MutationType{
+			testUtils.CollectionNamedMutationType,
+			testUtils.CollectionSaveMutationType,
+		}),
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.UpdateDoc{ // Since it can't read, it can't update either.
+				CollectionID: 0,
+
+				Identity: immutable.Some(2),
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // Now this identity can read.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad",
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+
+			testUtils.UpdateDoc{ // But this actor still can't update.
+				CollectionID: 0,
+
+				Identity: immutable.Some(2),
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_OwnerGivesOnlyReadAccessToAnotherActor_OtherActorCanReadButNotDelete(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives read access to another actor, but the other actor can't delete",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.DeleteDoc{ // Since it can't read, it can't delete either.
+				CollectionID: 0,
+
+				Identity: immutable.Some(2),
+
+				DocID: 0,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "reader",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // Now this identity can read.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad",
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+
+			testUtils.DeleteDoc{ // But this actor still can't delete.
+				CollectionID: 0,
+
+				Identity: immutable.Some(2),
+
+				DocID: 0,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_update_gql_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_update_gql_test.go
new file mode 100644
index 0000000000..dcfda587e8
--- /dev/null
+++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_update_gql_test.go
@@ -0,0 +1,360 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package test_acp_relationship_add_docactor
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/sourcenetwork/immutable"
+
+	testUtils "github.com/sourcenetwork/defradb/tests/integration"
+)
+
+func TestACP_OwnerGivesUpdateWriteAccessToAnotherActorTwice_GQL_ShowThatTheRelationshipAlreadyExists(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives write(update) access to another actor twice, no-op",
+
+		SupportedMutationTypes: immutable.Some([]testUtils.MutationType{
+			// GQL mutation will return no error when wrong identity is used so test that separately.
+			testUtils.GQLRequestMutationType,
+		}),
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can not update yet.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				SkipLocalUpdateEvent: true,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: true, // is a no-op
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_OwnerGivesUpdateWriteAccessToAnotherActor_GQL_OtherActorCanUpdate(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives write(update) access to another actor",
+
+		SupportedMutationTypes: immutable.Some([]testUtils.MutationType{
+			// GQL mutation will return no error when wrong identity is used so test that separately.
+			testUtils.GQLRequestMutationType,
+		}),
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can not update yet.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				SkipLocalUpdateEvent: true,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can now update.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can now also read.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad Lone", // Note: updated name
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
diff --git a/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_update_test.go b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_update_test.go
new file mode 100644
index 0000000000..79d727a690
--- /dev/null
+++ b/tests/integration/acp/relationship/add_doc_actor_test/add_doc_actor_with_update_test.go
@@ -0,0 +1,541 @@
+// Copyright 2024 Democratized Data Foundation
+//
+// Use of this software is governed by the Business Source License
+// included in the file licenses/BSL.txt.
+//
+// As of the Change Date specified in that file, in accordance with
+// the Business Source License, use of this software will be governed
+// by the Apache License, Version 2.0, included in the file
+// licenses/APL.txt.
+
+package test_acp_relationship_add_docactor
+
+import (
+	"fmt"
+	"testing"
+
+	"github.com/sourcenetwork/immutable"
+
+	testUtils "github.com/sourcenetwork/defradb/tests/integration"
+)
+
+func TestACP_OwnerGivesUpdateWriteAccessToAnotherActorTwice_ShowThatTheRelationshipAlreadyExists(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives write(update) access to another actor twice, no-op",
+
+		SupportedMutationTypes: immutable.Some([]testUtils.MutationType{
+			testUtils.CollectionNamedMutationType,
+			testUtils.CollectionSaveMutationType,
+		}),
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can not update yet.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: true, // is a no-op
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_OwnerGivesUpdateWriteAccessToAnotherActor_OtherActorCanUpdate(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives write(update) access to another actor",
+
+		SupportedMutationTypes: immutable.Some([]testUtils.MutationType{
+			testUtils.CollectionNamedMutationType,
+			testUtils.CollectionSaveMutationType,
+		}),
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can not read yet.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{}, // Can't see the documents yet
+				},
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can not update yet.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+
+				ExpectedError: "document not found or not authorized to access",
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can now update.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can now also read.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad Lone", // Note: updated name
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
+
+func TestACP_OwnerGivesUpdateWriteAccessToAnotherActor_OtherActorCanUpdateSoCanTheOwner(t *testing.T) {
+	expectedPolicyID := "fc56b7509c20ac8ce682b3b9b4fdaad868a9c70dda6ec16720298be64f16e9a4"
+
+	test := testUtils.TestCase{
+
+		Description: "Test acp, owner gives write(update) access to another actor, both can read",
+
+		Actions: []any{
+			testUtils.AddPolicy{
+
+				Identity: immutable.Some(1),
+
+				Policy: `
+                    name: Test Policy
+
+                    description: A Policy
+
+                    actor:
+                      name: actor
+
+                    resources:
+                      users:
+                        permissions:
+                          read:
+                            expr: owner + reader + writer
+
+                          write:
+                            expr: owner + writer
+
+                          nothing:
+                            expr: dummy
+
+                        relations:
+                          owner:
+                            types:
+                              - actor
+
+                          reader:
+                            types:
+                              - actor
+
+                          writer:
+                            types:
+                              - actor
+
+                          admin:
+                            manages:
+                              - reader
+                            types:
+                              - actor
+
+                          dummy:
+                            types:
+                              - actor
+                `,
+
+				ExpectedPolicyID: expectedPolicyID,
+			},
+
+			testUtils.SchemaUpdate{
+				Schema: fmt.Sprintf(`
+						type Users @policy(
+							id: "%s",
+							resource: "users"
+						) {
+							name: String
+							age: Int
+						}
+					`,
+					expectedPolicyID,
+				),
+			},
+
+			testUtils.CreateDoc{
+				Identity: immutable.Some(1),
+
+				CollectionID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad",
+						"age": 28
+					}
+				`,
+			},
+
+			testUtils.AddDocActorRelationship{
+				RequestorIdentity: 1,
+
+				TargetIdentity: 2,
+
+				CollectionID: 0,
+
+				DocID: 0,
+
+				Relation: "writer",
+
+				ExpectedExistence: false,
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(2), // This identity can now update.
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Shahzad Lone"
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // This identity can now also read.
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Shahzad Lone", // Note: updated name
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+
+			testUtils.UpdateDoc{
+				CollectionID: 0,
+
+				Identity: immutable.Some(1), // Owner can still also update (ownership not transferred)
+
+				DocID: 0,
+
+				Doc: `
+					{
+						"name": "Lone"
+					}
+				`,
+			},
+
+			testUtils.Request{
+				Identity: immutable.Some(2), // Owner can still also read (ownership not transferred)
+
+				Request: `
+					query {
+						Users {
+							_docID
+							name
+							age
+						}
+					}
+				`,
+
+				Results: map[string]any{
+					"Users": []map[string]any{
+						{
+							"_docID": "bae-9d443d0c-52f6-568b-8f74-e8ff0825697b",
+							"name":   "Lone", // Note: updated name
+							"age":    int64(28),
+						},
+					},
+				},
+			},
+		},
+	}
+
+	testUtils.ExecuteTestCase(t, test)
+}
diff --git a/tests/integration/utils.go b/tests/integration/utils.go
index e6ab296140..eb0128ab00 100644
--- a/tests/integration/utils.go
+++ b/tests/integration/utils.go
@@ -340,6 +340,9 @@ func performAction(
 	case AddPolicy:
 		addPolicyACP(s, action)
 
+	case AddDocActorRelationship:
+		addDocActorRelationshipACP(s, action)
+
 	case CreateDoc:
 		createDoc(s, action)