In a standard relational based databases, the suggested place to write relationships to Permify is sending the write request in database transaction of the client action: such as assigning the user as owner.
If the transaction fails, you should delete the malformed relation tuple from Permify to maintain consistency.
Here's an example of how this might look in code:
```
func CreateDocuments(db *gorm.DB) error {
tx := db.Begin()
defer func() {
if r := recover(); r != nil {
tx.Rollback()
// if transaction fails, then delete malformed relation tuple
permify.DeleteData(...)
}
}()
if err := tx.Error; err != nil {
return err
}
if err := tx.Create(docs).Error; err != nil {
tx.Rollback()
// if transaction fails, then delete malformed relation tuple
permify.DeleteData(...)
return err
}
// if transaction successful, write relation tuple to Permify
permify.WriteData(...)
return tx.Commit().Error
}
```
Although this is an anti-pattern, this approach ensures that if the transaction in the application database fails and is rolled back, the corresponding data in Permify is also deleted, preventing inconsistencies.
You call this an anti-pattern (and rightfully so, since cluttering application code like this is a nightmare), but then what is the better pattern? In an app with >100 entities and >500 types of business transactions, many of which can fail in unexpected ways, will I be forced to maintain what was changed in Permify and roll back manually?
If yes, then this is quite a burden and might be a valid reason for not using a separate permissions store. But maybe there are better ways...?
Actually we have webhooks in our cloud offering to streamline and address this. Since this post is about our open source, I didn't mention it as an option. However, if you choose to go with the open source, you would need to maintain it manually as you described. Open to any suggestions on this. We're designing a functionality to add rollback to snapshots[0], but it likely won't be shipped in the near future.
If the transaction fails, you should delete the malformed relation tuple from Permify to maintain consistency.
Here's an example of how this might look in code:
```
func CreateDocuments(db *gorm.DB) error {
}```
Although this is an anti-pattern, this approach ensures that if the transaction in the application database fails and is rolled back, the corresponding data in Permify is also deleted, preventing inconsistencies.