Q1 was a slow quarter and had I had a 2,700 mile change of scenery in the meantime. This update won't be very visual. The goal of Q1 was to migrate completely from Mongo to a more robust database, of which we landed on Couchbase. After trying the half assed implementation of a couchbase adapter another developer had created I ended up having to write my own adapter which is fully compliant with the feathers query API (As well as tested and maintained). I have plans to continue development on this package to include additional controls for dealing with couchbase specific queries.

At the start of Q2 the entire application was running with couchbase as a backend. Although realtime interaction was and has been broken since the upgrade to feathers v3 and channels. With the upgrade I fully adopted the "services are data sources" approach to designing interactions with feathers. To put it simply everything is a service and you don't ever directly interact with a DB except through the adapter service. This approach greatly simplifies assumptions you make as you don't really care if it's backed by a DB, files, or some API service. Along with this new approach I decided Synk needed some protections on the API endpoints. It has gone too far and a big goal is to implement access control on all services and endpoints with minimal overhead. The good news is that I've written my own ACL system before and rewritten the ACL for Synk a few times at this point. This time around I leveraged a project named CASL which allows a developer to explain traits and roles in a declarative way.

For our use case there is a top level abilities module. From that module you're able to pull ACL definitions which is just a set of predefined rules based on a role that is applied to a users' account that targets a room or another subject. This allowed us to define high level groups while also having granular control. Another planned feature is to have wildcard permisisons. (i.e. room.* or room.modify.* vs room.modify.volume). Which wouldn't be too difficult to extend in time.

The ACL refactor took a good week of time as it's cumbersome to shuffle data around in a dynamic safe way without writing generic adapters. However the end result is a nice clean way to state permissions required for an endpoint. For a simple endpoint which requires no special wrappers to get extra data the hook to call looks like this.

{
  before: {
    create: [
      roomAbilities((abilities) => [abilities.can.create])       
    ]
  }
}

The roomAbilities wrapper just takes the context and creates an ACL abilities object which has the permission functions. The wrapper also handles evaluation of every rule you return in an OR. So every rule is evaluated. Rather than deal with complex AND and OR ability queries I abstract that into the ACL object which takes in generic data and based on that data it will produce true/false. This setup allows me to completely decouple the ability framework and test it independendly for rule validation and integration into the hooks to verify correct usage. Essentially the ACL system handles permissions in a pure testable way.

Another big endeavor with this update is fixing a halfassed attempt of an attach hook. In the context of couchbase since it is a NoSQL database there aren't really joins defined at the key-value level. N1QL supports JOIN's but they can be unreliable for resources just created as they need to be in the GSI before it works with feathersjs-couchbase. This may change in the future but for now it only supports N1QL & GSI. The attach hook now handles before/after joins as well as paginated finds or gets. It also supports sub-resource joins seemlessly. An example is retrieving the parent room object and automatically attaching the scenes to the room, where the scenes have instances and are also joined and the instances also result in their resources being attached. You're also able to forego attaching all fields on a subresource, but the plan to allow n-depth attachments and potentially avoid cyclic joins, as they are still not supported.

Q2 isn't a flashy update as in the past because it's been mostly paying back technical debt. Of which there is still plenty to pay, but I'm moving closer to having a dynamic fluid backend so the frontend can be agile and be feature complete. Getting ACL's out of the way was a huge hurdle for getting Synk ready for a public beta phase at some point.

The plans for Q3 have already bled over from Q2 as time is precious. Q3 is to refocus on the frontend and give it a functional look-over and prioritize ease of use and intuitiveness with the controls. The current layout of Synk doesn't lend itself to managing more resources than a handful. It's cumbersome to get a real look what is playing and where. To integrate with the new channels feature it might also be in store to refactor how sound events are carried out and instead use something like redux to handle sound state modifications.