[{"data":1,"prerenderedAt":428},["ShallowReactive",2],{"footer-primary":3,"footer-secondary":93,"footer-description":119,"around-the-world-diy-wedding":121,"around-the-world-diy-wedding-next":159,"sales-reps":176},{"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":149,"season":150,"seo":8},"380ee198-9850-4e7f-a849-e1f328b0b6c0","diy-wedding","910770710","Hold on to your bowties and bouquets as we dive head-first into the world of wedding planning. Except this isn't any wedding - it's a wedding between two nerds who know how to code. We'll discuss the hacky projects built to help us organize and deliver a magical day - from custom a custom invite RSVP system, email and text alerts, security-list generator, and some of the weirder ideas we ran out of time to build.  ","3bc39a09-5c4d-4b6f-8cb5-48447db3a84e",15,[129],{"name":130,"url":131},"Kevin Lewis","https://directus.io/team/kevin-lewis",5,"2024-02-07","DIYing My Wedding The Hacker's Way","\u003Cp>Speaker 0: Hello. My name is Kevin. I run developer relations at Directus. But the reason I say that more specifically is because my past life, as I mentioned to some of you earlier, was running an events agency. I've run over 300 hackathons, meetups, conferences, workshops, on behalf of clients.\u003C/p>\u003Cp>So we're actually gonna start this by talking about the basic recipe for every single event regardless of format. Firstly, you need a reason for people to meet. Here, it's because we are interested in some way, shape, or form about directors. You need a place and a time, and you actually need people to be in the space for the reason that you're gathering them. Everything else above that is actually extra.\u003C/p>\u003Cp>You know, the food, the drinks, it's extra. We don't need it. The stickers, we don't need it. We don't need anything else. As long as people, you know, know what to expect, that's all good.\u003C/p>\u003Cp>And remember, I have run events 100 of times over, which means organizing a wedding should be simple. Right? This is right in my wheelhouse. Basically, what I wake up to do in the morning. I'm gonna spoil it for you and tell you that, no, I was cocky and I thought it was easier than it was.\u003C/p>\u003Cp>But before we realized that, my wife and I were in too deep. We we were organizing our own wedding. But we did have one thing on our side, and that is the fact that we are huge nerds and we like to hack together little solutions to problems in our lives. So this talk is going to take us through some of those little projects that we built to try and make that day easier easier to to run. Yeah.\u003C/p>\u003Cp>Run. Let's use the word run. So firstly, we already had the reason to meet, obviously. We already sorted the venues and dates, so we just needed the people. And that starts, of course, with weddings, with sending out wedding invites.\u003C/p>\u003Cp>Now the first big difference we realized with a wedding is that unlike tech events, people expect invites to feel quite personal to them. But we also need to gather data consistently from them, which is often difficult if you're using physical media. And one other quirk with our setup is that we had the ceremony, you know, the I do and then we had the reception, the party bit afterwards. And the ceremony venue could only hold about a quarter of the people as our reception venue. So immediately, we effectively had a ticket type, 2 ticket types.\u003C/p>\u003Cp>We had one that brought people to the whole day and we had one just for people coming to the reception. This is actually very common. I I didn't realize upfront so I feel less bad about it in hindsight. But we have these 2 ticket types. Another variable is that not every guest was given a plus one.\u003C/p>\u003Cp>We did this to manage budgets, guest lists. You know, we wanted to know people who were coming, so that's that's important. This was a case by case. So not everyone got a plus one. So once again, there's another variable on a ticket type.\u003C/p>\u003Cp>And the final consideration of an event that is somewhat unique to other events that I've run is that one person will often act as the coordinator for a whole group. I will not send an invite to my mom and an invite to my dad. I'll send an invite to my parents, and realistically, one of them is gonna take take point on on, you know, accepting on behalf of the party, but organizing plans on behalf of the whole party. But we also needed to know out of that party who's coming and who isn't because it isn't a given that everyone's gonna come or everyone is not going to come. So it's all these interesting variables, that made this actually quite a complex delivery, let's call it.\u003C/p>\u003Cp>I'm very much talking like an event organizer here. Very complex delivery. So how do we make this happen? I work for Directus. So, of course, I use Directus, which I think means I got to plan my wedding at least partially on work time.\u003C/p>\u003Cp>So we set up we set up a table for individuals individuals, and that in that included the, the name, dietary, and access requirements for an individual, whether or not they were coming, and whether this person was a plus one. I'm really happy we added this filled up front because as as we got closer, I looked at the list and went, who the fuck is that a couple of times. Fortunately, they were marked as a plus one. And we'll talk about it in a moment. They were linked to an invite so I could work out who's plus one they were.\u003C/p>\u003Cp>Right? So that that was that was worthwhile. We also had a wellness certification, which we'll talk about a little bit later. Now each invite had a slug, which we used in the URL for the custom invites, some nice custom text so we can, you know, write a little message that's a little more personal to them, a link to 1 or more of those people, a pair of booleans to dictate whether this invite included an invite to the ceremony, whether or not they were given a plus one, and lead contact phone number and email address. We don't need that for every individual, just the person taking taking, you know, taking point for the for the group, and a date field on which that invite was used, which we effectively checked if it was null, if it wasn't used, and if it was used if it had a date value it had been used and we knew when.\u003C/p>\u003Cp>So I took, I did all of this in a spreadsheet, wrote a one off script to drag it all into direct us. Fantastic. Now, a set of invites, we have a set of people, or the other way around. Set of people and a set of invites. And the other part of this invite system was a web application.\u003C/p>\u003Cp>It was an express app. You used view on the front end, used the direct us SDK to render out invite pages and actually accept the responses. Here's an example of what a basic invite looked like. So this person, we still love them very much, of course, but they're only coming to the reception and they don't get a plus one. So this is this is what that looked like.\u003C/p>\u003Cp>So each person RSVPs yes or no. Anyone who says yes, we ask for their dietary and or access requirements. The group phone number, the group email address, you hit send. And we try to get everyone to respond to this even if the answer was just them going, no, nope, submit. And at least we know where we stand.\u003C/p>\u003Cp>This is an example of what I'll call a fully loaded invite. This person gets a plus one. They also get invited to both parts of the day. There's a bit more information up there. And you'll notice this box here, they say they want to they want to bring a plus one, you know, they they have to not everyone we gave that ability to did, and then they give us information about the plus one.\u003C/p>\u003Cp>First name, last name, dietary, and access. Once again, it's expected that one person will still take point for the whole group including the plus one. On submit, we update each person attached to that invite. We create a new person if they're a plus one and immediately link them with that invite. So that's really useful for, again, going, who the hell is this person?\u003C/p>\u003Cp>Oh, they're they're connected to Bob's invites, so they're they're Bob's plus 1. And also, updated the invite as used by adding in the dates. We could also keep track of when people when people are responding as well. And honestly, it worked great. You know?\u003C/p>\u003Cp>I know some traditionalists are like, you send paper invites to people. But these were instant. They were free. They were flexible. They were still personalized.\u003C/p>\u003Cp>They allowed for consistent data entry. Didn't kill loads of trees to make it happen. It was grand, actually. It worked fantastically. We ultimately ended up with a list of who could and couldn't make it, a list of invites that we used and not used, and a mark against all the plus ones as well as dietary and access requirements worked great.\u003C/p>\u003Cp>Part 1, check. We got our people. This is great. Now we are fools who DIY ed our wedding. We also completely serviced our own bars.\u003C/p>\u003Cp>So let's let's take a moment to talk about what that means when you are organizing drinks for an event, for a big event. This may be knowledge to you as potentially nonevent organizers. There is a service called a wet bar, and that basically is a whole service you hire in. These people basically, it's a service that a bar will offer. They will come with a ton of drinks, staff, glassware, fridges, all the, you know, the the little the the ice buckets and the little tongs for it and all the lemons and limes.\u003C/p>\u003Cp>They they charge you for all those drinks as if you were in a London bar, which is why shock horror of this is not what we did. And then they take away everything afterwards, including the things they didn't use. It's like bringing the bar to you, but you're paying full bar prices. We didn't do that. We did a dry bar, which means that we we did it all.\u003C/p>\u003Cp>We rented glassware. We rented ice buckets. We rented all the the the trays and all this shit. We rented more tables for tablecloths. We rented fridges.\u003C/p>\u003Cp>We bought a ton of drinks at wholesale. And then we just hired people who were bartenders and paid them a good hourly rate to come and and work for us, and we had handled the rest of it. You know, bought all the spirits and they obviously were significantly cheaper than if I was gonna buy that shot by shot from a bar. In fact, just as a just as a note, unit cost of every drink, soft or or alcoholic, just the average cost per drink I work out, if you include stuff like glassware higher, the cost of the person's time split over the number of units, I work out to be about £1.80, which is, like, wicked because you're talking, like, 5, 6, 7, 8 in a London bar otherwise. We saved a ton of money.\u003C/p>\u003Cp>We did a bunch of work. We saved a bunch of money. But, like, you know, just worth noting there. So we did that. Why what is this what is this gonna do with with stupid hacky projects that maybe in hindsight I shouldn't have done?\u003C/p>\u003Cp>This no. No. No. Clearly clearly, this is an example because my wedding did not have a total monthly recurring revenue. This is an insights panel inside of directors.\u003C/p>\u003Cp>You will notice that on this dashboard, there are a set of panels. But you can create new, like, bespoke panels by building panel extensions. And that's what we did. Now in the interest of time, I'm just gonna show you that the outcome of this. We had a collection for drinks recipes, and then built a custom panel for that for the director's insights dashboard builder, which allowed us to set the ratios for each drink and get a shopping list for quantities based on our guest list.\u003C/p>\u003Cp>So the number on the right is the unit for that given drink based on data in a different collection. For example, Coke Zeros lemonades, they come in crates of 24, but the beers come in boxes of 12. So it's not always you need this many of a thing. Well, I just got it to tell me you need to order 9 units, 9 crepes of this, 9 crepes of this and so on. Just as a as a another note, this took a bit of research.\u003C/p>\u003Cp>At a wedding, you should expect a guest to have a drink every 45 minutes. There you go. That's a bit of knowledge you didn't have, which you now have. So that just helped us understand how many drinks, you know, how many drinks on average we had. This was super helpful.\u003C/p>\u003Cp>Was it overengineered? Yes. Would I do it again? No. Would I use a spreadsheet next time?\u003C/p>\u003Cp>Yes. But we're here. We did it. I get to talk about it. Next, the notification system.\u003C/p>\u003Cp>One guest told us that our wedding was the best communicated wedding they've ever been to, and they were absolutely right. Yes. It was. You may have noticed when people RSVP'd, we or we spoke about it, we collected the lead contacts' contact information. We collected their phone number.\u003C/p>\u003Cp>We collected their email address. The moment that was submitted, we ran an automation through directors flows in the Vonage number insights API to standardize the number format because no one can ever put in a number the correct way. Even if you're like, they just no one knows how to write phone numbers. Honestly, it makes me so angry. So we used a whole a whole goddamn API to standardize this.\u003C/p>\u003Cp>Then we built a second flow for sending messages to our guests. It used, do I have a picture of it? No. Fine. It used this thing called the confirmation prompt dialogue.\u003C/p>\u003Cp>So, you know, you go to send message, it pops up a box so you can insert some extra information and you hit go. It runs this automation. And in there, it allowed us to filter by ticket type because, you know, some you wanna send a different message to your ceremony and reception guest versus your reception guests. It allowed you to, pick whether you want this to be SMS or email. In the end, everything went both ways, but whatever, there was Vonage SMS API and the resend email API to then send out those emails to guests.\u003C/p>\u003Cp>Another approach would have just been to push people to external platforms, you know, external lists as soon as they've RSVP'd. So, you know, you RSVP and this flow could just go here, get thrown into an email system list, you know, a Mailchimp list, and then just use their tools in order to send messages and not have to integrate with APIs directly. But by doing this at the source of the data, as soon as people got in touch as they often do, getting closer to the day and saying, I can't make it anymore, Or you go, I forgot to invite someone and, you know, and they well, actually, it's more important the other way where they where they opt out. You don't have to manage that second list and keep them in sync. Every time you run the flow to send a message, it's always using the dataset as it stands right now.\u003C/p>\u003Cp>Super useful, actually. I was I was into this. I would I would do this again. We made a choice early on that every guest would be able to do a COVID test and just generally say they were feeling good the day our wedding. We had some vulnerable guests.\u003C/p>\u003Cp>You know, we're responsible for bringing people together. It it it really mattered. So using that same Express and View application as our invite system, we added a button on each invite that the day before was shown that was like, submit your wellness certification. And then they they did that. They, you know, they filled it and said they're feeling okay on behalf of the party and they they hit go.\u003C/p>\u003Cp>But what this did was it generated a security list with a little mark next to everyone's name, denoting whether they had done this wellness certification or not. Those people who did, fantastic, welcome in. Those who didn't, and there were a tiny handful who just didn't see the message or didn't do it, whatever. We had a set of COVID tests on the door, and our security guard London wedding security guard. Our security guard, you know, got them a drink and went, basically, peace out, do the test, see in 15 minutes.\u003C/p>\u003Cp>Just, you know, we have this nice outside area. That's that's where you live for 15 minutes. Right? But the security list was live generated as people were filling it in. We were able to generate that, as a page, so that was super useful as well.\u003C/p>\u003Cp>And there was so much more we could have done. We had every person in a database. Everyone had a unique invite link. We could have checked people in digitally, though I think it really would have felt like a tech conference then and not a wedding. So I'm glad we didn't do that.\u003C/p>\u003Cp>We thought about building experiences where people would, like, validate themselves with, like, installations and, like like, play around. We just didn't have time to do that. We could have had people share their photos directly and use, like, direct us files to, like, you know, consume that and store that in a central location. But while we didn't have time to do all of that, at least I can now add wedding planning to my skill list, and, no, I won't help you with yours. So that's it, really.\u003C/p>\u003Cp>That's a bit of fun. Hope you found it interesting. And next time next time? Not next time. Next time, I would hire a wedding planner.\u003C/p>","Hello. My name is Kevin. I run developer relations at Directus. But the reason I say that more specifically is because my past life, as I mentioned to some of you earlier, was running an events agency. I've run over 300 hackathons, meetups, conferences, workshops, on behalf of clients. So we're actually gonna start this by talking about the basic recipe for every single event regardless of format. Firstly, you need a reason for people to meet. Here, it's because we are interested in some way, shape, or form about directors. You need a place and a time, and you actually need people to be in the space for the reason that you're gathering them. Everything else above that is actually extra. You know, the food, the drinks, it's extra. We don't need it. The stickers, we don't need it. We don't need anything else. As long as people, you know, know what to expect, that's all good. And remember, I have run events 100 of times over, which means organizing a wedding should be simple. Right? This is right in my wheelhouse. Basically, what I wake up to do in the morning. I'm gonna spoil it for you and tell you that, no, I was cocky and I thought it was easier than it was. But before we realized that, my wife and I were in too deep. We we were organizing our own wedding. But we did have one thing on our side, and that is the fact that we are huge nerds and we like to hack together little solutions to problems in our lives. So this talk is going to take us through some of those little projects that we built to try and make that day easier easier to to run. Yeah. Run. Let's use the word run. So firstly, we already had the reason to meet, obviously. We already sorted the venues and dates, so we just needed the people. And that starts, of course, with weddings, with sending out wedding invites. Now the first big difference we realized with a wedding is that unlike tech events, people expect invites to feel quite personal to them. But we also need to gather data consistently from them, which is often difficult if you're using physical media. And one other quirk with our setup is that we had the ceremony, you know, the I do and then we had the reception, the party bit afterwards. And the ceremony venue could only hold about a quarter of the people as our reception venue. So immediately, we effectively had a ticket type, 2 ticket types. We had one that brought people to the whole day and we had one just for people coming to the reception. This is actually very common. I I didn't realize upfront so I feel less bad about it in hindsight. But we have these 2 ticket types. Another variable is that not every guest was given a plus one. We did this to manage budgets, guest lists. You know, we wanted to know people who were coming, so that's that's important. This was a case by case. So not everyone got a plus one. So once again, there's another variable on a ticket type. And the final consideration of an event that is somewhat unique to other events that I've run is that one person will often act as the coordinator for a whole group. I will not send an invite to my mom and an invite to my dad. I'll send an invite to my parents, and realistically, one of them is gonna take take point on on, you know, accepting on behalf of the party, but organizing plans on behalf of the whole party. But we also needed to know out of that party who's coming and who isn't because it isn't a given that everyone's gonna come or everyone is not going to come. So it's all these interesting variables, that made this actually quite a complex delivery, let's call it. I'm very much talking like an event organizer here. Very complex delivery. So how do we make this happen? I work for Directus. So, of course, I use Directus, which I think means I got to plan my wedding at least partially on work time. So we set up we set up a table for individuals individuals, and that in that included the, the name, dietary, and access requirements for an individual, whether or not they were coming, and whether this person was a plus one. I'm really happy we added this filled up front because as as we got closer, I looked at the list and went, who the fuck is that a couple of times. Fortunately, they were marked as a plus one. And we'll talk about it in a moment. They were linked to an invite so I could work out who's plus one they were. Right? So that that was that was worthwhile. We also had a wellness certification, which we'll talk about a little bit later. Now each invite had a slug, which we used in the URL for the custom invites, some nice custom text so we can, you know, write a little message that's a little more personal to them, a link to 1 or more of those people, a pair of booleans to dictate whether this invite included an invite to the ceremony, whether or not they were given a plus one, and lead contact phone number and email address. We don't need that for every individual, just the person taking taking, you know, taking point for the for the group, and a date field on which that invite was used, which we effectively checked if it was null, if it wasn't used, and if it was used if it had a date value it had been used and we knew when. So I took, I did all of this in a spreadsheet, wrote a one off script to drag it all into direct us. Fantastic. Now, a set of invites, we have a set of people, or the other way around. Set of people and a set of invites. And the other part of this invite system was a web application. It was an express app. You used view on the front end, used the direct us SDK to render out invite pages and actually accept the responses. Here's an example of what a basic invite looked like. So this person, we still love them very much, of course, but they're only coming to the reception and they don't get a plus one. So this is this is what that looked like. So each person RSVPs yes or no. Anyone who says yes, we ask for their dietary and or access requirements. The group phone number, the group email address, you hit send. And we try to get everyone to respond to this even if the answer was just them going, no, nope, submit. And at least we know where we stand. This is an example of what I'll call a fully loaded invite. This person gets a plus one. They also get invited to both parts of the day. There's a bit more information up there. And you'll notice this box here, they say they want to they want to bring a plus one, you know, they they have to not everyone we gave that ability to did, and then they give us information about the plus one. First name, last name, dietary, and access. Once again, it's expected that one person will still take point for the whole group including the plus one. On submit, we update each person attached to that invite. We create a new person if they're a plus one and immediately link them with that invite. So that's really useful for, again, going, who the hell is this person? Oh, they're they're connected to Bob's invites, so they're they're Bob's plus 1. And also, updated the invite as used by adding in the dates. We could also keep track of when people when people are responding as well. And honestly, it worked great. You know? I know some traditionalists are like, you send paper invites to people. But these were instant. They were free. They were flexible. They were still personalized. They allowed for consistent data entry. Didn't kill loads of trees to make it happen. It was grand, actually. It worked fantastically. We ultimately ended up with a list of who could and couldn't make it, a list of invites that we used and not used, and a mark against all the plus ones as well as dietary and access requirements worked great. Part 1, check. We got our people. This is great. Now we are fools who DIY ed our wedding. We also completely serviced our own bars. So let's let's take a moment to talk about what that means when you are organizing drinks for an event, for a big event. This may be knowledge to you as potentially nonevent organizers. There is a service called a wet bar, and that basically is a whole service you hire in. These people basically, it's a service that a bar will offer. They will come with a ton of drinks, staff, glassware, fridges, all the, you know, the the little the the ice buckets and the little tongs for it and all the lemons and limes. They they charge you for all those drinks as if you were in a London bar, which is why shock horror of this is not what we did. And then they take away everything afterwards, including the things they didn't use. It's like bringing the bar to you, but you're paying full bar prices. We didn't do that. We did a dry bar, which means that we we did it all. We rented glassware. We rented ice buckets. We rented all the the the trays and all this shit. We rented more tables for tablecloths. We rented fridges. We bought a ton of drinks at wholesale. And then we just hired people who were bartenders and paid them a good hourly rate to come and and work for us, and we had handled the rest of it. You know, bought all the spirits and they obviously were significantly cheaper than if I was gonna buy that shot by shot from a bar. In fact, just as a just as a note, unit cost of every drink, soft or or alcoholic, just the average cost per drink I work out, if you include stuff like glassware higher, the cost of the person's time split over the number of units, I work out to be about £1.80, which is, like, wicked because you're talking, like, 5, 6, 7, 8 in a London bar otherwise. We saved a ton of money. We did a bunch of work. We saved a bunch of money. But, like, you know, just worth noting there. So we did that. Why what is this what is this gonna do with with stupid hacky projects that maybe in hindsight I shouldn't have done? This no. No. No. Clearly clearly, this is an example because my wedding did not have a total monthly recurring revenue. This is an insights panel inside of directors. You will notice that on this dashboard, there are a set of panels. But you can create new, like, bespoke panels by building panel extensions. And that's what we did. Now in the interest of time, I'm just gonna show you that the outcome of this. We had a collection for drinks recipes, and then built a custom panel for that for the director's insights dashboard builder, which allowed us to set the ratios for each drink and get a shopping list for quantities based on our guest list. So the number on the right is the unit for that given drink based on data in a different collection. For example, Coke Zeros lemonades, they come in crates of 24, but the beers come in boxes of 12. So it's not always you need this many of a thing. Well, I just got it to tell me you need to order 9 units, 9 crepes of this, 9 crepes of this and so on. Just as a as a another note, this took a bit of research. At a wedding, you should expect a guest to have a drink every 45 minutes. There you go. That's a bit of knowledge you didn't have, which you now have. So that just helped us understand how many drinks, you know, how many drinks on average we had. This was super helpful. Was it overengineered? Yes. Would I do it again? No. Would I use a spreadsheet next time? Yes. But we're here. We did it. I get to talk about it. Next, the notification system. One guest told us that our wedding was the best communicated wedding they've ever been to, and they were absolutely right. Yes. It was. You may have noticed when people RSVP'd, we or we spoke about it, we collected the lead contacts' contact information. We collected their phone number. We collected their email address. The moment that was submitted, we ran an automation through directors flows in the Vonage number insights API to standardize the number format because no one can ever put in a number the correct way. Even if you're like, they just no one knows how to write phone numbers. Honestly, it makes me so angry. So we used a whole a whole goddamn API to standardize this. Then we built a second flow for sending messages to our guests. It used, do I have a picture of it? No. Fine. It used this thing called the confirmation prompt dialogue. So, you know, you go to send message, it pops up a box so you can insert some extra information and you hit go. It runs this automation. And in there, it allowed us to filter by ticket type because, you know, some you wanna send a different message to your ceremony and reception guest versus your reception guests. It allowed you to, pick whether you want this to be SMS or email. In the end, everything went both ways, but whatever, there was Vonage SMS API and the resend email API to then send out those emails to guests. Another approach would have just been to push people to external platforms, you know, external lists as soon as they've RSVP'd. So, you know, you RSVP and this flow could just go here, get thrown into an email system list, you know, a Mailchimp list, and then just use their tools in order to send messages and not have to integrate with APIs directly. But by doing this at the source of the data, as soon as people got in touch as they often do, getting closer to the day and saying, I can't make it anymore, Or you go, I forgot to invite someone and, you know, and they well, actually, it's more important the other way where they where they opt out. You don't have to manage that second list and keep them in sync. Every time you run the flow to send a message, it's always using the dataset as it stands right now. Super useful, actually. I was I was into this. I would I would do this again. We made a choice early on that every guest would be able to do a COVID test and just generally say they were feeling good the day our wedding. We had some vulnerable guests. You know, we're responsible for bringing people together. It it it really mattered. So using that same Express and View application as our invite system, we added a button on each invite that the day before was shown that was like, submit your wellness certification. And then they they did that. They, you know, they filled it and said they're feeling okay on behalf of the party and they they hit go. But what this did was it generated a security list with a little mark next to everyone's name, denoting whether they had done this wellness certification or not. Those people who did, fantastic, welcome in. Those who didn't, and there were a tiny handful who just didn't see the message or didn't do it, whatever. We had a set of COVID tests on the door, and our security guard London wedding security guard. Our security guard, you know, got them a drink and went, basically, peace out, do the test, see in 15 minutes. Just, you know, we have this nice outside area. That's that's where you live for 15 minutes. Right? But the security list was live generated as people were filling it in. We were able to generate that, as a page, so that was super useful as well. And there was so much more we could have done. We had every person in a database. Everyone had a unique invite link. We could have checked people in digitally, though I think it really would have felt like a tech conference then and not a wedding. So I'm glad we didn't do that. We thought about building experiences where people would, like, validate themselves with, like, installations and, like like, play around. We just didn't have time to do that. We could have had people share their photos directly and use, like, direct us files to, like, you know, consume that and store that in a central location. But while we didn't have time to do all of that, at least I can now add wedding planning to my skill list, and, no, I won't help you with yours. So that's it, really. That's a bit of fun. Hope you found it interesting. And next time next time? Not next time. Next time, I would hire a wedding planner.","published",[139],{"people_id":140},{"id":141,"first_name":142,"last_name":143,"avatar":144,"bio":145,"links":146},"82b3f7e5-637b-4890-93b2-378b497d5dc6","Kevin","Lewis","a662f91b-1ee9-4277-8c9d-3ac1878e44ad","Director of Developer Experience at Directus",[147],{"url":131,"service":148},"website",[],{"id":151,"number":152,"year":153,"episodes":154,"show":156},"63ed15fc-e3f3-48cb-9d72-a437171d1001",2,"2024",[122,155],"08bdd8ab-2852-46ca-8914-6caa9c88aa3f",{"title":157,"tile":158},"Around the World","430ec649-8c29-4657-9425-2981fbae18c6",{"id":155,"slug":160,"season":151,"vimeo_id":161,"description":162,"tile":163,"length":164,"resources":8,"people":165,"episode_number":169,"published":133,"title":170,"video_transcript_html":171,"video_transcript_text":172,"content":8,"seo":8,"status":137,"episode_people":173,"recommendations":175},"wishbot","910771694","In this talk, we will discuss the development of WishBot: a trading card game based entirely in discord. we will talk about some of the intricacies of building bots at scale, and how Directus can be used to manage users, collections, and trading.","b19f813c-1894-4437-bd06-c49dbfdd5f18",30,[166],{"name":167,"url":168},"Nils Jeschke","https://www.linkedin.com/in/nils-jeschke/",6,"Building a Card Game Discord Bot With Directus","\u003Cp>Speaker 0: My name\u003C/p>\u003Cp>Speaker 1: is Milt. As you already know, I'm going to be talking about directors in combination with Discord bots and in this specific case, a Disney themed trading card game. Very simple. Stage 1, the concept where I got into the project. It was a project which I took over from someone else.\u003C/p>\u003Cp>It's a trading card game. It's Disney themed. It had to be a Discord bot because they just wanted it to be, very easy to market to a new user base and very easy to interact with. That's where the interaction base is coming in because in Discord that means not just sending a message but sending a interaction request command. So doing a slash saying I want something and giving some parameters to it and making it work and having it integrated with ranking sites.\u003C/p>\u003Cp>So it shows up on the ranking sites, you vote for them, you get something in Discord using the bot, and the more you vote the more you get. And we had some early problems which were caused by the project. First of all, being, mainly hosted on a different site. Let's just not call them how they actually are. Fast code, let's say.\u003C/p>\u003Cp>The problem was that the code was spread around multiple projects. They were all interconnected with each other. That caused problems because things were, defined multiple times in different ways, sometimes with differing definitions. So a is equal to b, but b also is equal to c. At the same time, a is 1 and b is 2.\u003C/p>\u003Cp>And we had high response times because multiple projects interacting with another on, for some reason multiple continents as well. And multiple data sources was we had multiple Google Sheets which were used as databases. I think we know where that one is going the moment we start getting into multiple 1,000 entries per Google Sheet. So stage 1, consolidation, getting everything into one application, getting all the projects combined into 1, which still used, the same platform for it in the beginning, getting all the data sources merged into 1 as well, which later on made it a little bit easier exporting all the data and getting rid of those data sources. And we used a MySQL database as an intermediary before we started switching over the infrastructure to something called Sapphire, which is, a framework for creating Discord bots.\u003C/p>\u003Cp>And here's where Directus comes in. We tried a lot of CMS systems and we wanted to have one thing. We wanted to have it quickly deployable. We wanted to have it highly adaptable. Easy to use, not only for administrators and developers, but for, creators, like creating new material inside the CMS, event based and cron based, automation, also known as flows, a REST and a GraphQL API, which was a requirement set by the owner of the project.\u003C/p>\u003Cp>I just rolled with it. We never used it since we then just use the director's SDK for everything that, happened. And for everything that we didn't use it, we use the internal API. And then it had to have the option to be either self or cloud hosted depending on the scope of the project later on. Funny enough, if you start with self hosted, I heard it's quite easy to get a self hosted directors instance into cloud hosted?\u003C/p>\u003Cp>Fairly easy?\u003C/p>\u003Cp>Speaker 0: Oh, I'm not sure you can let me for validation. Sure. That sounds correct.\u003C/p>\u003Cp>Speaker 1: It's easier than just, here, have a Google Sheet.\u003C/p>\u003Cp>Speaker 0: I mean, you said you are real low. Yeah. We we, leapfrog leapfrog that.\u003C/p>\u003Cp>Speaker 1: Yeah. And this code verification causes one big problem. It's you have to anonymize all the data. You have to follow GDPR, g yeah. GDPR.\u003C/p>\u003Cp>You have a lot of restrictions when it comes to collecting data from a user. So, generally, you're only allowed to know their ID, and that's all. No name. No information about what they did, what they wrote. There's exceptions to it, and that means you can handle those information when an event happens and you're not able to save it outside of that event.\u003C/p>\u003Cp>And infrastructure security, that's something that they recently added. They want you to essentially not allow anyone to access your bot on an administrative, capacity. Meaning, those servers that it's running on usually have to be secured by, for example, SSH with identity tokens instead of passwords. And funny enough, they actually checked it. So that's the quick rundown of the project and can actually look into it, how that, structure looks like.\u003C/p>\u003Cp>Here I actually see the user database. A lot of gibberish.\u003C/p>\u003Cp>Speaker 2: Could you switch the light theme?\u003C/p>\u003Cp>Speaker 1: We can switch light theme. Yeah.\u003C/p>\u003Cp>Speaker 2: It would be better for the projector.\u003C/p>\u003Cp>Speaker 1: Now this is an older instance. Now I have to see where it was in here.\u003C/p>\u003Cp>Speaker 0: Right there. Yeah.\u003C/p>\u003Cp>Speaker 1: Right there.\u003C/p>\u003Cp>Speaker 0: I believe so. If you scroll down. If it's an older you you should, just change your browser theme. It was it not user configurable? No.\u003C/p>\u003Cp>What was it? It's a 10 by 4. It's not write that theme.\u003C/p>\u003Cp>Speaker 1: There we go.\u003C/p>\u003Cp>Speaker 0: Yeah. That's better.\u003C/p>\u003Cp>Speaker 1: It's easier to be read.\u003C/p>\u003Cp>Speaker 2: And now the database needs some time to load again.\u003C/p>\u003Cp>Speaker 1: Apparently, I have a little bit of a bad connection with about 2 millisecond 2 seconds until database response. But, yeah, here we go. We have anonymized data. We know where user is, and we know who the user is, but only by ID, which is interesting because we have to handle things like a complete inventory in JSON. And all of those IDs in this case correspond to, where do we have it now?\u003C/p>\u003Cp>Why is it not showing what's above there? Can have There you go. Useful. They have already one part of the bot, and that's the ability to break everything. That's the ability to get yourself a random card dropped.\u003C/p>\u003Cp>In this case, the only thing that's actually random is the card being dropped. The value is always the same and it actually gains a little bit by liking it, having, yeah, people like, dislike, and delete their accounts. In this case, affecting the value because those are usually counted together. You have the ability to claim a card by clicking on a button. That then adds it directly into your inventory which is instantly reflected in direct us.\u003C/p>\u003Cp>And you can actually view your collection of items, which is a little bit problematic at the moment. You have a larger inventory because all the information gets invalidated after about 10 minutes of the session being started. So for 200 cards, you might need more than 2 minutes to scroll through all of them. I think Kevin might already encountered that problem. So that one is keeping a server specific record of your inventory.\u003C/p>\u003Cp>So you can have multiple inventories and multiple servers at some point. It was planned to have a global one but, Ono decided against it. And where directors starts to actually be more involved is by running the client command, and I hope the website still works because If we go where is it? It's like come here. You already claimed your reward.\u003C/p>\u003Cp>Hold on. No. It seems that you haven't voted yet. I hate it. That one will send you to a different website, which then makes you vote for a bot, which sends information to, directors.\u003C/p>\u003Cp>Funny enough in a format that is by default not understood by directors which means I had to include a custom hook which passes all the data and then sends it back to directors as JSON formatted.\u003C/p>\u003Cp>Speaker 0: So\u003C/p>\u003Cp>Speaker 2: log What are you voting for?\u003C/p>\u003Cp>Speaker 1: Especially not especially. Essentially, for the popularity of that specific application.\u003C/p>\u003Cp>Speaker 0: Oh, really? So that's like an external ranking of different Discord bots. And, obviously, bot creators want their bot to be not voted. So this is an incentive mechanism built into WishBot. But once every 12 hours, I think is how is how often you can vote here, you vote.\u003C/p>\u003Cp>I assume it sends, yeah, it sends like a webhook with this archaic data format to digest. That's handled, and then you can claim a reward inside of WishBot for doing that every 12 hours.\u003C/p>\u003Cp>Speaker 1: There you go. We have voted. And now that just to show that one, this data is actually present in here. And it has the time to live because, this k b storage is cleaning itself up. 300 3,600 seconds.\u003C/p>\u003Cp>It's exactly an hour that this data is, living inside it. So it should be enough time for anyone to run a simple command and get their reward, which in this case is totally random. You get what you get. The drops, those are static, but the value that you get is random based on nothing but a number generator.\u003C/p>\u003Cp>Speaker 0: And so this currency effectively in the game, the star\u003C/p>\u003Cp>Speaker 1: that's I\u003C/p>\u003Cp>Speaker 0: think it's called that star. You get that as a user, but that's also held on cards. So you have\u003C/p>\u003Cp>Speaker 1: a value gap. You have value which you can use to essentially get more cards. So it is a self perpetuating cycle. You get more cards, you sell more cards, and you end up at some point with the ones that you would like. Like for example, Mickey Mouse.\u003C/p>\u003Cp>Let's see. Yeah. I do have another currency and it's generating those cards currently based off list of 1,000 entries into database, which is including those images which are pulled off directors directly. So, yeah, that's about.\u003C/p>\u003Cp>Speaker 0: And there's a trading mechanism.\u003C/p>\u003Cp>Speaker 1: Yeah. That's a trading mechanism of for which I need a second user to actually initiate it.\u003C/p>\u003Cp>Speaker 0: Well, we we all know there's a trading Yeah.\u003C/p>\u003Cp>Speaker 1: Yeah. Any questions?\u003C/p>\u003Cp>Speaker 3: So this obscure data format that you're getting from the the voting side. How are you handling that with the customer input? Or is that being done right with the flow?\u003C/p>\u003Cp>Speaker 1: It's done with the flow, which is listening on all push requests that are coming in. And in that specific, case, I have to, I had to create a custom hook, which then allowed directors to pull any data which is not default JSON formatted and converted into the correct format. Let's see if I can act yeah. I can't pull it up here because that one doesn't have remote access to the machine that's running it.\u003C/p>\u003Cp>Speaker 0: So Directus is handling the the voting and claiming mechanism. It's obviously handling user registration effectively. Hello. It's also handling, a user's collection and\u003C/p>\u003Cp>Speaker 1: stuff\u003C/p>\u003Cp>Speaker 0: like that. There's the trading mechanism which it manages. Is Is there anything else that we are missing in there?\u003C/p>\u003Cp>Speaker 1: Actually, no. It's besides handling data. Directors is in this stage not having any additional part in it.\u003C/p>\u003Cp>Speaker 0: There's also subscribing, you know, the same monthly that's not directors, though.\u003C/p>\u003Cp>Speaker 1: To a degree, it actually is because directors has an internal record of everyone that ever subscribed. I just have to see if there's personal data on that one. So let me just Okay. If we don't scroll to the right, it's okay. So it's keeping a track of everyone that has subscribed within the last, 6 months and still has one active.\u003C/p>\u003Cp>So it's essentially, clearing up that list almost every day. In this case, it's getting from Ko Fi an information about everyone that subscribed. It's only getting their email address though. So in this case, directors has to keep a record of the email address, which in this court, a user can use their own email address. And since they know what they subscribe for, they can select what they subscribe for out of a list.\u003C/p>\u003Cp>I can actually show that one. For example not not activate the server sub. That shouldn't work because activate server sub was never activated. Jesus. Oh, yeah.\u003C/p>\u003Cp>Here. You have to put in your email. And in here, you have a list of tiers which are available. And the combination of both is actually used to verify you as a user because Ko Fi doesn't know who you are on Discord. Same with Discord, they don't know who you are on Kofi.\u003C/p>\u003Cp>Speaker 0: And you can only store from Discord, arbitrary user ID that means something outside of\u003C/p>\u003Cp>Speaker 1: Discord is actually by default not even giving you the user's email address, and that would not help much because you most likely or not most likely but maybe didn't use the same email address for 2 services. So that would break the whole system. So in this case, they have to provide the data themselves, then select the correct tier, which is interesting for anyone to crack in the beginning because they don't know your personal data and they don't know you even subscribe because Kofi is not making that information public.\u003C/p>\u003Cp>Speaker 0: That's an interesting workaround to I have a question.\u003C/p>\u003Cp>Speaker 1: Yeah.\u003C/p>\u003Cp>Speaker 0: I've built a Discord bot before. Terrible development experience. It's really, really rough. And it just lived as an express app.\u003C/p>\u003Cp>Speaker 1: Yeah.\u003C/p>\u003Cp>Speaker 0: Where's the bot running? Is it running as part of, like, the direct project or is it running elsewhere?\u003C/p>\u003Cp>Speaker 1: It's running externally, on the same virtual machine as Directus, but not within Directus, especially because it's using Sapphire, which requires a ESM module. And, as I think, directors as a project is not set up to handle ESM. Maybe. At least not the version that I'm using here. It would just instantly, crash the moment I build it.\u003C/p>\u003Cp>Speaker 0: Interesting. That's been one thing I I wondered about particularly is could you feasibly run a Discord bot entirely within\u003C/p>\u003Cp>Speaker 1: within directors and users? But\u003C/p>\u003Cp>Speaker 0: if you're not doing it here, we need we need, you know, talk about that possibility. So just curious.\u003C/p>\u003Cp>Speaker 1: You would just have to have a flow which is handling the incoming data because Discord is sending it to one endpoint, so, like, an interaction, webhook endpoint. And then you essentially just send a fetch request back to Discord, and it does what you want.\u003C/p>\u003Cp>Speaker 0: Yeah.\u003C/p>\u003Cp>Speaker 2: Would you like to show how you create new cars? Because I've seen your use of, like, input groups. Maybe some, people get a sense of how the Reactors looks on the back end. Yeah. Always interesting to see how others create content.\u003C/p>\u003Cp>Mhmm.\u003C/p>\u003Cp>Speaker 1: Oh, nice. Hi, camera. What is this? Ah, there we go. The cards.\u003C/p>\u003Cp>Speaker 0: So at the moment when you create cards, you do it. It is done here within the Data Studio?\u003C/p>\u003Cp>Speaker 1: It's done within the Data Studio. Yes. The ID, we set it actually as something manual because in the beginning, we imported a lot of data, and we actually modified some IDs because we had duplicates and it's kind of hard to import data and have duplicate IDs which are the primary key. So I kinda let the creator of those cars handle it themselves rather than me handling more than a 1000 entries. Mhmm.\u003C/p>\u003Cp>Name wish listed is something that is default to 20 and deactivated is, a feature that we use for essentially simulating misprints, like creating cards. Sometimes there's a mistake in the card, maybe in the image of it. It's getting marked as a misprint. But until it's getting marked as that, it's actually available. So\u003C/p>\u003Cp>Speaker 0: And it doesn't stop being available afterwards. It just stops\u003C/p>\u003Cp>Speaker 1: being distributed. It stops being distributed, which makes them kind of rare to get. Cards actually have a color in the sense of Discord messages, especially embed messages, always having a little bar on the left. We have a default color for that one. We never actually use anything else.\u003C/p>\u003Cp>The image is stored within directors manually setting a value, and we actually have a larger list of movies and series where you can select your character to be from. We use that way because we don't want to enter that data multiple times with thousands of entries and rather have that one once. And a little description of the character which is shown on the embed as well. Value? Value is, how much the card is worth in terms of the bot's own currency called stardust.\u003C/p>\u003Cp>Speaker 0: But you said it was randomized. Oh, no. It isn't. What's randomized? Are the claims Yes.\u003C/p>\u003Cp>Speaker 1: The value itself is fixed. Otherwise, you wouldn't be having, high value cards which stay the same value. Because you could have the same card with the same ID multiple times. But what differentiates the one card with ID 1 and the other card with ID 1? Actually, nothing really.\u003C/p>\u003Cp>Unless it has a difference, which means then it's not the same card anymore, which means a new ID is being created.\u003C/p>\u003Cp>Speaker 0: Is there any limitations, placed by Discord on response times to the slash command. And is there anything interesting you've had to do to do with the\u003C/p>\u003Cp>Speaker 1: 3 milliseconds? The initial response has to be done within 3 milliseconds.\u003C/p>\u003Cp>Speaker 0: 3?\u003C/p>\u003Cp>Speaker 1: Yes. Okay. 3 milliseconds initial response means you get a ping and you instantly send one back.\u003C/p>\u003Cp>Speaker 0: It's breaking. Yeah.\u003C/p>\u003Cp>Speaker 1: That's how much time they give you. That it's an ephemeral ready response.\u003C/p>\u003Cp>Speaker 0: Yeah.\u003C/p>\u003Cp>Speaker 1: It says 3 milliseconds in the docs even though it isn't.\u003C/p>\u003Cp>Speaker 0: Yeah. Do but do you have let's say, I'd say slash collection. Right? And you're generating a list of 200 cards with images, and you're grabbing those from directors. Is how long do you have to respond to that before it will time out?\u003C/p>\u003Cp>And then I suppose there's another interesting thing around, like, image, like, image sizes or optimizer. And you can't just say no. None of\u003C/p>\u003Cp>Speaker 1: that is\u003C/p>\u003Cp>Speaker 0: the case, but I have to believe there's some kind of limits there.\u003C/p>\u003Cp>Speaker 1: From back when the bot was created, the limitation of response time was 60 seconds to any command. It's pretty long. Yeah. At the same time, if you use image generating AI and you usually take more than 60 seconds, you would have to consume the command and then send a response later from an external event because otherwise, it would just start breaking everything. And what was the other question?\u003C/p>\u003Cp>Speaker 0: Image optimizations, whether there's anything\u003C/p>\u003Cp>Speaker 1: first of all, we, from the start, created images with a small size because that is a self hosted instance. It means every image that is shown in Discord is actively being requested from that instance. It's even though it's in a data center, has a lot of bandwidth, it still starts to overload directors as a self hosted instance in that VM if I get more than a couple thousand requests a second because it can't handle it anymore. And we kind of figured out that, funny enough that's another thing but Directus breaks regularly. No.\u003C/p>\u003Cp>Does it break now? I think it's going to break.\u003C/p>\u003Cp>Speaker 0: Yeah. And what's what broke there? Do you know why?\u003C/p>\u003Cp>Speaker 1: That's the one point. I can't tell you why because nothing shows up in the logs. It just stops loading. So it essentially times out trying to load that, not only that specific image, but all of them. Interesting.\u003C/p>\u003Cp>But\u003C/p>\u003Cp>Speaker 0: You you mean the video that I have the recording of and will take through an editing workflow before I\u003C/p>\u003Cp>Speaker 1: Oh, yeah. Definitely. That's cool. That's cool. Nah.\u003C/p>\u003Cp>Doesn't want to load it. It's actually not even loading the project image anymore. It shouldn't be.\u003C/p>\u003Cp>Speaker 0: Yeah. Anyway, cool. Are there any other interesting, like, technical notes about how this was come how this was put together, usage of directors, and of course, any questions for that maybe? I feel like we're we're at that point.\u003C/p>\u003Cp>Speaker 1: Right? You have no\u003C/p>\u003Cp>Speaker 0: more planned content. Right?\u003C/p>\u003Cp>Speaker 1: I have no more planned content indeed. Yeah. And there is actually nothing else in here anymore besides a little log of arrows and bugs that sometimes happen. But I think that the directors or that specific instance is at the point where it, doesn't want to cooperate anymore. Oh, actually, there are But most of them seem to be acknowledged.\u003C/p>\u003Cp>So it's actually keeping a track of every error that happens within the Discord bot because the Discord bot is writing a log, but it's a rotating log. So this way I can keep track of them and actually connect them to the user that triggered it. So I can get get back to them, can figure out what happens. What happened if I go in here? Let's see what it is.\u003C/p>\u003Cp>Ah, nice. That's the response from Discord, by the way.\u003C/p>\u003Cp>Speaker 0: Yeah. The message is there. Come on. Yeah.\u003C/p>\u003Cp>Speaker 1: And that's an interesting one. FaceTime. Interesting.\u003C/p>\u003Cp>Speaker 0: Really interesting projects. I think a really novel use of directus. And one that I I certainly didn't see before this project and haven't\u003C/p>\u003Cp>Speaker 3: database? I a database?\u003C/p>\u003Cp>Speaker 1: I selected directors instead of a database because the creators don't necessarily have the technical lodge, knowledge to put in data manually into the database, let alone then put files on a file server, connect them to the database, and have that everything retrieved. This is making it very easy for me to administer, administrate, for me to develop for it, and for anyone creating content to add to it. At the same time, I can see logs about things that happen outside of directors.\u003C/p>","My name is Milt. As you already know, I'm going to be talking about directors in combination with Discord bots and in this specific case, a Disney themed trading card game. Very simple. Stage 1, the concept where I got into the project. It was a project which I took over from someone else. It's a trading card game. It's Disney themed. It had to be a Discord bot because they just wanted it to be, very easy to market to a new user base and very easy to interact with. That's where the interaction base is coming in because in Discord that means not just sending a message but sending a interaction request command. So doing a slash saying I want something and giving some parameters to it and making it work and having it integrated with ranking sites. So it shows up on the ranking sites, you vote for them, you get something in Discord using the bot, and the more you vote the more you get. And we had some early problems which were caused by the project. First of all, being, mainly hosted on a different site. Let's just not call them how they actually are. Fast code, let's say. The problem was that the code was spread around multiple projects. They were all interconnected with each other. That caused problems because things were, defined multiple times in different ways, sometimes with differing definitions. So a is equal to b, but b also is equal to c. At the same time, a is 1 and b is 2. And we had high response times because multiple projects interacting with another on, for some reason multiple continents as well. And multiple data sources was we had multiple Google Sheets which were used as databases. I think we know where that one is going the moment we start getting into multiple 1,000 entries per Google Sheet. So stage 1, consolidation, getting everything into one application, getting all the projects combined into 1, which still used, the same platform for it in the beginning, getting all the data sources merged into 1 as well, which later on made it a little bit easier exporting all the data and getting rid of those data sources. And we used a MySQL database as an intermediary before we started switching over the infrastructure to something called Sapphire, which is, a framework for creating Discord bots. And here's where Directus comes in. We tried a lot of CMS systems and we wanted to have one thing. We wanted to have it quickly deployable. We wanted to have it highly adaptable. Easy to use, not only for administrators and developers, but for, creators, like creating new material inside the CMS, event based and cron based, automation, also known as flows, a REST and a GraphQL API, which was a requirement set by the owner of the project. I just rolled with it. We never used it since we then just use the director's SDK for everything that, happened. And for everything that we didn't use it, we use the internal API. And then it had to have the option to be either self or cloud hosted depending on the scope of the project later on. Funny enough, if you start with self hosted, I heard it's quite easy to get a self hosted directors instance into cloud hosted? Fairly easy? Oh, I'm not sure you can let me for validation. Sure. That sounds correct. It's easier than just, here, have a Google Sheet. I mean, you said you are real low. Yeah. We we, leapfrog leapfrog that. Yeah. And this code verification causes one big problem. It's you have to anonymize all the data. You have to follow GDPR, g yeah. GDPR. You have a lot of restrictions when it comes to collecting data from a user. So, generally, you're only allowed to know their ID, and that's all. No name. No information about what they did, what they wrote. There's exceptions to it, and that means you can handle those information when an event happens and you're not able to save it outside of that event. And infrastructure security, that's something that they recently added. They want you to essentially not allow anyone to access your bot on an administrative, capacity. Meaning, those servers that it's running on usually have to be secured by, for example, SSH with identity tokens instead of passwords. And funny enough, they actually checked it. So that's the quick rundown of the project and can actually look into it, how that, structure looks like. Here I actually see the user database. A lot of gibberish. Could you switch the light theme? We can switch light theme. Yeah. It would be better for the projector. Now this is an older instance. Now I have to see where it was in here. Right there. Yeah. Right there. I believe so. If you scroll down. If it's an older you you should, just change your browser theme. It was it not user configurable? No. What was it? It's a 10 by 4. It's not write that theme. There we go. Yeah. That's better. It's easier to be read. And now the database needs some time to load again. Apparently, I have a little bit of a bad connection with about 2 millisecond 2 seconds until database response. But, yeah, here we go. We have anonymized data. We know where user is, and we know who the user is, but only by ID, which is interesting because we have to handle things like a complete inventory in JSON. And all of those IDs in this case correspond to, where do we have it now? Why is it not showing what's above there? Can have There you go. Useful. They have already one part of the bot, and that's the ability to break everything. That's the ability to get yourself a random card dropped. In this case, the only thing that's actually random is the card being dropped. The value is always the same and it actually gains a little bit by liking it, having, yeah, people like, dislike, and delete their accounts. In this case, affecting the value because those are usually counted together. You have the ability to claim a card by clicking on a button. That then adds it directly into your inventory which is instantly reflected in direct us. And you can actually view your collection of items, which is a little bit problematic at the moment. You have a larger inventory because all the information gets invalidated after about 10 minutes of the session being started. So for 200 cards, you might need more than 2 minutes to scroll through all of them. I think Kevin might already encountered that problem. So that one is keeping a server specific record of your inventory. So you can have multiple inventories and multiple servers at some point. It was planned to have a global one but, Ono decided against it. And where directors starts to actually be more involved is by running the client command, and I hope the website still works because If we go where is it? It's like come here. You already claimed your reward. Hold on. No. It seems that you haven't voted yet. I hate it. That one will send you to a different website, which then makes you vote for a bot, which sends information to, directors. Funny enough in a format that is by default not understood by directors which means I had to include a custom hook which passes all the data and then sends it back to directors as JSON formatted. So log What are you voting for? Especially not especially. Essentially, for the popularity of that specific application. Oh, really? So that's like an external ranking of different Discord bots. And, obviously, bot creators want their bot to be not voted. So this is an incentive mechanism built into WishBot. But once every 12 hours, I think is how is how often you can vote here, you vote. I assume it sends, yeah, it sends like a webhook with this archaic data format to digest. That's handled, and then you can claim a reward inside of WishBot for doing that every 12 hours. There you go. We have voted. And now that just to show that one, this data is actually present in here. And it has the time to live because, this k b storage is cleaning itself up. 300 3,600 seconds. It's exactly an hour that this data is, living inside it. So it should be enough time for anyone to run a simple command and get their reward, which in this case is totally random. You get what you get. The drops, those are static, but the value that you get is random based on nothing but a number generator. And so this currency effectively in the game, the star that's I think it's called that star. You get that as a user, but that's also held on cards. So you have a value gap. You have value which you can use to essentially get more cards. So it is a self perpetuating cycle. You get more cards, you sell more cards, and you end up at some point with the ones that you would like. Like for example, Mickey Mouse. Let's see. Yeah. I do have another currency and it's generating those cards currently based off list of 1,000 entries into database, which is including those images which are pulled off directors directly. So, yeah, that's about. And there's a trading mechanism. Yeah. That's a trading mechanism of for which I need a second user to actually initiate it. Well, we we all know there's a trading Yeah. Yeah. Any questions? So this obscure data format that you're getting from the the voting side. How are you handling that with the customer input? Or is that being done right with the flow? It's done with the flow, which is listening on all push requests that are coming in. And in that specific, case, I have to, I had to create a custom hook, which then allowed directors to pull any data which is not default JSON formatted and converted into the correct format. Let's see if I can act yeah. I can't pull it up here because that one doesn't have remote access to the machine that's running it. So Directus is handling the the voting and claiming mechanism. It's obviously handling user registration effectively. Hello. It's also handling, a user's collection and stuff like that. There's the trading mechanism which it manages. Is Is there anything else that we are missing in there? Actually, no. It's besides handling data. Directors is in this stage not having any additional part in it. There's also subscribing, you know, the same monthly that's not directors, though. To a degree, it actually is because directors has an internal record of everyone that ever subscribed. I just have to see if there's personal data on that one. So let me just Okay. If we don't scroll to the right, it's okay. So it's keeping a track of everyone that has subscribed within the last, 6 months and still has one active. So it's essentially, clearing up that list almost every day. In this case, it's getting from Ko Fi an information about everyone that subscribed. It's only getting their email address though. So in this case, directors has to keep a record of the email address, which in this court, a user can use their own email address. And since they know what they subscribe for, they can select what they subscribe for out of a list. I can actually show that one. For example not not activate the server sub. That shouldn't work because activate server sub was never activated. Jesus. Oh, yeah. Here. You have to put in your email. And in here, you have a list of tiers which are available. And the combination of both is actually used to verify you as a user because Ko Fi doesn't know who you are on Discord. Same with Discord, they don't know who you are on Kofi. And you can only store from Discord, arbitrary user ID that means something outside of Discord is actually by default not even giving you the user's email address, and that would not help much because you most likely or not most likely but maybe didn't use the same email address for 2 services. So that would break the whole system. So in this case, they have to provide the data themselves, then select the correct tier, which is interesting for anyone to crack in the beginning because they don't know your personal data and they don't know you even subscribe because Kofi is not making that information public. That's an interesting workaround to I have a question. Yeah. I've built a Discord bot before. Terrible development experience. It's really, really rough. And it just lived as an express app. Yeah. Where's the bot running? Is it running as part of, like, the direct project or is it running elsewhere? It's running externally, on the same virtual machine as Directus, but not within Directus, especially because it's using Sapphire, which requires a ESM module. And, as I think, directors as a project is not set up to handle ESM. Maybe. At least not the version that I'm using here. It would just instantly, crash the moment I build it. Interesting. That's been one thing I I wondered about particularly is could you feasibly run a Discord bot entirely within within directors and users? But if you're not doing it here, we need we need, you know, talk about that possibility. So just curious. You would just have to have a flow which is handling the incoming data because Discord is sending it to one endpoint, so, like, an interaction, webhook endpoint. And then you essentially just send a fetch request back to Discord, and it does what you want. Yeah. Would you like to show how you create new cars? Because I've seen your use of, like, input groups. Maybe some, people get a sense of how the Reactors looks on the back end. Yeah. Always interesting to see how others create content. Mhmm. Oh, nice. Hi, camera. What is this? Ah, there we go. The cards. So at the moment when you create cards, you do it. It is done here within the Data Studio? It's done within the Data Studio. Yes. The ID, we set it actually as something manual because in the beginning, we imported a lot of data, and we actually modified some IDs because we had duplicates and it's kind of hard to import data and have duplicate IDs which are the primary key. So I kinda let the creator of those cars handle it themselves rather than me handling more than a 1000 entries. Mhmm. Name wish listed is something that is default to 20 and deactivated is, a feature that we use for essentially simulating misprints, like creating cards. Sometimes there's a mistake in the card, maybe in the image of it. It's getting marked as a misprint. But until it's getting marked as that, it's actually available. So And it doesn't stop being available afterwards. It just stops being distributed. It stops being distributed, which makes them kind of rare to get. Cards actually have a color in the sense of Discord messages, especially embed messages, always having a little bar on the left. We have a default color for that one. We never actually use anything else. The image is stored within directors manually setting a value, and we actually have a larger list of movies and series where you can select your character to be from. We use that way because we don't want to enter that data multiple times with thousands of entries and rather have that one once. And a little description of the character which is shown on the embed as well. Value? Value is, how much the card is worth in terms of the bot's own currency called stardust. But you said it was randomized. Oh, no. It isn't. What's randomized? Are the claims Yes. The value itself is fixed. Otherwise, you wouldn't be having, high value cards which stay the same value. Because you could have the same card with the same ID multiple times. But what differentiates the one card with ID 1 and the other card with ID 1? Actually, nothing really. Unless it has a difference, which means then it's not the same card anymore, which means a new ID is being created. Is there any limitations, placed by Discord on response times to the slash command. And is there anything interesting you've had to do to do with the 3 milliseconds? The initial response has to be done within 3 milliseconds. 3? Yes. Okay. 3 milliseconds initial response means you get a ping and you instantly send one back. It's breaking. Yeah. That's how much time they give you. That it's an ephemeral ready response. Yeah. It says 3 milliseconds in the docs even though it isn't. Yeah. Do but do you have let's say, I'd say slash collection. Right? And you're generating a list of 200 cards with images, and you're grabbing those from directors. Is how long do you have to respond to that before it will time out? And then I suppose there's another interesting thing around, like, image, like, image sizes or optimizer. And you can't just say no. None of that is the case, but I have to believe there's some kind of limits there. From back when the bot was created, the limitation of response time was 60 seconds to any command. It's pretty long. Yeah. At the same time, if you use image generating AI and you usually take more than 60 seconds, you would have to consume the command and then send a response later from an external event because otherwise, it would just start breaking everything. And what was the other question? Image optimizations, whether there's anything first of all, we, from the start, created images with a small size because that is a self hosted instance. It means every image that is shown in Discord is actively being requested from that instance. It's even though it's in a data center, has a lot of bandwidth, it still starts to overload directors as a self hosted instance in that VM if I get more than a couple thousand requests a second because it can't handle it anymore. And we kind of figured out that, funny enough that's another thing but Directus breaks regularly. No. Does it break now? I think it's going to break. Yeah. And what's what broke there? Do you know why? That's the one point. I can't tell you why because nothing shows up in the logs. It just stops loading. So it essentially times out trying to load that, not only that specific image, but all of them. Interesting. But You you mean the video that I have the recording of and will take through an editing workflow before I Oh, yeah. Definitely. That's cool. That's cool. Nah. Doesn't want to load it. It's actually not even loading the project image anymore. It shouldn't be. Yeah. Anyway, cool. Are there any other interesting, like, technical notes about how this was come how this was put together, usage of directors, and of course, any questions for that maybe? I feel like we're we're at that point. Right? You have no more planned content. Right? I have no more planned content indeed. Yeah. And there is actually nothing else in here anymore besides a little log of arrows and bugs that sometimes happen. But I think that the directors or that specific instance is at the point where it, doesn't want to cooperate anymore. Oh, actually, there are But most of them seem to be acknowledged. So it's actually keeping a track of every error that happens within the Discord bot because the Discord bot is writing a log, but it's a rotating log. So this way I can keep track of them and actually connect them to the user that triggered it. So I can get get back to them, can figure out what happens. What happened if I go in here? Let's see what it is. Ah, nice. That's the response from Discord, by the way. Yeah. The message is there. Come on. Yeah. And that's an interesting one. FaceTime. Interesting. Really interesting projects. I think a really novel use of directus. And one that I I certainly didn't see before this project and haven't database? I a database? I selected directors instead of a database because the creators don't necessarily have the technical lodge, knowledge to put in data manually into the database, let alone then put files on a file server, connect them to the database, and have that everything retrieved. This is making it very easy for me to administer, administrate, for me to develop for it, and for anyone creating content to add to it. At the same time, I can see logs about things that happen outside of directors.",[174],"34312cb6-c468-4edf-968b-b674542d1bbd",[],{"reps":177},[178,234],{"name":179,"sdr":8,"link":180,"countries":181,"states":183},"John Daniels","https://meet.directus.io/meetings/john2144/john-contact-form-meeting",[182],"United States",[184,185,186,187,188,189,190,191,192,193,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],"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":235,"link":236,"countries":237},"Michelle Riber","https://meetings.hubspot.com/mriber",[238,239,240,241,242,243,244,245,246,247,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,215,426,427],"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",1773850443738]