[{"data":1,"prerenderedAt":438},["ShallowReactive",2],{"footer-primary":3,"footer-secondary":93,"footer-description":119,"around-the-world-multitenancy-at-hybrid-heroes":121,"around-the-world-multitenancy-at-hybrid-heroes-next":164,"sales-reps":186},{"items":4},[5,29,49,69],{"id":6,"title":7,"url":8,"page":8,"children":9},"522e608a-77b0-4333-820d-d4f44be2ade1","Solutions",null,[10,15,20,25],{"id":11,"title":12,"url":8,"page":13},"fcafe85a-a798-4710-9e7a-776fe413aae5","Headless CMS",{"permalink":14},"/solutions/headless-cms",{"id":16,"title":17,"url":8,"page":18},"79972923-93cf-4777-9e32-5c9b0315fc10","Backend-as-a-Service",{"permalink":19},"/solutions/backend-as-a-service",{"id":21,"title":22,"url":8,"page":23},"0fa8d0c1-7b64-4f6f-939d-d7fdb99fc407","Product Information",{"permalink":24},"/solutions/product-information-management",{"id":26,"title":27,"url":28,"page":8},"63946d54-6052-4780-8ff4-91f5a9931dcc","100+ Things to Build","https://directus.io/blog/100-tools-apps-and-platforms-you-can-build-with-directus",{"id":30,"title":31,"url":8,"page":8,"children":32},"8ab4f9b1-f3e2-44d6-919b-011d91fe072f","Resources",[33,37,41,45],{"id":34,"title":35,"url":36,"page":8},"f951fb84-8777-4b84-9e91-996fe9d25483","Documentation","https://docs.directus.io",{"id":38,"title":39,"url":40,"page":8},"366febc7-a538-4c08-a326-e6204957f1e3","Guides","https://docs.directus.io/guides/",{"id":42,"title":43,"url":44,"page":8},"aeb9128e-1c5f-417f-863c-2449416433cd","Community","https://directus.chat",{"id":46,"title":47,"url":48,"page":8},"da1c2ed8-0a77-49b0-a903-49c56cb07de5","Release Notes","https://github.com/directus/directus/releases",{"id":50,"title":51,"url":8,"page":8,"children":52},"d61fae8c-7502-494a-822f-19ecff3d0256","Support",[53,57,61,65],{"id":54,"title":55,"url":56,"page":8},"8c43c781-7ebd-475f-a931-747e293c0a88","Issue Tracker","https://github.com/directus/directus/issues",{"id":58,"title":59,"url":60,"page":8},"d77bb78e-cf7b-4e01-932a-514414ba49d3","Feature Requests","https://github.com/directus/directus/discussions?discussions_q=is:open+sort:top",{"id":62,"title":63,"url":64,"page":8},"4346be2b-2c53-476e-b53b-becacec626a6","Community Chat","https://discord.com/channels/725371605378924594/741317677397704757",{"id":66,"title":67,"url":68,"page":8},"26c115d2-49f7-4edc-935e-d37d427fb89d","Cloud Dashboard","https://directus.cloud",{"id":70,"title":71,"url":8,"page":8,"children":72},"49141403-4f20-44ac-8453-25ace1265812","Organization",[73,78,84,88],{"id":74,"title":75,"url":76,"page":77},"1f36ea92-8a5e-47c8-914c-9822a8b9538a","About","/about",{"permalink":76},{"id":79,"title":80,"url":81,"page":82},"b84bf525-5471-4b14-a93c-225f6c386005","Careers","#",{"permalink":83},"/careers",{"id":85,"title":86,"url":87,"page":8},"86aabc3a-433d-434b-9efa-ad1d34be0a34","Brand Assets","https://drive.google.com/drive/folders/1lBOTba4RaA5ikqOn8Ewo4RYzD0XcymG9?usp=sharing",{"id":89,"title":90,"url":8,"page":91},"8d2fa1e3-198e-4405-81e1-2ceb858bc237","Contact",{"permalink":92},"/contact",{"items":94},[95,101,107,113],{"id":96,"title":97,"url":8,"page":98,"children":100},"8a1b7bfa-429d-4ffc-a650-2a5fdcf356da","Cloud Policies",{"permalink":99},"/cloud-policies",[],{"id":102,"title":103,"url":81,"page":104,"children":106},"bea848ef-828f-4306-8017-6b00ec5d4a0c","License",{"permalink":105},"/bsl",[],{"id":108,"title":109,"url":81,"page":110,"children":112},"4e914f47-4bee-42b7-b445-3119ee4196ef","Terms",{"permalink":111},"/terms",[],{"id":114,"title":115,"url":81,"page":116,"children":118},"ea69eda6-d317-4981-8421-fcabb1826bfd","Privacy",{"permalink":117},"/privacy",[],{"description":120},"\u003Cp>A composable backend to build your Headless CMS, BaaS, and more.&nbsp;\u003C/p>",{"id":122,"slug":123,"vimeo_id":124,"description":125,"tile":126,"length":127,"resources":8,"people":128,"episode_number":132,"published":133,"title":134,"video_transcript_html":135,"video_transcript_text":136,"content":8,"status":137,"episode_people":138,"recommendations":152,"season":153,"seo":8},"c1bf3bba-c29b-4d08-91b2-9c53b86d21cf","multitenancy-at-hybrid-heroes","894205000","We will walk you through the steps to implement segregation of client data using Directus fields and scripts to create the appropriate roles and permissions. We will also showcase a real-world use case and how our client benefit.","fbaa2f85-6d9b-4f92-9b1b-c07cda31e3d5",21,[129],{"name":130,"url":131},"Mariana Costa","https://marianacosta.xyz/",2,"2023-07-14","Multitenancy in Directus - Berlin Meetup","\u003Cp>Speaker 0: Okay then. So welcome everyone. So I'm Mariana. And today, I'm going to be talking a little bit about, we handle multi tenancy in one of our projects. So basically, like a startup guide for if you need to set up multitenancy in your project, just from the director's point of view, but hopefully it'll help you, like, make the process a little less, painful.\u003C/p>\u003Cp>Let's let's put it that way. So, yeah, I'm Mariana. I'm a software developer at Ivory Heroes. I've been at the company for, okay, a year 8 months, I think. And this is Joliel who is not here.\u003C/p>\u003Cp>Unfortunately, he was going to be co presenting with me, but something came up. So it's easier in spirit. So, and without without any further delays, let's just get right get right into it. So basically, the structure of the talk will be like, defining multi tenancy. So what it is, then the advantages, how why you might need it, why it may make sense for your own projects.\u003C/p>\u003Cp>Then basically, we'll do a small case study of 1 of our own projects where we had to implement multi tenancy. How we approached it, how we got started, and also the downsides of our approach and some other, like, general topics that also came up while we were doing this implementation. So, yeah, let's let's get right into it. So, basically, multi tenancy is an architecture where you have essentially one single instance to serve multiple clients. So let's say you want to set up a CMS to, for schools to set up their own block content.\u003C/p>\u003Cp>With multitenancy, you can have you can also only one instance of, of directors and serve all of all of the schools you want, while having the data collocated but separated from each other. So each school would only see the information that pertains to their own school. But, like, why would you want to do that? Why not just set up individual instances for for each school that would like to to use your services? So maybe maybe you want to lower infrastructure costs.\u003C/p>\u003Cp>So in some situations, and now we'll stress the some parts of the sentence because it's it's very dependent on the context. It may be cheaper to just have one single instance, if you don't, like, expect any crazy loads. So, the problem here is that sometimes scaling up just one instance may be more cumbersome than just having several single instances separated and deployed individually. So, yeah, as I said, this is very much it very much depends on on the context. For our case, it makes sense, but it may not make sense for for yours.\u003C/p>\u003Cp>So another possible benefit is that it can lower the the, entry barrier for your your potential clients. So and this is actually one of the reasons why we also choose this. So let's say we have a client that wants to use your product, but they don't really want to worry about the infrastructure. So they don't want to want to deploy anything. They don't want to run any infrastructure.\u003C/p>\u003Cp>They just want you to take care take care of all of it. And let's say you also don't really have the resources. We have multiple instances. Multi tenancy can help it can help with this. Like, a good compromise could be to just bear the costs of one single instance that can support multiple, tenants.\u003C/p>\u003Cp>And so you can also support multiple clients and a lower cost. And finally, this isn't really a reason that we, that resonated with us for our context, but it may resonate with you. It can make it easier to kind of aggregate data. So let's say you want to see which features of your, CMS are being used the most often by the most clients. It's easier when you just have, your data collocated.\u003C/p>\u003Cp>And, again, we don't really have a lot of experience with it, but it may be something that you are interested in. So let's let's say these these benefits, did convince you to to try out multi tenancy. I thought it would be the best to kinda look at a real life, example, And that's why we're going to use, our project that my team is currently working on as as an inspiration. So direct, which is kind of similar to directors and sometimes gets confusing when we talk about the project, in a company, is a platform that we're developing for Freunde visited Berlin. And it's basically focused on the management of, psychological studies.\u003C/p>\u003Cp>So it's basically a one stop shop for, coordinating a study, creating content for a study, distributing that content to potential study participants. Like one example of of, possible psychological study could be, like, to analyze the impact of immigration of an immigration process in an asylum seeker, for example. So where does multitenancy come into play in in in our product? So the main goal of our clients of AIUN VISITED was to be able to offer the platform to other partners. So think other universities, without having to ask them to set up their own infrastructure.\u003C/p>\u003Cp>So I feel would bear the cost of of the infrastructure and would offer the platform to other, to to other clients. But, Fine Infrastructure Debt also didn't really want to, push their own infrastructure cost too much. So the goal was to lower their own infrastructure costs and make it easier for other clients to adopt the platform. And so if, the these these requirements kinda match up nicely with with the advantages that I listed, above. So we kinda went ahead and implemented multi tenancy for this.\u003C/p>\u003Cp>So before we get started actually looking at the implementation, a quick side note. So today we'll be focusing on multitenancy just from the CMS point of view. However, your project and as our own did, probably has more moving parts. So there are more places where you have to implement multitenancy and there are more places where you have to set up systems that guarantee that multitenancy is insured on all of, on your entire platform. So direct direct itself is composed of several different systems.\u003C/p>\u003Cp>So we have a CMS to create the content. We have an app that is used by the study, participants. We have an admin panel that's used by the coordinators and then an API to kind of tie it all together. So we had to do a lot of changes in all of these, on all of these parts of the app. So today, we're gonna look at a small subset of, of multitenancy, obviously, focused on directors.\u003C/p>\u003Cp>And, hopefully, it'll be at least, like, a starting point for you to to kinda go through with with a pullbacking multi tenancy on at least one part of your of your product. So, yeah, with that said, like, let's jump right into it. So when you Google direct us multi tenancy, there are not a lot of results. Like there's not like one major guy that pops up to to, as as being, like, super relevant for your use case. We have a couple of, like, GitHub, issues, a glossary entry in the Directus website.\u003C/p>\u003Cp>We also have, like, more discussions, more GitHub discussions, the down further. So let's maybe look at the glossary entry for for multi tenancy. So, this entry provides a very similar definition to, the one that we looked at previously, but it adds some director specific details. So, basically, that's the two main ways that you can achieve multi tenancy, indirect. So either through project scoping or through wall scoping.\u003C/p>\u003Cp>So we, for our product opted for wall scoping because project scoping was just not a viable option for us. We self host, and we weren't really, it wasn't really viable to deploy multiple instances of directors as a project scoping approach does. But maybe if if you happen to use Directed Cloud, then, yeah, this definitely could be an option. It's just a disclaimer that we opted for rollscoping because it's all flows and at the moment, at the time, it's was the most reasonable option. So in this presentation, we're going to I'm going to showcase like a slightly modified approach of the roll scoping.\u003C/p>\u003Cp>So basically, instead of using, one word per tenant, we're gonna assign tenants to users. We found this approach to be a bit simpler, and it is also one that is, kind of promoted by direct. This is one of in one of their more or less recent videos, that talks about multitenancy. But both options are obviously, good, and it's just the context dependent. There's not much to one over the other.\u003C/p>\u003Cp>So regardless of which approach you choose, either assigning tenants to roles or to users, the main concept to keep in mind is permissions. So, in in our approach, the tenant based permissions are the core of the logic. So, essentially, it's these permissions that allow us to filter which items a user has access to based on the, on the tenant of that item and that user. So let's maybe to to kind of make it easier to visualize this. Let's take a look at all the data structure.\u003C/p>\u003Cp>So in in this approach, we have a tenant's collection, as a matter of guess, which allows you to to find the tenant. So in a real life scenario scenario, which is what we do, this creation, the credit permissions for the tenants are limited to the super admin role, and which is something that you also might consider because the tenants are a very, very privileged is a very privileged privileged collection. So after we create the tenants collection, we also need a way to actually assign the tenants to to things, to tenants and to users and other collections. So we create one to many, relations between the whichever collections you want to be, multi tenant and to the users, collection as well. So now we can assign tenants to things and to users, but we don't have data segregation at this point.\u003C/p>\u003Cp>So a a user from one tenant can see data from another tenant. So, but first, let's maybe look at at permissions. So, users belongs to roles and roles can have many permissions. And these permissions basically dictate how the roles can interact with the collections. So let's say we have a customer role and we, we have an admin role.\u003C/p>\u003Cp>We may want to prevent the customer role from creating in tenants while a site while allowing the admin role for correct permissions to to the tenant collection. So you may have noticed that in these two diagrams, the permissions, collection doesn't really have, a connection with the tenants. So how do we actually create the tenant based permissions that our system depends on? So to put it all together, we kind of need the last piece of the puzzle, which are rules, permission rules. Rules allow you to make this permission the permissions more specific.\u003C/p>\u003Cp>So in this case, we're adding a rule that states that the user can only access, an item in a collection if their tenant matches a tenant of that item. So let's say, this is a permission for the customer role to to read from the product collection. So this is basically the gist of how the multi tenancy solution with, with user permissions, goes. So you may be aware that also, besides the data structure, there are there's also the question of actually creating sorry. I have a question about that.\u003C/p>\u003Cp>Yes. Isn't it pretty tedious Exactly. We're gonna we're gonna we're gonna cover this right in the right in the next slide. So as I like like you said, it's it's very tedious to set up roles and permissions automatically, especially if you have like multiple deployments of, of the application. So and it's Stephenson is also error prone.\u003C/p>\u003Cp>So, if you forget to add a permission to a credit collection, then you're gonna be using our app and then you're gonna be, like, scratching your head, trying to understand why isn't is this not returning the items correctly? Or when I when I quit because I know that I created a collection. Why are they not showing up? So, you know, it's a very, very prominent. It's very tedious.\u003C/p>\u003Cp>So because we have a lot of collections and because we have several deployments, like in review apps, in staging and production environments, we kinda set up, automated permissions through, scripts. So we don't use it for this. We use external scripts, but the concept concept is is the same. So using the direct SDK, we fetch all of the collections that should support multi tenancy. So, in this case, we check the collect the collections that have a tenant field.\u003C/p>\u003Cp>And then we update the director's permission, system table to to include all of the permissions, that we want to support, and ensuring that the permissions field specifies that the rule that we we looked at a few slides ago, is is enforced, which ensures that users can only access, can only do specified actions, either reading or writing or sharing on the items that belong to their own tenant. And in addition to our own collections, you can obviously do this also to system collections. We also do it with files and folders because they, say it should be tenant specific as well. And the the logic is fairly similar. You just have to change the the target of of that permission.\u003C/p>\u003Cp>And so with this basic data structure and with these, automated, permissions, we can have a simple multitenancy to to start with. And as useful as we found this setup to be, we, this this approach kind of does come with some downsides, and I would highlight 2. So the first one would be complexity. So setting up a multi tenant system is inherently more difficult, especially if you have more than just a CMS. And in the multi tenancies system as is our our own case, we also have to add additional features like our clients, also wanted a multi tenant kind of work for a multi tenancy approach because they wanted customization.\u003C/p>\u003Cp>They wanted their tenants to be able to customize the UI. They want the to customize the way that the study flows. So it adds it's more complexity to to wrap your head around. It's just overall a are the solution to it to implement. And secondly, because the data is is co located, at least in this approach, it's we pay need to pay even more attention to security, especially if you're handling, very sensitive data like medical data.\u003C/p>\u003Cp>Like, we're placing a lot of trust in this in this multi tenancy system. So this comes at a cost. We need to implement more systems, more checks to make sure that the data release, segregated and, that we we can ensure our clients that, you know, no tenants can see sensitive information from other tenants. As with everything, basically, multi tenant is yes as trade offs. And there really isn't one clear cut rule that can tell you whether you should or should not implement a multitenancy for us.\u003C/p>\u003Cp>At the time it makes sense and it still continues to make sense. We're still working on it. We're still integrating on it, and it may or may not make sense for your project. And but, hopefully, this this brief intro will kind of at least, settle some, give you some stronger ground to to to thread when you start in, when you start exploring this topic. And we're almost done.\u003C/p>\u003Cp>But before before you go, I'd like to circle back on on what I said a few slides ago. So this this brief guide, let's put it that way, is meant as a starting point to multitenancy. So there are a lot of topics which I definitely did not cover today. Some things we have come across in our own product and we have solved them. Others which, we have encountered and the decided that we don't really have the resources or it doesn't really make sense to to tackle them right now.\u003C/p>\u003Cp>And surely, like many other many other topics we are not even aware of. So I just I gather a few here, like, a few topics of discussions for for examples. So how do you handle uniqueness across tenants, for example? So let's say you have a books collection and in the scheme of that collection you have an ISBN. So the, unique code that is attributed to 2 books, field that is set to unique.\u003C/p>\u003Cp>And then 2 of your tenants have the same book, and the first tenant tries to add a book to a collection and it's offline. And then the second the second tenant second user in another tenant tries to add a book and throw an arrow stone because the field is supposed to be unique. So how do you handle the situation? So you can maybe set up a composite index, so that the unique constraint applies only to the ISBN tenant pair and not just the ISBN. But as far as I know, this is not a natively supported indirect.\u003C/p>\u003Cp>So you would have to do some workarounds. You'd have to implement some custom interface to show that. But it is a possibility. Or you can even remove the unique constraint if if you think that it doesn't really compromise the integrity of your data schema, it can be it can be easier to just remove the constraints if you can ensure that the system is still compliant with with your with your architecture. And what about tenancy outside of directors?\u003C/p>\u003Cp>I did mention before that we have several other systems in our platform. So how how do you sync up the tenants collection with with external services? So we can you can set up scripts that run periodically and sync the necessary information, which is what we do, or you can also make use of direct to Saks, which is also something that we are considering, and something that possibly we will start adopting. And what about permissions? Like, how do you keep permissions up to date?\u003C/p>\u003Cp>If a new collection is added, it's just as come or correctly. So in our use case, we, the automation for this, for this, that it wasn't really worth the effort, but you can also adopt a similar approach to the tenancy that I mentioned in the point above. And, finally, like I said previously, we are following a user based tenancy as opposed to a world based one. But as I said, both options are are viable. I've linked some discussions, in the appendices of of the, of this presentation that do go further into into this topic if you like, if you're interested.\u003C/p>\u003Cp>But, yeah, I'm sure there are many, many more topics that we haven't really had the chance to to cover, but hopefully this is a good for the, for the discussion. And I do hope that this presentation kind of provided you with a solid, solid introduction to, to multitenancy and that it can make its implementation a little bit less, less painful. And, yeah, I think I think that's it. Thank you all for listening. I left my email there if you're interested in just asking whatever about the presentation, about the product or whatever you you can think of.\u003C/p>\u003Cp>And, yeah, if you have any questions, then let me know. If you don't, then that's fine. I'm not, I won't get mad, but yeah. Thank you.\u003C/p>","Okay then. So welcome everyone. So I'm Mariana. And today, I'm going to be talking a little bit about, we handle multi tenancy in one of our projects. So basically, like a startup guide for if you need to set up multitenancy in your project, just from the director's point of view, but hopefully it'll help you, like, make the process a little less, painful. Let's let's put it that way. So, yeah, I'm Mariana. I'm a software developer at Ivory Heroes. I've been at the company for, okay, a year 8 months, I think. And this is Joliel who is not here. Unfortunately, he was going to be co presenting with me, but something came up. So it's easier in spirit. So, and without without any further delays, let's just get right get right into it. So basically, the structure of the talk will be like, defining multi tenancy. So what it is, then the advantages, how why you might need it, why it may make sense for your own projects. Then basically, we'll do a small case study of 1 of our own projects where we had to implement multi tenancy. How we approached it, how we got started, and also the downsides of our approach and some other, like, general topics that also came up while we were doing this implementation. So, yeah, let's let's get right into it. So, basically, multi tenancy is an architecture where you have essentially one single instance to serve multiple clients. So let's say you want to set up a CMS to, for schools to set up their own block content. With multitenancy, you can have you can also only one instance of, of directors and serve all of all of the schools you want, while having the data collocated but separated from each other. So each school would only see the information that pertains to their own school. But, like, why would you want to do that? Why not just set up individual instances for for each school that would like to to use your services? So maybe maybe you want to lower infrastructure costs. So in some situations, and now we'll stress the some parts of the sentence because it's it's very dependent on the context. It may be cheaper to just have one single instance, if you don't, like, expect any crazy loads. So, the problem here is that sometimes scaling up just one instance may be more cumbersome than just having several single instances separated and deployed individually. So, yeah, as I said, this is very much it very much depends on on the context. For our case, it makes sense, but it may not make sense for for yours. So another possible benefit is that it can lower the the, entry barrier for your your potential clients. So and this is actually one of the reasons why we also choose this. So let's say we have a client that wants to use your product, but they don't really want to worry about the infrastructure. So they don't want to want to deploy anything. They don't want to run any infrastructure. They just want you to take care take care of all of it. And let's say you also don't really have the resources. We have multiple instances. Multi tenancy can help it can help with this. Like, a good compromise could be to just bear the costs of one single instance that can support multiple, tenants. And so you can also support multiple clients and a lower cost. And finally, this isn't really a reason that we, that resonated with us for our context, but it may resonate with you. It can make it easier to kind of aggregate data. So let's say you want to see which features of your, CMS are being used the most often by the most clients. It's easier when you just have, your data collocated. And, again, we don't really have a lot of experience with it, but it may be something that you are interested in. So let's let's say these these benefits, did convince you to to try out multi tenancy. I thought it would be the best to kinda look at a real life, example, And that's why we're going to use, our project that my team is currently working on as as an inspiration. So direct, which is kind of similar to directors and sometimes gets confusing when we talk about the project, in a company, is a platform that we're developing for Freunde visited Berlin. And it's basically focused on the management of, psychological studies. So it's basically a one stop shop for, coordinating a study, creating content for a study, distributing that content to potential study participants. Like one example of of, possible psychological study could be, like, to analyze the impact of immigration of an immigration process in an asylum seeker, for example. So where does multitenancy come into play in in in our product? So the main goal of our clients of AIUN VISITED was to be able to offer the platform to other partners. So think other universities, without having to ask them to set up their own infrastructure. So I feel would bear the cost of of the infrastructure and would offer the platform to other, to to other clients. But, Fine Infrastructure Debt also didn't really want to, push their own infrastructure cost too much. So the goal was to lower their own infrastructure costs and make it easier for other clients to adopt the platform. And so if, the these these requirements kinda match up nicely with with the advantages that I listed, above. So we kinda went ahead and implemented multi tenancy for this. So before we get started actually looking at the implementation, a quick side note. So today we'll be focusing on multitenancy just from the CMS point of view. However, your project and as our own did, probably has more moving parts. So there are more places where you have to implement multitenancy and there are more places where you have to set up systems that guarantee that multitenancy is insured on all of, on your entire platform. So direct direct itself is composed of several different systems. So we have a CMS to create the content. We have an app that is used by the study, participants. We have an admin panel that's used by the coordinators and then an API to kind of tie it all together. So we had to do a lot of changes in all of these, on all of these parts of the app. So today, we're gonna look at a small subset of, of multitenancy, obviously, focused on directors. And, hopefully, it'll be at least, like, a starting point for you to to kinda go through with with a pullbacking multi tenancy on at least one part of your of your product. So, yeah, with that said, like, let's jump right into it. So when you Google direct us multi tenancy, there are not a lot of results. Like there's not like one major guy that pops up to to, as as being, like, super relevant for your use case. We have a couple of, like, GitHub, issues, a glossary entry in the Directus website. We also have, like, more discussions, more GitHub discussions, the down further. So let's maybe look at the glossary entry for for multi tenancy. So, this entry provides a very similar definition to, the one that we looked at previously, but it adds some director specific details. So, basically, that's the two main ways that you can achieve multi tenancy, indirect. So either through project scoping or through wall scoping. So we, for our product opted for wall scoping because project scoping was just not a viable option for us. We self host, and we weren't really, it wasn't really viable to deploy multiple instances of directors as a project scoping approach does. But maybe if if you happen to use Directed Cloud, then, yeah, this definitely could be an option. It's just a disclaimer that we opted for rollscoping because it's all flows and at the moment, at the time, it's was the most reasonable option. So in this presentation, we're going to I'm going to showcase like a slightly modified approach of the roll scoping. So basically, instead of using, one word per tenant, we're gonna assign tenants to users. We found this approach to be a bit simpler, and it is also one that is, kind of promoted by direct. This is one of in one of their more or less recent videos, that talks about multitenancy. But both options are obviously, good, and it's just the context dependent. There's not much to one over the other. So regardless of which approach you choose, either assigning tenants to roles or to users, the main concept to keep in mind is permissions. So, in in our approach, the tenant based permissions are the core of the logic. So, essentially, it's these permissions that allow us to filter which items a user has access to based on the, on the tenant of that item and that user. So let's maybe to to kind of make it easier to visualize this. Let's take a look at all the data structure. So in in this approach, we have a tenant's collection, as a matter of guess, which allows you to to find the tenant. So in a real life scenario scenario, which is what we do, this creation, the credit permissions for the tenants are limited to the super admin role, and which is something that you also might consider because the tenants are a very, very privileged is a very privileged privileged collection. So after we create the tenants collection, we also need a way to actually assign the tenants to to things, to tenants and to users and other collections. So we create one to many, relations between the whichever collections you want to be, multi tenant and to the users, collection as well. So now we can assign tenants to things and to users, but we don't have data segregation at this point. So a a user from one tenant can see data from another tenant. So, but first, let's maybe look at at permissions. So, users belongs to roles and roles can have many permissions. And these permissions basically dictate how the roles can interact with the collections. So let's say we have a customer role and we, we have an admin role. We may want to prevent the customer role from creating in tenants while a site while allowing the admin role for correct permissions to to the tenant collection. So you may have noticed that in these two diagrams, the permissions, collection doesn't really have, a connection with the tenants. So how do we actually create the tenant based permissions that our system depends on? So to put it all together, we kind of need the last piece of the puzzle, which are rules, permission rules. Rules allow you to make this permission the permissions more specific. So in this case, we're adding a rule that states that the user can only access, an item in a collection if their tenant matches a tenant of that item. So let's say, this is a permission for the customer role to to read from the product collection. So this is basically the gist of how the multi tenancy solution with, with user permissions, goes. So you may be aware that also, besides the data structure, there are there's also the question of actually creating sorry. I have a question about that. Yes. Isn't it pretty tedious Exactly. We're gonna we're gonna we're gonna cover this right in the right in the next slide. So as I like like you said, it's it's very tedious to set up roles and permissions automatically, especially if you have like multiple deployments of, of the application. So and it's Stephenson is also error prone. So, if you forget to add a permission to a credit collection, then you're gonna be using our app and then you're gonna be, like, scratching your head, trying to understand why isn't is this not returning the items correctly? Or when I when I quit because I know that I created a collection. Why are they not showing up? So, you know, it's a very, very prominent. It's very tedious. So because we have a lot of collections and because we have several deployments, like in review apps, in staging and production environments, we kinda set up, automated permissions through, scripts. So we don't use it for this. We use external scripts, but the concept concept is is the same. So using the direct SDK, we fetch all of the collections that should support multi tenancy. So, in this case, we check the collect the collections that have a tenant field. And then we update the director's permission, system table to to include all of the permissions, that we want to support, and ensuring that the permissions field specifies that the rule that we we looked at a few slides ago, is is enforced, which ensures that users can only access, can only do specified actions, either reading or writing or sharing on the items that belong to their own tenant. And in addition to our own collections, you can obviously do this also to system collections. We also do it with files and folders because they, say it should be tenant specific as well. And the the logic is fairly similar. You just have to change the the target of of that permission. And so with this basic data structure and with these, automated, permissions, we can have a simple multitenancy to to start with. And as useful as we found this setup to be, we, this this approach kind of does come with some downsides, and I would highlight 2. So the first one would be complexity. So setting up a multi tenant system is inherently more difficult, especially if you have more than just a CMS. And in the multi tenancies system as is our our own case, we also have to add additional features like our clients, also wanted a multi tenant kind of work for a multi tenancy approach because they wanted customization. They wanted their tenants to be able to customize the UI. They want the to customize the way that the study flows. So it adds it's more complexity to to wrap your head around. It's just overall a are the solution to it to implement. And secondly, because the data is is co located, at least in this approach, it's we pay need to pay even more attention to security, especially if you're handling, very sensitive data like medical data. Like, we're placing a lot of trust in this in this multi tenancy system. So this comes at a cost. We need to implement more systems, more checks to make sure that the data release, segregated and, that we we can ensure our clients that, you know, no tenants can see sensitive information from other tenants. As with everything, basically, multi tenant is yes as trade offs. And there really isn't one clear cut rule that can tell you whether you should or should not implement a multitenancy for us. At the time it makes sense and it still continues to make sense. We're still working on it. We're still integrating on it, and it may or may not make sense for your project. And but, hopefully, this this brief intro will kind of at least, settle some, give you some stronger ground to to to thread when you start in, when you start exploring this topic. And we're almost done. But before before you go, I'd like to circle back on on what I said a few slides ago. So this this brief guide, let's put it that way, is meant as a starting point to multitenancy. So there are a lot of topics which I definitely did not cover today. Some things we have come across in our own product and we have solved them. Others which, we have encountered and the decided that we don't really have the resources or it doesn't really make sense to to tackle them right now. And surely, like many other many other topics we are not even aware of. So I just I gather a few here, like, a few topics of discussions for for examples. So how do you handle uniqueness across tenants, for example? So let's say you have a books collection and in the scheme of that collection you have an ISBN. So the, unique code that is attributed to 2 books, field that is set to unique. And then 2 of your tenants have the same book, and the first tenant tries to add a book to a collection and it's offline. And then the second the second tenant second user in another tenant tries to add a book and throw an arrow stone because the field is supposed to be unique. So how do you handle the situation? So you can maybe set up a composite index, so that the unique constraint applies only to the ISBN tenant pair and not just the ISBN. But as far as I know, this is not a natively supported indirect. So you would have to do some workarounds. You'd have to implement some custom interface to show that. But it is a possibility. Or you can even remove the unique constraint if if you think that it doesn't really compromise the integrity of your data schema, it can be it can be easier to just remove the constraints if you can ensure that the system is still compliant with with your with your architecture. And what about tenancy outside of directors? I did mention before that we have several other systems in our platform. So how how do you sync up the tenants collection with with external services? So we can you can set up scripts that run periodically and sync the necessary information, which is what we do, or you can also make use of direct to Saks, which is also something that we are considering, and something that possibly we will start adopting. And what about permissions? Like, how do you keep permissions up to date? If a new collection is added, it's just as come or correctly. So in our use case, we, the automation for this, for this, that it wasn't really worth the effort, but you can also adopt a similar approach to the tenancy that I mentioned in the point above. And, finally, like I said previously, we are following a user based tenancy as opposed to a world based one. But as I said, both options are are viable. I've linked some discussions, in the appendices of of the, of this presentation that do go further into into this topic if you like, if you're interested. But, yeah, I'm sure there are many, many more topics that we haven't really had the chance to to cover, but hopefully this is a good for the, for the discussion. And I do hope that this presentation kind of provided you with a solid, solid introduction to, to multitenancy and that it can make its implementation a little bit less, less painful. And, yeah, I think I think that's it. Thank you all for listening. I left my email there if you're interested in just asking whatever about the presentation, about the product or whatever you you can think of. And, yeah, if you have any questions, then let me know. If you don't, then that's fine. I'm not, I won't get mad, but yeah. Thank you.","published",[139],{"people_id":140},{"id":141,"first_name":142,"last_name":143,"avatar":144,"bio":145,"links":146},"3f446f06-d786-49a0-a66d-0325d032848b","Mariana","Costa","fa797563-eab9-4e9a-9170-9f37dbfe15d4","Software Developer at Hybrid Heroes",[147,149],{"url":131,"service":148},"website",{"service":150,"url":151},"github","https://github.com/marianafcosta",[],{"id":154,"number":155,"year":156,"episodes":157,"show":161},"dac1d26f-8071-4acc-a556-3fc30d03496a",1,"2023",[158,122,159,160],"fa893567-1d64-43e6-9cfd-a79380b49d8e","0edf83f5-87d4-4ea1-8030-0dbf472d228f","a25a20b8-6c18-49fb-b0a1-84a57025aebb",{"title":162,"tile":163},"Around the World","430ec649-8c29-4657-9425-2981fbae18c6",{"id":159,"slug":165,"season":154,"vimeo_id":166,"description":167,"tile":168,"length":169,"resources":170,"people":174,"episode_number":178,"published":179,"title":180,"video_transcript_html":181,"video_transcript_text":182,"content":8,"seo":8,"status":137,"episode_people":183,"recommendations":185},"extending-online-art-gallery","894204814","Using Directus extensions, we augmented Directus to add functionality to generate blurhashes for the smooth loading of high-quality full-screen images.","5a9d3778-c4df-46a1-b60f-c05a32784930",19,[171],{"name":172,"url":173},"Pixie Labs","https://www.pixielabs.io/",[175],{"name":176,"url":177},"David Somers","https://www.linkedin.com/in/jalada",3,"2023-08-23","Extending Directus for an Online Art Gallery - London Meetup","\u003Cp>Speaker 0: Alright. Hi. My name's David. I'm gonna tell you a little bit about, extending directors to build a beautiful online art gallery. Can everyone hear me okay?\u003C/p>\u003Cp>If you can't, please, like, wave at me, shout at me, be like, Can't hear you. And then I'll speak up, we'll move this. A quick show of hands just so I can gauge, who here has used Directus on a project? Great. Good start.\u003C/p>\u003Cp>Who has used it for more than one project? Just because I'm curious. Nice. Who has, when they've been working on a director's project, you've used an extension as part of that? Alright.\u003C/p>\u003Cp>Starting to shrink. Great. Who has written a custom extension? Okay. Great.\u003C/p>\u003Cp>Phew. Otherwise, I was worried that I was going to be like, hey, you guys tell me how to write an extension. All right. Before I start, a little bit about me. I'm David.\u003C/p>\u003Cp>I'm head of engineering at Pixilabs. We are a digital product development agency. That means that we design and develop digital products, everything from internal platforms for FTSE 100 companies to manage smart home device installations, helping funded startups launch their product, all the way down to we once made a typewriter type by itself when you tweeted at it. And that was part of a digital art installation for Twitter, which was really fun. Basically, if we can code it, we will do our best to do that.\u003C/p>\u003Cp>And, actually, most of the time we build, like, full stack web applications in Ruby on Rails. But sometimes, we need a headless CMS and sometimes, we often turn to directors. So that's what I wanna talk to you about, not the Ruby on Rails apps. Just because I thought it would be interesting, like, if I was here, I would wanna know what are people what are other people making with Directus. Right?\u003C/p>\u003Cp>So I thought I'd show you a couple of things that we've made at Pixielabs. The first one, is a company called Blackwing 7. They make bespoke cinematography lenses for film, TV, music videos, things like that. This is kinda what you maybe a site that you would traditionally expect for a headless CMS. Right?\u003C/p>\u003Cp>So, we actually took this over from another agency. It was all completely static, and the client wanted to be able to edit little bits of it, make some of it interactive, and things like that. And so that was something that we kind of turned to Directus to build. Something maybe a bit more unusual, thinking about that kind of, like, not just a headless CMS kind of vibe. This was a for good project called Red Flags.\u003C/p>\u003Cp>You can kind of think of it as like hazard perception but for consent. If any of you have taken your driving test and you've done the hazard perception, you know, you're watching a video of someone driving, usually through Wales, and you click a button every time there's a sheep on the road. Basically, that, but, but, yeah, for for consent. So there's, like, a video that you watch of someone going on a first date and you click a button every time you see, a, you know, an issue to do with consent. This was a campaign around that.\u003C/p>\u003Cp>And at the end, you get a score of how many you spotted or how many you missed, and you get to submit some details about you to sort of help their campaign, help understand who is engaging with this. And that's particularly interesting because that was where we were kind of using that ability. You know, Directus is ultimately just a wrapper around a database. Right? And so we could use that to store those results that were being submitted alongside the content that was part of the website as well.\u003C/p>\u003Cp>So really acting as more like a basic kind of app data store there than just a headless CMS. You kind of maybe something you might use Firebase for as well maybe is kind of like a sort of point of comparison. Kind of interesting. I'm gonna talk about a different project, for a client called Depuri that we worked on. I'm gonna tell you a little bit about that project, why we picked Directus, the extension that we had to build.\u003C/p>\u003Cp>That's the meat of it. And some tips as well for building your own extension if you, you know, are sort of wondering about how you'd go about doing that. Hopefully, by the end, you're gonna know some pitfalls to avoid if you do go about building an extension, how to get started as well, and, also, you're gonna hopefully know the best, in my opinion, way to, progressively load images on a website if you wanna do it in, like, a really, kind of optimum way because that's the extension that we built. So the project was, to build this kind of beautiful online art gallery, for a new brand, of online art curation and auctions called De Pury. We did a whole kind of tech stack evaluation and architecture process for this, and we recognized a couple of things.\u003C/p>\u003Cp>We knew that we wanted a bespoke front end so that we could wield all of our front end power, and we wanted a layer there that could, you know, we could kind of do whatever we wanted to do. So, we knew that the designs were gonna be you know, they wanted it to feel luxurious and feel sophisticated and expensive, and so we knew that we needed to be able to kind of tweak it a lot. And we recognized early on we needed a CMS because we did not want to have to edit all the content by hand. We wanted the client to do that. So we recognized pretty quickly that we needed a headless CMS.\u003C/p>\u003Cp>So Directus ended up being a good fit for a few reasons, actually. First of all, the image handling in Directus, if you've not explored that a bit, is really cool. We knew we were gonna need to be able to do resizing for different devices. We potentially thought we might have to do sort of interesting transformations of images. Maybe we wanted to make them grayscale or blur them or anything like that as part of the designs.\u003C/p>\u003Cp>And, Directus exposes the whole of the Sharp API. I don't know if anyone's a JavaScript dev. You might be familiar with Sharp. It's like ImageMagick or something like that. It's a really great package for manipulating images.\u003C/p>\u003Cp>Directus just gives you that whole thing. You can just drive it via the API which is super cool. You can also configure it to cache forever and have no expiry on caching. Right? Which was useful for us.\u003C/p>\u003Cp>We didn't want images randomly loading slow because Contentful had decided to delete some of our images from their cache or something like that. We really like the API. A lot of headless CMSs at GraphQL. I'm not really a huge fan of GraphQL. Really like that there's a REST API with Directus.\u003C/p>\u003Cp>It's just quicker and easier to get up and running for a small project. Right? It's easy to deploy. Tapuri had some existing infrastructure on Amazon Web Services, and so it's just a Node. Js app.\u003C/p>\u003Cp>You can deploy it somewhere. It'll align nicely with that. And lastly, we knew that we could extend it. Right? We felt comfort as we went into this project that we were like, well, if if there's something that directors can't do, we can at least write some JavaScript to make it do what we needed.\u003C/p>\u003Cp>It turns out, we did need it. So direct us wasn't quite enough. Once we got going, and we were iterating, we identified a problem with the way that the images were loading. The website was full of these large, high quality images. They wanted to sort of full bleed, you know, images of the artwork, that was being curated.\u003C/p>\u003Cp>And there were also just, like, galleries and it was just images. Right? Just thumbnails of images. And we wanted these to feel great, especially on mobile devices. The default approach, usually, is to do something like, low quality image placeholders.\u003C/p>\u003Cp>Is anyone is anyone familiar with the concept of low quality image placeholders? If you're not, it's like where you basically request a really tiny image that's, like, 6 by 6 pixels, then you make it as big as you want it, and you add some kind of blur to it. Right? And then as the real image loads, you cross fade from one to the other. You get kind of a nice fade as the image loads rather than just, like, a gray box.\u003C/p>\u003Cp>The problem is that that still takes time. Right? The page loads. We've got, like, 50 images that we wanna load. Now we're asking someone's web browser to load 50 images.\u003C/p>\u003Cp>Still lots of requests and so we ended up in this situation, the client wasn't happy with it, where you've got a bunch of gray boxes that quickly change to these blurry versions of images and then they change again to the real image and it just didn't look great. Right? Fortunately, we had a solution in our back pocket that we'd used before which is called blur hash. Is anyone familiar with blur hash as a thing? Alright.\u003C/p>\u003Cp>Great. Mostly shaking of heads, which is good. So Blahash, is a solution to this. It was made by a company called WALT, which is like a European Deliveroo competitor, which I hadn't heard of, I guess because we have Deliveroo. And they built a thing to to solve this problem.\u003C/p>\u003Cp>I'll just show you it quickly. So it's kind of like a representation of a placeholder of an image. Right? So, imagine they had the same problem. Right?\u003C/p>\u003Cp>They had this nice app and they just had these gray boxes and they were annoyed about it. What you basically do is you feed your image into the blur hash algorithm and you get, like, a very short representation of a blurry version of that image. Really, really short, like 10 to 20 characters, which you can then pass back to the blur hash library and it will generate a kind of blurry, smooshed version of the image. And what's cool about this over low quality image placeholders is that there's no extra request. You can include this, so when you're getting the data for your page, you're getting the data about your images, you can have the blur hash ready to go alongside the, like, URL, width, and height.\u003C/p>\u003Cp>So there's no extra request. One request for everything and you've already got those placeholder images. Super useful for us. Alright. So we knew we wanted blur hash.\u003C/p>\u003Cp>Directus doesn't have blur hash support by default, so so we needed to build an extension. Specifically, we built a hook extension, and I'll talk a little bit about different types of extensions but that, basically, is, like, custom JavaScript code that you can write and it will run at certain points defined by directors. Right? So, if you've ever written WordPress plugins, maybe, where you've got hooks, that'll feel really familiar or any kind of event based programming in JavaScript, you know, where you're like on this event, do this code. Basically, that.\u003C/p>\u003Cp>So, in theory, we were like, well, this is pretty straightforward. We want to add a new field against all our images to store the blur hash. Then, when an image is created or modified using that hook, we want to use the blur hash library to calculate that string that you saw for the image and then save it into that new field. In reality, there were a few interesting gotchas which I'll tell you about, but in principle it was pretty straightforward. I'll just show you it quickly, what it looks like in reality.\u003C/p>\u003Cp>So this was the site. Ignore my dev tools on the side here because I've got network throttling on to try and show you what it looks like. Please find the right button eventually. Hopefully, I've refreshed and cleared cache. Yeah.\u003C/p>\u003Cp>So, you can see the effect where the blur hash is already there and then it crossfades to the image. As I scroll down, some of these are still even on a pretend 3 gs they're still loading in time. But, you can see the effect. There's no flicker from one to another. There's no gray, then color, then image.\u003C/p>\u003Cp>It's just straight in. Some of the of course, they're now loading. You know, there we go. There's 1. We can go and look at this in Directus as well.\u003C/p>\u003Cp>So if I come in here, this is the Directus instance for this site, this is for the home page. If I create a new block here, I'm gonna pretend like they're curating my own photos. So if I create this home page block, if I go back and look at that now and go and look and edit that image, we can see that the blur hash has been added. Right? So the extension's got that field in there.\u003C/p>\u003Cp>It's generated it on save, and it's put it against the image. So now if I go and have a look, hopefully Imagine if it doesn't work out. Live demos was the worst. I tried to keep this one really simple. Yeah.\u003C/p>\u003Cp>So you can see the blur hash loaded straightaway and then, on my simulated 3 gs, eventually, my image loads. Look at that. Oh, there was one other thing as well. We were talking about that nice REST API. So you can see here, right, this is the this is all the JSON for the homepage.\u003C/p>\u003Cp>Single request to get the home page and get all of the related fields. Yeah? Sorry, can you carry on the flow? I'll ask when you're done. Okay.\u003C/p>\u003Cp>Yeah. I've got space for questions at the end. Hold it hold it in your head if you can. Yeah. So you can see, you can see the blur hashes here being included in with the JSON.\u003C/p>\u003Cp>Right? So they're all ready to go. Just drop it on. Cool. Alright.\u003C/p>\u003Cp>The fun stuff. What did we learn? Quite a bit. First of all, there's a Director's extension SDK, which is super useful for getting started. It has a nice kind of, like, command line interface for getting set up.\u003C/p>\u003Cp>It generates a kind of, like, directory depending on It asks you what kind of extension you wanna make, puts it all together for you, and kinda gets you started. There are lots of types of extensions, and that can be confusing. These are all the different types. Also, they're all kinda subtly different, in the way that they're, like, put together. At least when we were doing ours, hooks are are JavaScript and they're compiled using a thing called roll up, which I'll talk about in a sec.\u003C/p>\u003Cp>But then app extensions are like ECMAScript modules, and they're loaded in a little bit differently and it's very confusing and it's moved around a little bit and, yeah, there's definitely some funkiness there to watch out for. When you build an extension, especially a hook extension, all of the internal API services are made available to you. They're, like, handed to your code. Like, Here you go. You can use all of this stuff.\u003C/p>\u003Cp>There's no documentation for what any of that stuff is, Not even in the source code, there's not really comments for it. So you do have to kind of poke around to try and find what you need. I can actually show you an example where we've got our extension source code here. It's a little bit small, I know. But like this here, we're, like, calling the this asset service is coming from Directus.\u003C/p>\u003Cp>Directus is giving it to us. Presumably, they want us to use it. But this get asset method, you've just gotta guess, what it's doing. Right? And it changes because it's an internal API and I did feel a little bit nervous putting it in here, I will admit.\u003C/p>\u003Cp>But, hey, it works. So look over the source code. They are there to use. There's also no agreed way to embed a database migration in an extension. So you can write a migration as part of your as part of a director's extension.\u003C/p>\u003Cp>But, like, if you wanna release an extension that does something to the database, there's no kind of agreed way of doing that. That made us a little bit nervous. I think there's a few different approaches. You can ask the user to put it in themselves. You can copy it in sneak.\u003C/p>\u003Cp>Ly, which is what we do, or you can just do it at run time, which feels a little bit scary. Rollup, which is a tool that, at least for hook extensions is being used to kinda compile the extension. So you write your extension code and then Rollup builds it. Not webpack or anything like that. It's Rollup.\u003C/p>\u003Cp>Kind of funky. It does some weird stuff if you want some dependencies. If you're including some dependencies for your extension, roll up's gonna do its best to try and push those all to your extension, and it can make a bit of a mess. And that kinda relates to this. Testing locally can be painful.\u003C/p>\u003Cp>There is some stuff to help. The Director's, extension SDK has, like, a link tool that you can use to link your extension code into, like, a local Director. So while you're devbing and you're playing around, you can try stuff out That can mess with nodes, like dependency resolution, which can cause you trouble. So watch out for that. But, all that said, reading other extension code is super useful and there's 2 really great ways of doing that.\u003C/p>\u003Cp>1 is that there's this awesome Directus on GitHub. Everyone loves an awesome something on GitHub, which has got a list of extensions. Super useful to go through and look and see how are other people doing this, how are people solving this problem. And, also, you can just go on to npm and search keywords directors extension because that SDK adds that by default to your package JSON. So if anyone who does that and then publishes it, it gets added as a keyword, which makes it super easy to search.\u003C/p>\u003Cp>I think that was probably intentional so that they can find all the director's extensions, But useful as well if you're building your own. And hopefully, this doesn't I know there's a lot of negatives there, but it was kind of a, like, here's some stuff to watch out for. In general, it was actually pretty straightforward. The extension's only a 100 lines of code. There's not a lot to it.\u003C/p>\u003Cp>Right? And it was very easy to get started. And I think, like, there's lots of opportunities to build stuff here. Right? Like, this is a community, it's open source, which actually Kevin is gonna talk about.\u003C/p>\u003Cp>And it's hard to sell open source to clients, but it does sell well to us and to the team. Like, we believe quite strongly in open source as well. So being able to, like, do this and give back, is great. Yeah. Hopefully hopefully, that was useful and interesting.\u003C/p>\u003Cp>Thanks for listening, if it wasn't.\u003C/p>","Alright. Hi. My name's David. I'm gonna tell you a little bit about, extending directors to build a beautiful online art gallery. Can everyone hear me okay? If you can't, please, like, wave at me, shout at me, be like, Can't hear you. And then I'll speak up, we'll move this. A quick show of hands just so I can gauge, who here has used Directus on a project? Great. Good start. Who has used it for more than one project? Just because I'm curious. Nice. Who has, when they've been working on a director's project, you've used an extension as part of that? Alright. Starting to shrink. Great. Who has written a custom extension? Okay. Great. Phew. Otherwise, I was worried that I was going to be like, hey, you guys tell me how to write an extension. All right. Before I start, a little bit about me. I'm David. I'm head of engineering at Pixilabs. We are a digital product development agency. That means that we design and develop digital products, everything from internal platforms for FTSE 100 companies to manage smart home device installations, helping funded startups launch their product, all the way down to we once made a typewriter type by itself when you tweeted at it. And that was part of a digital art installation for Twitter, which was really fun. Basically, if we can code it, we will do our best to do that. And, actually, most of the time we build, like, full stack web applications in Ruby on Rails. But sometimes, we need a headless CMS and sometimes, we often turn to directors. So that's what I wanna talk to you about, not the Ruby on Rails apps. Just because I thought it would be interesting, like, if I was here, I would wanna know what are people what are other people making with Directus. Right? So I thought I'd show you a couple of things that we've made at Pixielabs. The first one, is a company called Blackwing 7. They make bespoke cinematography lenses for film, TV, music videos, things like that. This is kinda what you maybe a site that you would traditionally expect for a headless CMS. Right? So, we actually took this over from another agency. It was all completely static, and the client wanted to be able to edit little bits of it, make some of it interactive, and things like that. And so that was something that we kind of turned to Directus to build. Something maybe a bit more unusual, thinking about that kind of, like, not just a headless CMS kind of vibe. This was a for good project called Red Flags. You can kind of think of it as like hazard perception but for consent. If any of you have taken your driving test and you've done the hazard perception, you know, you're watching a video of someone driving, usually through Wales, and you click a button every time there's a sheep on the road. Basically, that, but, but, yeah, for for consent. So there's, like, a video that you watch of someone going on a first date and you click a button every time you see, a, you know, an issue to do with consent. This was a campaign around that. And at the end, you get a score of how many you spotted or how many you missed, and you get to submit some details about you to sort of help their campaign, help understand who is engaging with this. And that's particularly interesting because that was where we were kind of using that ability. You know, Directus is ultimately just a wrapper around a database. Right? And so we could use that to store those results that were being submitted alongside the content that was part of the website as well. So really acting as more like a basic kind of app data store there than just a headless CMS. You kind of maybe something you might use Firebase for as well maybe is kind of like a sort of point of comparison. Kind of interesting. I'm gonna talk about a different project, for a client called Depuri that we worked on. I'm gonna tell you a little bit about that project, why we picked Directus, the extension that we had to build. That's the meat of it. And some tips as well for building your own extension if you, you know, are sort of wondering about how you'd go about doing that. Hopefully, by the end, you're gonna know some pitfalls to avoid if you do go about building an extension, how to get started as well, and, also, you're gonna hopefully know the best, in my opinion, way to, progressively load images on a website if you wanna do it in, like, a really, kind of optimum way because that's the extension that we built. So the project was, to build this kind of beautiful online art gallery, for a new brand, of online art curation and auctions called De Pury. We did a whole kind of tech stack evaluation and architecture process for this, and we recognized a couple of things. We knew that we wanted a bespoke front end so that we could wield all of our front end power, and we wanted a layer there that could, you know, we could kind of do whatever we wanted to do. So, we knew that the designs were gonna be you know, they wanted it to feel luxurious and feel sophisticated and expensive, and so we knew that we needed to be able to kind of tweak it a lot. And we recognized early on we needed a CMS because we did not want to have to edit all the content by hand. We wanted the client to do that. So we recognized pretty quickly that we needed a headless CMS. So Directus ended up being a good fit for a few reasons, actually. First of all, the image handling in Directus, if you've not explored that a bit, is really cool. We knew we were gonna need to be able to do resizing for different devices. We potentially thought we might have to do sort of interesting transformations of images. Maybe we wanted to make them grayscale or blur them or anything like that as part of the designs. And, Directus exposes the whole of the Sharp API. I don't know if anyone's a JavaScript dev. You might be familiar with Sharp. It's like ImageMagick or something like that. It's a really great package for manipulating images. Directus just gives you that whole thing. You can just drive it via the API which is super cool. You can also configure it to cache forever and have no expiry on caching. Right? Which was useful for us. We didn't want images randomly loading slow because Contentful had decided to delete some of our images from their cache or something like that. We really like the API. A lot of headless CMSs at GraphQL. I'm not really a huge fan of GraphQL. Really like that there's a REST API with Directus. It's just quicker and easier to get up and running for a small project. Right? It's easy to deploy. Tapuri had some existing infrastructure on Amazon Web Services, and so it's just a Node. Js app. You can deploy it somewhere. It'll align nicely with that. And lastly, we knew that we could extend it. Right? We felt comfort as we went into this project that we were like, well, if if there's something that directors can't do, we can at least write some JavaScript to make it do what we needed. It turns out, we did need it. So direct us wasn't quite enough. Once we got going, and we were iterating, we identified a problem with the way that the images were loading. The website was full of these large, high quality images. They wanted to sort of full bleed, you know, images of the artwork, that was being curated. And there were also just, like, galleries and it was just images. Right? Just thumbnails of images. And we wanted these to feel great, especially on mobile devices. The default approach, usually, is to do something like, low quality image placeholders. Is anyone is anyone familiar with the concept of low quality image placeholders? If you're not, it's like where you basically request a really tiny image that's, like, 6 by 6 pixels, then you make it as big as you want it, and you add some kind of blur to it. Right? And then as the real image loads, you cross fade from one to the other. You get kind of a nice fade as the image loads rather than just, like, a gray box. The problem is that that still takes time. Right? The page loads. We've got, like, 50 images that we wanna load. Now we're asking someone's web browser to load 50 images. Still lots of requests and so we ended up in this situation, the client wasn't happy with it, where you've got a bunch of gray boxes that quickly change to these blurry versions of images and then they change again to the real image and it just didn't look great. Right? Fortunately, we had a solution in our back pocket that we'd used before which is called blur hash. Is anyone familiar with blur hash as a thing? Alright. Great. Mostly shaking of heads, which is good. So Blahash, is a solution to this. It was made by a company called WALT, which is like a European Deliveroo competitor, which I hadn't heard of, I guess because we have Deliveroo. And they built a thing to to solve this problem. I'll just show you it quickly. So it's kind of like a representation of a placeholder of an image. Right? So, imagine they had the same problem. Right? They had this nice app and they just had these gray boxes and they were annoyed about it. What you basically do is you feed your image into the blur hash algorithm and you get, like, a very short representation of a blurry version of that image. Really, really short, like 10 to 20 characters, which you can then pass back to the blur hash library and it will generate a kind of blurry, smooshed version of the image. And what's cool about this over low quality image placeholders is that there's no extra request. You can include this, so when you're getting the data for your page, you're getting the data about your images, you can have the blur hash ready to go alongside the, like, URL, width, and height. So there's no extra request. One request for everything and you've already got those placeholder images. Super useful for us. Alright. So we knew we wanted blur hash. Directus doesn't have blur hash support by default, so so we needed to build an extension. Specifically, we built a hook extension, and I'll talk a little bit about different types of extensions but that, basically, is, like, custom JavaScript code that you can write and it will run at certain points defined by directors. Right? So, if you've ever written WordPress plugins, maybe, where you've got hooks, that'll feel really familiar or any kind of event based programming in JavaScript, you know, where you're like on this event, do this code. Basically, that. So, in theory, we were like, well, this is pretty straightforward. We want to add a new field against all our images to store the blur hash. Then, when an image is created or modified using that hook, we want to use the blur hash library to calculate that string that you saw for the image and then save it into that new field. In reality, there were a few interesting gotchas which I'll tell you about, but in principle it was pretty straightforward. I'll just show you it quickly, what it looks like in reality. So this was the site. Ignore my dev tools on the side here because I've got network throttling on to try and show you what it looks like. Please find the right button eventually. Hopefully, I've refreshed and cleared cache. Yeah. So, you can see the effect where the blur hash is already there and then it crossfades to the image. As I scroll down, some of these are still even on a pretend 3 gs they're still loading in time. But, you can see the effect. There's no flicker from one to another. There's no gray, then color, then image. It's just straight in. Some of the of course, they're now loading. You know, there we go. There's 1. We can go and look at this in Directus as well. So if I come in here, this is the Directus instance for this site, this is for the home page. If I create a new block here, I'm gonna pretend like they're curating my own photos. So if I create this home page block, if I go back and look at that now and go and look and edit that image, we can see that the blur hash has been added. Right? So the extension's got that field in there. It's generated it on save, and it's put it against the image. So now if I go and have a look, hopefully Imagine if it doesn't work out. Live demos was the worst. I tried to keep this one really simple. Yeah. So you can see the blur hash loaded straightaway and then, on my simulated 3 gs, eventually, my image loads. Look at that. Oh, there was one other thing as well. We were talking about that nice REST API. So you can see here, right, this is the this is all the JSON for the homepage. Single request to get the home page and get all of the related fields. Yeah? Sorry, can you carry on the flow? I'll ask when you're done. Okay. Yeah. I've got space for questions at the end. Hold it hold it in your head if you can. Yeah. So you can see, you can see the blur hashes here being included in with the JSON. Right? So they're all ready to go. Just drop it on. Cool. Alright. The fun stuff. What did we learn? Quite a bit. First of all, there's a Director's extension SDK, which is super useful for getting started. It has a nice kind of, like, command line interface for getting set up. It generates a kind of, like, directory depending on It asks you what kind of extension you wanna make, puts it all together for you, and kinda gets you started. There are lots of types of extensions, and that can be confusing. These are all the different types. Also, they're all kinda subtly different, in the way that they're, like, put together. At least when we were doing ours, hooks are are JavaScript and they're compiled using a thing called roll up, which I'll talk about in a sec. But then app extensions are like ECMAScript modules, and they're loaded in a little bit differently and it's very confusing and it's moved around a little bit and, yeah, there's definitely some funkiness there to watch out for. When you build an extension, especially a hook extension, all of the internal API services are made available to you. They're, like, handed to your code. Like, Here you go. You can use all of this stuff. There's no documentation for what any of that stuff is, Not even in the source code, there's not really comments for it. So you do have to kind of poke around to try and find what you need. I can actually show you an example where we've got our extension source code here. It's a little bit small, I know. But like this here, we're, like, calling the this asset service is coming from Directus. Directus is giving it to us. Presumably, they want us to use it. But this get asset method, you've just gotta guess, what it's doing. Right? And it changes because it's an internal API and I did feel a little bit nervous putting it in here, I will admit. But, hey, it works. So look over the source code. They are there to use. There's also no agreed way to embed a database migration in an extension. So you can write a migration as part of your as part of a director's extension. But, like, if you wanna release an extension that does something to the database, there's no kind of agreed way of doing that. That made us a little bit nervous. I think there's a few different approaches. You can ask the user to put it in themselves. You can copy it in sneak. Ly, which is what we do, or you can just do it at run time, which feels a little bit scary. Rollup, which is a tool that, at least for hook extensions is being used to kinda compile the extension. So you write your extension code and then Rollup builds it. Not webpack or anything like that. It's Rollup. Kind of funky. It does some weird stuff if you want some dependencies. If you're including some dependencies for your extension, roll up's gonna do its best to try and push those all to your extension, and it can make a bit of a mess. And that kinda relates to this. Testing locally can be painful. There is some stuff to help. The Director's, extension SDK has, like, a link tool that you can use to link your extension code into, like, a local Director. So while you're devbing and you're playing around, you can try stuff out That can mess with nodes, like dependency resolution, which can cause you trouble. So watch out for that. But, all that said, reading other extension code is super useful and there's 2 really great ways of doing that. 1 is that there's this awesome Directus on GitHub. Everyone loves an awesome something on GitHub, which has got a list of extensions. Super useful to go through and look and see how are other people doing this, how are people solving this problem. And, also, you can just go on to npm and search keywords directors extension because that SDK adds that by default to your package JSON. So if anyone who does that and then publishes it, it gets added as a keyword, which makes it super easy to search. I think that was probably intentional so that they can find all the director's extensions, But useful as well if you're building your own. And hopefully, this doesn't I know there's a lot of negatives there, but it was kind of a, like, here's some stuff to watch out for. In general, it was actually pretty straightforward. The extension's only a 100 lines of code. There's not a lot to it. Right? And it was very easy to get started. And I think, like, there's lots of opportunities to build stuff here. Right? Like, this is a community, it's open source, which actually Kevin is gonna talk about. And it's hard to sell open source to clients, but it does sell well to us and to the team. Like, we believe quite strongly in open source as well. So being able to, like, do this and give back, is great. Yeah. Hopefully hopefully, that was useful and interesting. Thanks for listening, if it wasn't.",[184],"6608dfaa-4ae5-4923-a28e-59b5a35f8aee",[],{"reps":187},[188,244],{"name":189,"sdr":8,"link":190,"countries":191,"states":193},"John Daniels","https://meet.directus.io/meetings/john2144/john-contact-form-meeting",[192],"United States",[194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243],"Michigan","Indiana","Ohio","West Virginia","Kentucky","Virginia","Tennessee","North Carolina","South Carolina","Georgia","Florida","Alabama","Mississippi","New York","MI","IN","OH","WV","KY","VA","TN","NC","SC","GA","FL","AL","MS","NY","Connecticut","CT","Delaware","DE","Maine","ME","Maryland","MD","Massachusetts","MA","New Hampshire","NH","New Jersey","NJ","Pennsylvania","PA","Rhode Island","RI","Vermont","VT","Washington DC","DC",{"name":245,"link":246,"countries":247},"Michelle Riber","https://meetings.hubspot.com/mriber",[248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320,321,322,323,324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352,353,354,355,356,357,358,359,360,361,362,363,364,365,366,367,368,369,370,371,372,373,374,375,376,377,378,379,380,381,382,383,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,225,436,437],"Albania","ALB","Algeria","DZA","Andorra","AND","Angola","AGO","Austria","AUT","Belgium","BEL","Benin","BEN","Bosnia and Herzegovina","BIH","Botswana","BWA","Bulgaria","BGR","Burkina Faso","BFA","Burundi","BDI","Cameroon","CMR","Cape Verde","CPV","Central African Republic","CAF","Chad","TCD","Comoros","COM","Côte d'Ivoire","CIV","Croatia","HRV","Czech Republic","CZE","Democratic Republic of Congo","COD","Denmark","DNK","Djibouti","DJI","Egypt","EGY","Equatorial Guinea","GNQ","Eritrea","ERI","Estonia","EST","Eswatini","SWZ","Ethiopia","ETH","Finland","FIN","France","FRA","Gabon","GAB","Gambia","GMB","Ghana","GHA","Greece","GRC","Guinea","GIN","Guinea-Bissau","GNB","Hungary","HUN","Iceland","ISL","Ireland","IRL","Italy","ITA","Kenya","KEN","Latvia","LVA","Lesotho","LSO","Liberia","LBR","Libya","LBY","Liechtenstein","LIE","Lithuania","LTU","Luxembourg","LUX","Madagascar","MDG","Malawi","MWI","Mali","MLI","Malta","MLT","Mauritania","MRT","Mauritius","MUS","Moldova","MDA","Monaco","MCO","Montenegro","MNE","Morocco","MAR","Mozambique","MOZ","Namibia","NAM","Niger","NER","Nigeria","NGA","North Macedonia","MKD","Norway","NOR","Poland","POL","Portugal","PRT","Republic of Congo","COG","Romania","ROU","Rwanda","RWA","San Marino","SMR","São Tomé and Príncipe","STP","Senegal","SEN","Serbia","SRB","Seychelles","SYC","Sierra Leone","SLE","Slovakia","SVK","Slovenia","SVN","Somalia","SOM","South Africa","ZAF","South Sudan","SSD","Spain","ESP","Sudan","SDN","Sweden","SWE","Tanzania","TZA","Togo","TGO","Tunisia","TUN","Uganda","UGA","United Kingdom","GBR","Vatican City","VAT","Zambia","ZMB","Zimbabwe","ZWE","UK","Germany","Netherlands","Switzerland","CH","NL",1773850428296]