 Yeah, so, evening everyone, my name is Chung. I'm currently a front-end engineer in Xilin where I do client-side web application with Angular and TypeScript. And today I talked a bit about my recently published repository on GitHub that were lucky got a bit of attention from the community. And like in the title set, it has 900 stars. So I can make it to 1,000 stars. After this talk, I would love to see it. If I can see some of my stuff, I share it on Twitter, like follow this. Actually, I can first share the slide with you guys, so maybe you can revisit it later. So I just don't know how to check. That is the sliding. I save it with everybody. So let's continue. So the agenda today is, what is the repository that I published? So the name is Angular Jira clone. So it is the clone of Jira written in Angular. And what is the motivation behind that? I'll share a bit about my architecture when I start to build the app. And some of the decisions why I'm building the app. And mostly, it's focusing on the CLS, the Teru CLS, a bit of search management with NGX or Akita, and the way I deploy it to Nellify and Heroku. After that, we have some short Q&A session. And just give me any question that you might have during the slide, the presentation. So let's start. So what is the Angular Jira clone? So that's a URL. You can click and you can see it at jira.chunke18.com. And what it is, it's just basically a simplified Jira clone and we'll build it with Angular 9 at the time that I wrote the code. And I will try to make it like an example of modern and real world Angular code, because I thought there's a lot of examples out there, but it's pretty simple when the guy was building with Angular. So I also can share the link with you guys. That is how it looks like on the link itself. So you can basically do some kind of simple stuff, like drag and drop ticket, and you can open it. You do a bit of assign the ticket kind of stuff. You can also view all of the detail by just reusing the same component with the same view basically. If you go back, maybe you can do the grid issue with the issue. So just putting some simple description and you have it. And what else? There's the search and there's some basic functionality, but the highlight is basically the board of Jira. So if you look at the board on Jira, this is how it looks like. It is my company stuff, so don't take any screenshots out there. And they have much more stuff, obviously. But I will try to make it quite identical somehow. But still, there's not exactly 100% the same. And let me go back to the slide. So this is a yo-yo.jira.chunketting.com. You can go in and take a look while I'm presenting. And it's just a gif that I do before, what I just showed you. So the motivation behind it when I start to work on the Jira clone is I saw quite a lot of cool stuff that we would react or view JS, mostly all of the interactive. And I don't know if there's a lot of game and stuff like that, but with Angular, there's not much on the GitHub. Or maybe I haven't seen it, but from my point of view, there's not a lot. And all of them was just very simple, just the list view or to delete, which is not really something we view on the day-to-day work. I also wanted to experiment what I wanted to try with Angular for a long time. So Agita is the state management library, which makes the process of managing the state is much simpler than if you're using NGI. Tailwind CLS is more like a CLS framework, utility, like they have one of the classes for you before so you can just use it. We've been talking about it later on the slide. And NGI is like the end design that provides a set of components to view web application. And also, when I view Jira, I wanted to also demonstrate a bit of my experience after working with Angular for four years. So at least I have something that I can view application, which hopefully is quite complicated. And I wanted to feature it in our technical series about 100 days of Angular, which my friend, like some of my friend and I, we were written about how to use Angular and how it's like shaping the web application in real life. But it is at the moment only available in Vietnam. And we don't have the efforts to do it in English very soon. The technical aspect behind it is I see the project with Angular CLI, which is just a common line interface to create new Angular application easier. Instead of you have to copy all of the file over, you just do run a simple query. And that's it for you. Akita is, we'll talk about it later. It's basically a state management library. NetJS for some basic API query. But recently I removed NetJS, I just stopped it because I deployed NetJS to Heroku. And sometime, like Daniel said, if the server is not wake up, it will take a while to start at the beginning. So it's slowed down the application. And I should replace it with just static JSON file hosted on Netlify. Well, there's some UI module for the tailwind and the CDK for drag and drop module. And NJS queue for the text editor. And last is Netlify to deploy it to host it. So we love what the high level design is like for every Angular application, always has at least one module. For either, is it like a simplest app in Angular has always has at least one module, which is F module. So also in my project, it is the root of everything. And I also have some core module, which is authentication or other thing. Also, when I break it down, it is like when you go to the website. When I slap the project, it will actually load the project module, which is this project module. It is not like load everything in one shot at the beginning. So it's just try to save and speed up the application at the load time. It goes the same for log in module, like when you want the user to enter the credential to start to use the app. You don't want to add that step to load the project module. But of course, you can start to preface in the background. And also in the background is my wife. She's standing there. Also, there's the GR control. So basically in Angular, when you need to use a component, it is not just like from a component. You import another component, like React.js. You also need to import it into the module before you can use it. So for a set of common component, what you can do is you can have a share module for control. So in the GR control module, it's basically like the custom button or custom text box. So I have it here so I can share the code a bit. So let's go into the GR clone. So like you see, there's an app module which imports some of the needed Angular module by default. I have to import it to use app. And because Angular is a framework, so this has a lot of building like HTTP to work with. I also need the GR control for some part of that. And the rest is some of the stuff that I need. So you go to the project module. You can see that I also import a lot of component. And also, there's a lot of module that I need to use on the board itself. And like I mentioned, I also imported the GR control module. Because in Angular, if you need something, you need to import it like you import it on the app module already, but it's not enough. You need it in the project module. You also have to import the module into the actual module that you need to use the code. And also, like the login, I also need to import GR control just to have some kind of text work. Yeah, I think that's basically it. So we go to the next slide. So behind the scene, when I start to build the layout, I start to look into some of the maybe I need to just start to write a code from the beginning with all of the flex layout. But I saw Tailwind. And Tailwind, basically, is an antenna-based framework for really building design, like fast. On the screen, I have a GIF. So basically, Tailwind has prepared all of the atomic CS class for you. Let's say you wanted to have the magnetop with five pieces. They have M desktop, that one, for example. And you don't really have to extract it to a new classes. And you need to write CS from stress. And we will talk about it a bit later. Maybe, yeah, actually, I can show Tailwind in action. But OK, maybe we should show it later. So why is Tailwind? Like I said, I always have the use of where I need to do just a little bit, just one line of CS. And if I need to break it into the class, it can be a lot of effort. I mean, I don't know. I just don't like it at all. If I have the cursor pointer, and I need to use it in one small element, if I want to break it into a class, it will be repeated all over. So I have a few options to really do this kind, like small style. The first one is always in line style. And it will always have the big GIF, like the strong GIF effect. So it is difficult for you to overwrite. And the quick one, the pro is basically, it's very quick to write. But it's messy. The second way is that you can start to really define for one line of CS, you need to define one class. And it will make the code look much structured, and also because it encapsulated in the components. If you use scope style in React, you don't want it. You don't afraid about this class will be liquid outside. Like you have my button using in another places, you don't have to worry about that. And this will pose the problem because it encapsulated. So because I have this, I wanted to reuse this because a pointer in many other places. It is not like it has to padding of two and margin of four. It is very like, could be reused somewhere. So if you like scope it into the component, you won't be able to reuse it. And the last option that I have is I can start to really generalize the pattern when I define as the class itself. So I could do a set of component class name for only cursor. I could do I can dash active for cursor forward, or I can dash default for cursor default, or PEL dash one for pending left five, and PEL dot two for pending left 10 pixel, for example. And I mean, of course, for this kind of class, I will not write manually. I can have all of the mixing with SAS to help me on that. But I don't know, it is like, if I start to build it, I need to document it somewhere so that my team member can reuse it. Because if there's only me in the team, it's easier for me to reuse all of that. But if there's a new front-end engineer coming, of course, there needs to be some reference so that he can refer to and start to use it. Otherwise, he will also start to introduce new class and maybe inline style that we don't want. That is when Teowin come to the places. So Teowin is like, have the very clear documentation on Teowin CLS. So you go in, you see this example. They just put a bunch of class inside. And all of that, there's the convention behind that. So if you want to do h, which is high, it will have the set of predefined. So you need to go through documentation. And you just see what you need to do. Container, they have all of this container. And for SM, it's for all kind of break point on the browser. And for this, they have blog, inline blog, fly inline flight, and all kind of stuff. So really, I found out sometimes, it really helped me to speed up the process. But of course, I need to remember the class. And I have to work with Teowin a little bit before. And also, it provided you the, how to, just excellent. You have to remove it first, how do I open this one. You remove it, and close the tab. It also, like, giving you the option for you to customize what you need to use. So they have the concept of Teowin.config file. I don't know what it is, but it's not free installation. So inside this Teowin.config.js, you can put a bunch of stuff. I will share with you later. Because I did it for the Gila layout. So OK, let's remove it first. So at the end, I decided to mix between SCS and Teowin in the project, so there's a cloning code for me, remember. So I think at the end, it's worth the effort that we spend a bit of time to go through the documentation of Teowin, and yeah, we can just start from there. Otherwise, you have to be the one who build the documentation itself. So yeah, there's a lot more work to do. We wanted to do it from the start. And, but OK, so when you write a lot of class for a lemon, you would say, if I have the use case where I wanted to reuse some of that, let's say you have the button, and you wanted to reuse it. So if you have to have another semi-button, you might have to copy a bunch of class over. And you have 10 buttons. You have to copy 10 times over. And I think it's not easy for reusable. So Teowin, I think they understand that there's a problem. So they introduce the concept of apply. So that is a special syntax of Teowin. So basically, what it does is you can put in the class name. And magically, when the view process is running, it will take the CSS behind that class name and plug it inside the VTN nest Teowin. So at the end, if you would have another button, you can start to really share the button across the file. I think I have this example running. So I can just use it. So that is the button that generated with only class. So I go to App Module. So here I have two buttons. The left side is the one that I created with a bunch of class, which is a lot. You see the background transparent. There's a border view, which is that one. And also, I have the button that use the button Teowin. And if you go to the SES file, where I defined the VTN Teowin, I can see that I just basically I do apply for all of the classes using all the HTML. So you can see it like that. So you see that is basically background transparent or text blue 700. But for the special state, like hover, you cannot do just hover or something, because it is not a valet syntax. So you have to do really another state of hover, and then you apply the corresponding classes. Like you, I do hover on a button, and then I apply the background blue 500. Then yeah, here I have to do the same. But you have to do with the hover, like the sector, the procedural classes. And I have it is very helpful, because on the jacqueline, I also use it for customizing the button. Maybe if I can share it quickly, just go back to this one. So all of this button here is customizing with Teowin. So this one, for example. But you go here, OK, not here, not here. You go here, this button is like blue, which is a primary. So I have is, this is a big project, so it's going to be very nested. So it's here control, this button. So inside the button, is it a one? Doesn't it? No, it's not input, it is button. So also, for me, I also use the same for the class button. I have a bunch of class, and I also do apply. And when it is disabled, I also do apply. And when you inspect the code, you can see the button, this button. Now, this button. This button has a bunch of style, which came from this apply. So I don't really write the code, on size 14.5 pixel, it just type from the text button, the class, for example. And I think this text button class will define it on the Teowin config somewhere. No, it's not inside, sorry. But it's just somewhere inside. So it's really like save you some time, because if you have the brief defined configuration, you just apply with your corresponding class. And we will talk about it shortly. And to configure it with viewer of React, I think it's easier, because they have provided the official guide for that. But for Angular, I wrote an article by myself. Just do some custom Wordpack setup, and you need to do a bit, just to play around with Wordpack a bit. Maybe it's a tricky beginning, but it's just easy. So we talked about the layout of GiraClone and how it's built with Teowin. So do you look at the GiraClone? That's the three-pound, the main thing, the three-pound. There's a navigation on the left side, which is a small one. There's a collapsible sidebar, and then this is a content. So that is the blue one is the navigation that I just showed you. So it's NAV, it's navigation. That's blue thing. And then I have this collapsible sidebar, which is like 200 something piece of. This one is 60, 64, and the rest is a content. So I, with Teowin is like, I defy some set of spacing by default. I set the sidebar is like 230 piece of, and the NAV bar left, which is 64 piece of. And on the, when I build the class for that, I'll just do apply and then do W dash, NAV bar left. So that is just the condition, like no, not the condition. It's the syntax, like convention. So you do the W dash, and you put it inside of spacing. So it will understand that you wanted to refer to this configuration. So I inspect the code quickly. I can see that NAV bar left content. And let's take a look at the code and make sure where it is. So it's NAV bar left. And I do apply the W dash NAV bar left. The red underscore is nothing you have to worry about. It just, I think it's some kind of style that I configure. So it's just do like the syntax like that. But basically, I'll just do apply W NAV bar left. And then when you see on the code, this will translate automatically to width 64 piece of. So you don't really have to really do width 64 piece of like that, or you have a variable somewhere. You can do it, basically you can do it, NAV bar left. Something like width. But you have to defy all of that into a variable SCS file. And I found if I define inside this JS, more or less the same, like I do it with variable on SCS. So I think it's more like the preference, like how you review the layout. But I like it better because if I need to change it to maybe not 64 anymore, it could be a hundred. I'll just come to the tailwinds here. Just change this NAV bar left to hundred. And I do it, run build and that's it. It's when just the UI will update automatically. It will be very similar when you change it on the SCS variable. But yeah, that is just, I think just like preference. And when I use tailwind, I'll just try to utilize tailwind. Yeah, I have also the sound variable here. And there's a machine to do a button. Yeah, but yeah, that's what I just talked about. But you might wonder, because tailwind is like preparing all of the class, which is like a lot, like clone, off-sizing a lot. So if we included it into the bundle, it could be resulting in the huge bundle. JavaScript, when we load it, when we serve it to the user and tailwind, if they buy default, they have the perk option. Perk is like that perk. So you can throw this controlling file side. And yeah, it is like when it's uncompressed, it's like too much. And when minified, it's still one much. And when it's digit, still a lot. So basically, you just need to enable this option, which is perk. And it will go through when the view process is taken, it will go through all of the HTML files and then check to see what class is actually using, what class is actually using on your project. So that it will remove all of the unnecessary class. For example, if I only do line, line, what, line. What, line, display, example. So if I only use flex and table, basically all of this blog and inline blog and inline flex will not be included in the final CSR, that is quite useful. And I did a quick test with this project, the tailwind because I just have some button and some margin here and there. And at the end, the result was quite good. But I need to see where is it. Just give me a moment. So here we go, enable the perk option. It will save, right? Where is it? Sorry, it's a bit. Okay, let's, should be somewhere, ah, here, here, sorry. So, when I bundled the file, the CS file, which is at the beginning, it's too big, like one mesh. But when I enable the perk, it's basically just two kilobytes, which is very small. So yeah, you don't have to really worry about the bundled file side when you work with tailwind because they provide it for you. And yeah, let's continue with this slide. So for all my personal recommendation, I would just recommend tailwind to use it, but really depend on what is your preference and how we're gonna shape your project. So we talk about state management a bit because just now it's about more the layout of the front-end side. So when I start to build a project, I mean, I work with IHS, so Akita and IHS is, I think they inherit the redact concept, quite like they follow the redact approach. So when you have the complicated app with a lot of data flowing around and when you seeing that, when you communicate between the component, there's a gap between, there's just too many layers and you start to communicate between like sibling component. It is when you need the state management and I use NGI in a lot of projects in Xilum. And to be honest, it is not an easy concept to understand at the beginning. And on this project, I start to use Akita and let's see how. So it is basically NGI flow. You would always have the reducer somewhere, which do on a switch space, a switch space to all of the action and really handle the state. And you have a big store. Just consider a store is like a big object somewhere and on the component, you select it, like select the data from the store. But when the problem is like, when I started to wanted to face the data in NGI, they introduced the concept of effect, which means that they don't want the tool, the component to know all about HTTP and all kind of stuff in the component itself. So there should be another, like somebody else, someone else, just somewhere. They do all of the HTTPs first and they update the store at the end, update the reducer and then update the store at the end. And I found that is very tricky to understand also. For me, I get it, like eventually I get it, but for some of my team member, it's just difficult for me because it is difficult concept. So yeah, why not NGI is just my personal preference. So maybe you might not really agree, so we can discuss about it at the end of the presentation. So let's talk about how I really need to start with NGI. So I need to create a set of action, which is either from load and load succeed, load something succeed and load something error. And for all of the results, I need to just repeat of the full set. I found that I don't really fancy of that because just a lot of boilerplate need to write. And on the reducer itself, I feel like using Sweet Play a lot, it is just not for me. It's just not the concept for me. But I understand that the NGI team has really, like introducing new syntax to shorten the code that needs to be right. And after you write the reducer, you need to put it into the store module, which is very like Angular concept. In React, maybe you need to do something else, but in Angular, everything you need to be imported into a module at the end. So it's for load, meaning it needs to be on a very top level of the application. And from all of the components, you need to create like select from the store or you need to create the selector like dependency injection like the service and you can query data from service. And when you need to do something, you call in dispatch to dispatch an action. And that is the part I should talk about, about the effect. So when you need to press data, because the team they wanted to disconnect the HTTP, the call is side effect from the component itself. So there will be somebody which call effect to handle it. So we also need to dispatch when you go to the application, you still need to dispatch the action to load the data. But then the load data will be listening into the effect. And then in the effect itself, they will start to really handle all of the HTTP request and all of the success and error from there. And on the component itself, you query to the selector. And once the effect updates the selector, then you have it on the component. I think for normal use, it is easy to work with, but just a lot of code needs to be written. And also when there's error, it is just difficult to choose where is the root code and I just don't like it. And yeah, because my team is consisting of my and myself and some of the junior friends. So when they're joining in, they just don't even know what is your query so they need to understand a lot of concept that I'm gonna because not just very simple, like just a component in life react, but also there's EDI and IHS and observable and a lot of stuff. And when I introduced NGI, they still need to learn a lot of stuff as well. So I think if you have some experience easy for you, but for the new one, NGI is just not something very intuitive at the beginning. And we talk about Akita later. So I will share some of the code I'm comparing between NGI and Akita so we can really in the same place. Yeah, so let's just show you some of the code. Maybe it's easier. So I'll show you some of my code in Xylem first. So there's the store. So I need to define the user. So let's say I have this context reducer which I need to define instead based on an interface just to have a type and reducer basically just the base function that do all type of squeeze case. And for each type of action, you will have to handle it differently for each type of action. But let's go back to the action. So there's this few action. Yeah, so always there's a lot and then lot succeed. And there's a lot of failure. And also there's a lot of failure and also a lot of failure succeed. And you will have another resource. This could be another set of three action at least. Could be load something and load something succeed and load something failure, which is okay. It's not something that I like. And the thing is, the trick is like, is this effect? Because when I call the load action, let's go back to this action. So I need to call it some way. I do this brand new. Yeah, I have the context that I have the facets of. Facet is I just to abstract the store. So that in the future, I can just easily replace this store implementation with something else. Because if you inject this store into every single component, it will be difficult in the future. If you want to migrate this NGIS, like migrate the state management to a different library, for example, it could be Akita or NGIS. So I introduce the facet. The facet, so basically just another layer of abstraction where you can talk, query data and disparate data. So I don't disparate it directly from the store in the component. I do it through the facet. So what is that? The component will go through the facet and then call the load. And then in the load of the facet, it will call the actual load action. And because the action here is defining so that the effect can handle. So you need to go to the effect. So on the effect itself, it will listen to all kind of action. So every action disparate will go through the effect. And even in the type of load, you will go through this function to actually make the request to the server. And then you start to disparate the facet and the failure action. So when the facet is updating the store, basically on the component, you can start to query from this collection. I do it like that everywhere. But when it's failure, it is getting tricky. So yeah, for my screen, when I got some error with effect, it just couldn't get to the place where I can recover for it. So I'm not really recommend to use it. So it is about NGX. So for Akita, it is a bit, I would say maybe much more simpler. So you don't have to define all kind of action, basically. You just need to define it in the store. And then you need to define a query and from your service, I will form your service to call to the HTTP server, you can update the store from there. So let me open the code where I do this project store. So there's a state. So there's a project folder which inside the state, there's a store, very simple. I have an user and the land and this code has something which has a lot of data. It's just basically an object of a project. So which is that one? This whole UI is serving from the single store. So all of this issue is coming from this land and then inside land is each land consists of several issues. This land consists of several land and each land consists of several issues, project issues. So for Akita, you just define the state simply and you just create like when the project is initialized, you just create the initial state and from the service itself, you just inject the store and then you have the store and you can start to use it when you do land project, when I just go to the server, I do this first, which means just go to the server and have some data and then when the process is succeeded, I'll just update the store immediately. I don't need to dispense any kind of action. So somebody will handle it, I'll just update the store immediately after I have data and if everything is finished, I'll just do set loading, which is set the loading state of the store. So they have error and loading is built in. So when you define this store, basically you have the loading like state and also the error state. So you don't have to define it on this initial state anyway. It is included when you define it and I found it very intuitive. It is like the flow that I think when I record, I have some data, I update the store and when the store have some data, which is the query kicking, so you can just inject the store and then you start to select all bunch of stuff and this is when we turn you in some kind of observable. So observable is just the representation of like the data could come in the future. It's like promise, but instead of promise, it returns a single data. Observable, we just keep sending data over time. So when you have this observable, when you listen to it somewhere, when there's a new data on the store, get updated and you use immutable that you update the object reference. It will really send the update to you. So you can do, okay, I don't do this here, but let's say you can do subscribe and you have the user here. So every time, every single time the user array, this one is updated and there's a new reference of the array on the store, you will click it and you know the data here inside. You relay like make the component pure so you don't really need to depend on the component on the chain detector of the framework itself to update the UI. You can really have the data and then tell the component to render it, like check the rendering on the UI. So you can be faster because comparing like object reference is much faster than if the library have to really go deep into every single property and see if there's any chain on the UI, on the data and then they update the UI. It will be much more expensive if you do it. So I think it's just the basic idea of how says management work and Agita is doing it very well for me and I really like it. And the next one is the very end of this talk today. So after I build all the stuff, I need to deploy somewhere. So I choose 95. So 95 basically is like static file hosted. So after you run NPM, you will have some kind of HTTP and Javascript and HTML and Javascript and CLS, all of the static file content, you can host it in 95. So it's very simple. You just connect it to the GitHub repository and you put in the build command and then that's it. After you push to master, it will automatically build the project for you and then it will serve it on the URL. But I do a lot of nullify on my personal account. So I have this DRAM which is doing. So to set up is quite simple. You just need to supply the build which is you connect it to repository and you select the like what branch you want to build when there's a push commit and just do a command and then select the distribution folder. And that's what you're seeing on this one. This one is the result from this build. So if now I commit a chain on the repository, that red repository, I push it to master and then of course they will start to do build here. But if I like push another commit on another branch, so it's trying to do the deploy review which means they're trying to build this the new commit in another branch to see if it really like get you succeed on a server because sometimes you never know when you do build on a server they need to restore all of the NPM from the server. And then maybe one of the library you are using is removed. So it could be failure. You will never know. So that is this deploy review. And it's very helpful I guess. And another thing I'm using to publish the web is like I ring like Heroku. So I have the Nest JS API which is deployed to Heroku. So basically, Nellify is only to host the static from like HTML or JS. But if you need a server which is running 24-7 and always listening to a request from the client you cannot do it with Nellify. So that is Heroku with commit. And I'll just choose maybe Daniel will have a better explanation about Heroku later but I'll just use it for first time to deploy my simple API for this GRClone. So it is the GRClone API. And it's very simple. You need to connect to the repository and set up the build command. And after that, it's just every time you push they will trigger the build like the process for you. And yeah, that's it. I think I have the domain of the API even I don't use it. So if you go there, you can see that it's the simple API. Just put the text here and you will slash project. It will just give me a text adjacent so that I can get it from there and then I'll just run it on the UI. Very simple. It is not like posting and I need to connect to any database at the moment. It's very simple. It's just the fixed structure of the data all the time. And that's it. Yeah, I think that's it. Yeah, I think that's it. I think this has been a long talk and now it's the Q&A. I don't know why the Q&A is just trying to trigger the analysis. Yeah, anyway, I finished. And I hope that you enjoyed it and I learned something from it, maybe. And you have any question? It's now the time to talk. That's cool. Thank you, Trung. Thanks. Before you guys have any question, go to the report and give him a star. Oh, yeah, yeah, yeah, yeah, yeah, yeah, yeah. Let me do it. You don't have to remember the GitHub URL. You just do gira.truncate.com. Oh, now there's hope. Okay, on the right side, I have prepared you a button so you just click into it and there's a star. Okay, so now it's almost a thousand. I would appreciate if it's good, makes thousand soon in the future. But anyway, so any question, anyone? Any idea about the status management, like what you are using and maybe you have something to share about that? My question is actually on tailwind. Yeah. Also, really good talk. You know, it's like, not every day you see someone giving you insights into a really big project or a project of this size, like all the way from UI to the backend and state management and even deployment. So I think really good range. So you mentioned, like I use tailwind also. I really like the utility-first approach. I think like you mentioned, as the project grows, it gets really hard to keep track of the classes. So if someone new is looking at the code base, they're just seeing a bunch of PT is two and MX is five and there's a bunch of really new class names. How would you approach documenting that? Oh, I see. I mean, usually I don't just, even I use tailwind, I don't do my own class. So I just don't document it. I just ask my team to go to tailwind documentation and see the reference from that. I think they have a very good documentation and everything, so usually I don't have a lot of customizing, so for JIRA, I just have this spacing for the nav and navigation bar and the size bar. And yeah, I think that's it. The rest I'm just using by default tailwind. So I'll just ask my team members to first look at tailwind, how they're doing, just get the idea from that. We can do a bit of coding together and then what he needs to do is to refer to this form to the tailwind configuration somewhere. And you're from there. He can really graph what it's like. He can use, if he has some basic knowledge of tailwind, yeah, that is my approach because I just don't really have put it into a company work, so it is usually my outside of the scope. So that's all in me and a few of my friends who are also very familiar with tailwind. So there's no problem for them to get started on that. Oh yeah, no, I get that, yeah, thanks for sharing. Again, really good, really good talk. I'm starting a repo right now. Thank you. Any questions, anyone? So you mentioned that you use NestJS, you start with NestJS and then you kind of dump it? Yeah, sure. Are you gonna consider using Strapi now? Yeah, actually, I mean, I would plan to talk about it, so you see that is a phase two of the project, which is like crazy code, you see the API. My friend, he needs to define all of the detail and all of the crazy stuff to get, like spin up the ground QL, which is on NestJS. And with Strapi, it's just like you run the command and it's running on the server. You have even the UI to see the data, which is funny. I don't know, but my friend helped put a lot of effort into this NestJS V2, so Strapi in it is, I don't know. See all of this. You can have both versions running if you want. Yes, I'm trying. Maybe phase three then, they don't. Cool. And actually, I'll talk about it because there's a question at the beginning. Talk about the monorepo. I think it's worth mentioning, like, because on the phase two, okay, so, let's show you guys the code of the phase one. The phase one is I also host the front end and the back end in the same repository, but it's just to separate the folders. There's no connected between. And I don't know, I feel like there's a lot of things could be shared to package.json file. Like if you use load us in both back end and front end, you can share it. So, I have started to look at this in this workspace. So it is, they provide some building stuff for a monorepo. Basically, like what I have inside this phase two folder is like, there's only one folder which consists of several applications, which is the API is written on Next.js. The GiraClone is written in Angular TypeScript. I could also put another application which is using React.js. And when I run it, usually I start the GiraClone and I will try to break all of the share module, let's say, like share interface or data model into a folder. Inside this live thing, and from there I can import it in both the API and the front end. So you don't need to copy the definition file, TypeScript file over, you just share it via library and then you can use it in both front end and back end. I think it's quite, not quite, it's super helpful. And you can start to introduce all kinds of stuff, React, Angular, many stuff, maybe Vue.js in the future. And yeah, it's just my take on that. But it's a bit of work to set up at the beginning and you might need to have a better understanding of everything to really get started. But after that, everything will be easier for you. You have a monorepo setup. Yeah, I just share that, that's it. So if anyone don't have any question, I'll just share my latest TechSheet game. You can also give me a sign, you'll like to. It's just basically, it's a game I also write, written with Angular and TypeScript. It's based on a Vue project, but the brand of the game, all of the game loop, all of these how the piece is running, it will customize, written on TypeScript. So if you want to play it, you can go to this TechSheet creating, or from the Gira, you can have the link, this is the button, you can click it and you will immediately go to the game. And I hope you like it. Yeah, that's it, too much for me. I hope, I think, talks more today. Any question that you want? Or if not, then Eric, you have the control. Yeah, so.