How to define flexible sync subscriptions for collaboration platform

Hi everyone,

I’m looking for some best practices for platforms with collaboration features. I’m struggling with defining the queries for the flexible sync and with defining the permission roles for the schemas.

So imagine a platform where:

  • users can create (work)spaces
  • users can add contributors to the workspace
  • users can create bucketlists inside of this workspace
  • contributors should be able to read/create lists
  • users and contributors can add entries to the bucketlist
  • only the owner of the list/entry can edit or delete it
/// Custom User Meta Data from Authentication
class Account: Object {
    @Persisted(primaryKey: true) var _id: ObjectId    
}

/// Created on Authentication Trigger when User is created
class UserProfile: Object {
    @Persisted(primaryKey: true) var _id: ObjectId
    @Persisted var userId: String
    @Persisted var firstName: String
    @Persisted var lastName: String
    @Persisted var avatarImageUrl: String
}

class Space: Object {
    @Persisted(primaryKey: true) var _id: ObjectId
    @Persisted var title: String
    @Persisted var buckets: List<Bucket>
    @Persisted var contributors: List<UserProfile>

    /// Is there a better way of handling this?
    @Persisted var ownerId: String
    @Persisted var owner: UserProfile?
}

class Bucket: Object {
    @Persisted(primaryKey: true) var _id: ObjectId
    @Persisted var title: String
    @Persisted var entries: List<BucketEntry>
    @Persisted(originProperty: "buckets") var space: LinkingObjects<Space>

    @Persisted var ownerId: String
    @Persisted var owner: UserProfile?
}

class BucketEntry: Object {
    @Persisted(primaryKey: true) var _id: ObjectId
    @Persisted var title: String
    @Persisted(originProperty: "entries") var bucket: LinkingObjects<Bucket>

    @Persisted var ownerId: String
    @Persisted var owner: UserProfile?
}

My main question is: How should I configure the flexible sync to sync as less data as possible. Means only the spaces, buckets, entries which the user owns or is contributor of.

let config = user.flexibleSyncConfiguration(initialSubscriptions: { subs in
    if subs.first(named: "profiles") == nil {
        subs.append(QuerySubscription<UserProfile>(name: "profiles") {
            $0.userId == user.id /* plus profiles which are contributing to my spaces? */
        })
    }
    if subs.first(named: "spaces") == nil {
        subs.append(QuerySubscription<Space>(name: "spaces") {
            $0.ownerId == user.id || $0.contributors.userId.contains(user.id)
        })
    }
    if subs.first(named: "buckets") == nil {
        subs.append(QuerySubscription<Bucket>(name: "buckets") {
            $0.ownerId == user.id /* plus buckets in spaces I'm contributing to */
        })
    }
    if subs.first(named: "bucketEntries") == nil {
        subs.append(QuerySubscription<BucketEntry>(name: "bucketEntries") {
            $0.ownerId == user.id /* plus entries in buckets in spaces I'm contributing to */
        })
    }
})

When I understand it correctly I’m not able to do this:

if subs.first(named: "buckets") == nil {
    subs.append(QuerySubscription<Bucket>(name: "buckets") {
        $0.ownerId == user.id || $0.space.contributors.userId.contains(user.id)
    })
}

So what is best practice to handle these kind of nested relationships?

Another aspect of this I’m not sure of is how to define the roles/permissons in this scenario? I had a look on this article: https://www.mongodb.com/docs/atlas/app-services/sync/app-builder/device-sync-permissions-guide/#security

It seems one approach could be to store the information of the collaboration in the user meta data. It’s fine for the workspaces but how can I pass this deeper to the bucket and bucket entries