Todo application tutorial

The easiest way to learn is to learn through examples. We provided tutorials which should help you to start building applications with Sifu.

1. Intro

This tutorial is created with the assumption that you already have some basic knowledge of Sifu specification language and how to use Sifu. Concepts like creating a new specification, running AngularJS web application and Java Spring Boot web server are covered in Notes app tutorial.

Goals for this tutorial are:

  • become familiar with Git workflow we recommend when working with Sifu
  • learn how to model application requirements using Sifu specification language
  • understand the basic security concepts used in Sifu specification language
  • learn how to run generated Java Spring Boot and AngularJS applications using Docker

2. Initiate Git and start a new Sifu specification for the project

Prerequisites for this part of tutorial:



In order to unlock the full power of Sifu, we have developed a workflow which uses Git as source control. This allows you code generation from Sifu specification throughout the project lifecycle and mixing generated code with custom changes when you start implementing business logic to the backend and adding design to the front-end. You could look at Sifu as one more super-fast developer in your team, that`s why we recommend using dedicated branch named 'sifu' that will be used only by Sifu when generating code. For more information check Sifu and Git page.
There are three possible ways how you could initiate Git and start a new Sifu specification for the project:

  1. Initialize Git from remote repository, then manually create branches and Sifu specification file:
    1. start the Terminal and navigate to the project directory
    2. clone previously created remote Git repository (look above at Prerequisites for this tutorial) using command git clone <git repository url> (e.g. git clone https://github.com/github-username/ToDo-tutorial.git)
    3. the previous command will create the new directory named by cloned Git repository, navigate to this new directory, e.g. run command cd ToDo-tutorial
    4. create a new branch which will be used for generating code using command git checkout -b sifu
    5. create a new file with extension .sifu, for this example create todo.sifu using any way you prefer
    6. commit this new document by running command git add -A && git commit and enter the commit message when prompted
    7. switch back to initial branch (e.g. master) by running the command git checkout master
    8. run command git merge sifu to merge sifu branch into the initial branch
    9. run command git push to push local changes to the remote repository

  2. Initialize Git from remote repository, then use Sifu init command to create branches and specification file:
    1. start the Terminal and navigate to the project directory
    2. clone previously created remote Git repository (look above at Prerequisites for this tutorial) using command git clone <git repository url> (e.g. git clone https://github.com/github-username/ToDo-tutorial.git)
    3. the previous command will create the new directory named by cloned Git repository, so you need to enter this new directory, e.g. run command cd ToDo-tutorial
    4. run command sifu init todo - this will create new Git branch named sifu, switch to sifu branch, create todo.sifu document with the initial specification, make the initial commit on sifu branch, switch back to the initial branch (i.e. master) and merge sifu branch into it
    5. run command git push to push local changes to the remote repository

  3. Use Sifu init command to initialize Git locally, create branches and specification file, then push changes to the remote repository:
    1. start the Terminal and navigate to the project directory
    2. run command sifu init --git todo - this will initialize Git and offer you to choose default branch name, just confirm and accept develop, then it will create default branch named develop, create the new branch named sifu, switch to sifu branch, create todo.sifu document with initial specification, make initial commit on sifu branch, switch back to the initial branch (i.e. develop) and merge sifu branch into it
    3. to add new remote to previously created Github repository (look above at Prerequisites for this tutorial) run command git remote add origin <git repository url> (e.g. git remote add origin https://github.com/github-username/ToDo-tutorial.git). NOTE: In order this to work out of the box, when creating the repository on Github, create it without initial commit.
    4. run command git push -u origin develop to push local changes to the remote repository and to set upstream tracking of the local branch

If you have run sifu init command it would create initial Sifu specification file with the model of functional, but a minimal application for creating notes, that we have used for Notes app tutorial and will not use in this one.

To proceed with Todo tutorial please update the content of generated todo.sifu specification file to look like this:

todo project[
  url www.todo.com
  namespace com.todo
](

 #SERVER
 backend server[
   template java-springboot
   developer (your-profile-name)
 ](

 )

 #CLIENT
 webapp client[
   template js-angular

 ](

 )
)

If you have chosen to manually create a specification document, then you should add the above specification to it, as this will be the starting point.

Above specification content provides just enough information for Sifu to generate basic project structure for Java Spring Boot and Angular JS applications. It contains:

  • Starting point and root element for every specification is the project element. We have named it todo.
  • Settings for each element are defined inside brackets. Project element has its own for url and namespace.
  • Next, inside round brackets, we are adding all construction elements for the parent element. Project element consists of server and client elements with their settings and building elements.
  • We have one server element, named backend. This element has mandatory settings for template and developer. We will use java-springboot for the template, and developer name should match profile name of the currently logged user on your machine.
  • And we have one client element, named webapp. This element has a mandatory setting for a template. We will use js-angular to define tech stack our client spec will translate to.

3. Generate Spring Boot and Angular JS project structure using Sifu

Above specification has enough information to generate complete project structure for Spring Boot and Angular JS applications. Using the terminal (or command prompt) navigate to project folder with todo.sifu specification with above content and run command sifu generate. This will:

  • Switch to 'sifu' branch, generate project, server and client structure and code, ask for commit message on 'sifu' branch, commit, switch back to initial branch and merge 'sifu' branch into initial one. Output should be similar to this:
    Todo-generating-1

    Todo-generating-2
  • While running Sifu has written output into console log, so you could check it to see what actions have been done and which files have been created. It has created standard Spring Boot and Angular JS project structures with necessary files. Use preferred way to check what Sifu have generated from just a few lines in the specification.
    If you are using Atom editor, server Spring Boot project structure should look like this :
    Backend-project-structure

    and client Angular JS project structure like this: Webapp-project-structure

At this point, you have all project resources ready to start developing your Spring Boot and Angular JS applications. You could now start your preferred IDE and continue with coding, or you can start modeling requirements for your application using Sifu. What will be faster? What do you think?

4. Start modeling requirements for the web server

Let's see what will be requirements for the Todo application we should model:

  • We need to have a possibility to manage users and view a list of "to do`s" for each user.
  • We need to have a possibility to allow each user to manage only their list of "to do`s".

From requirements, we can conclude we need a web server that will provide access to storage where we will store data about users and todo lists, and expose endpoints toward the web application for displaying and managing data.

In the previous step, we have already defined one server element, named backend, now we will add definitions for server elements we need in order to provide the required functionality. We will use model element to define persistence models which will be used to generate database tables and all supporting code for a web server. For a start, we need two models, one for users and other for "to do" lists.

todo project[
  url www.todo.com
  namespace com.todo
](

 #SERVER
 backend server[
   template java-springboot
   developer (your-profile-name)
 ](
    
    # MODELS
    User model(
      firstName text[min 1, max 40]
      lastName text[min 1, max 60]
    )

    Todo model(
      user User
      task text[min 1, max 255]
      date date[default 2016-1-14]
    )

 )

 #CLIENT
 webapp client[
   template js-angular

 ](

 )
)

For User model, we have defined two elements: firstName and lastName. Both are defined as Model text elements with set values for minimum and maximum length settings. What you cannot see yet, is that we'll enrich this model with Sifu, and add some additional fields during the generation process, depending on other settings. When you define a model, we will always add id element as an identifier, which will be of type long when persisted to the database.

For Todo model we have defined three elements:

  • user element, defined as User type, in this way we are making a relation between two models. When related code and database tables are generated we will add the userId field into Todo table with foreign key reference to id field from the User table.
  • task element, defined as Text element, with set values for minimum and maximum length settings, and
  • date element, defined as Date element, with the default value set to 14.1.2016.

Next, we need to expose the endpoints which will be used by the web application for creating, reading, updating and deleting records. This is done by defining Server API elements. For now, we will add endpoints to cover CRUD operations for defined models. Later we will add more endpoints to cover specific cases.

todo project[
  url www.todo.com
  namespace com.todo
](

 #SERVER
 backend server[
   template java-springboot
   developer (your-profile-name)
 ](
      
    # MODELS
    User model(
      firstName text[min 1, max 40]
      lastName text[min 1, max 60]
    )

    Todo model(
      user User
      task text[min 1, max 255]
      date date[default 2016-1-14]
    )

    
    # APIs
    UserApi api(
      user crud[model User, rest]
    )

    TodoApi api(
      todo crud[model Todo, rest]
    )

 )

 #CLIENT
 webapp client[
   template js-angular

 ](

 )
)

As you can see, we've added two CRUD endpoints just by referencing defined models using CRUD model setting and exposing them as REST service with using rest setting. Later we'll see how the endpoints are generated and how you can check them.

Now it would be a good time to run Sifu again and generate the code from updated specification, so we could check all the goodies we have defined so far. As earlier, using terminal (or command prompt) navigate to project folder and run command sifu generate - this will do several things: switch to sifu branch, generate project code, settings and a script for creating database, commit changes on sifu branch (will prompt for a commit message), switch back to initial branch (e.g. master or develop) and merge sifu branch into it.

Based on above specification with added models and APIs, Sifu will generate new models, repositories, and web rest classes as if they were written by an experienced developer.
To check how Sifu is helping you implement best programming practices take a look at some of the generated code on our Github repository for this tutorial or search your local copies of files.

5. Start modeling web client application, connect it to already defined server and add security to both applications

We can now start modeling the web client application. Having in mind requirements we will start with adding Users page. On this page, we want to view existing Users with their Todos and to manage Users. We will assume this can be done only by the administrator, so we should add security settings that will allow only administrators to access this page. Let's add it to our specification.

todo project[
  url www.todo.com
  namespace com.todo
](

 #SERVER
 backend server[
   template java-springboot
   developer (your-profile-name)
   security (principal User, role UserRole, type(username))
 ](
    #ENUMS
        UserRole enum(ADMIN, MEMBER)
      
    # MODELS
    User model(
      firstName text[min 1, max 40]
      lastName text[min 1, max 60]
    )

    Todo model(
      user User
      task text[min 1, max 255]
      date date[default 2016-1-14]
    )

    # APIs
    UserApi api(
      user crud[model User, rest, secured ADMIN]
      users find[from User, rest, secured ADMIN]
            userTodos find[from Todo where Todo.user.id == userId, rest, secured ADMIN]
    )

    TodoApi api(
      todo crud[model Todo, rest]
    )

 )

 #CLIENT
 webapp client[
   template js-angular
   connectedTo backend
      path /webportal
 ](

      #EVENTS
      UserUpdated event
      ViewTodos event(id integer)

      #PAGE
      usersPage page[path /users, secured ADMIN](

        #BUTTON
        addUser button{on click open createUser}

        #TABLE
        users table[load UserApi.users](
          #LINKS
          viewUserTodos link{on click fire ViewTodos(item.id)}
          editUser link{on click open editUser(item.id)}
          deleteUser link{on click open deleteUser(item.id)}
        ){
          on UserUpdated reload
        }

        #TABLE
        userTodos table[hidden, load UserApi.userTodos]{
          on ViewTodos (show, reload(event.id))
        }
      )

      #FORMS
      createUser form[submit UserApi.createUser]{
        on success (close, fire UserUpdated)
      }

      editUser form[load UserApi.readUser, submit UserApi.updateUser]{
        on success (close, fire UserUpdated)
      }

      deleteUser form[load UserApi.readUser, submit UserApi.deleteUser]{
        on success (close, fire UserUpdated)
      }
 )
)

As you can see, we have expanded client element settings and added to which web server it is connected by defining connectedTo. This setting is especially useful when you define more than one server, or if you would like to connect client only to a specific server endpoint. With path setting, we have defined which path will be used as a base path for the web application. The full path for accessing web application is created combining project url setting with client path setting, in our example this would be www.todo.com/webportal.

 
#CLIENT
 webapp client[
   template js-angular
   connectedTo backend
      path /webportal
 ](...)

Inside round brackets, we have added 4 web application elements: one page, and three forms. With page element, we have defined web page named usersPage we will use to manage users. As for settings for this page, we defined the path and secured. The path is combined with the previous ones (project and client) and used to access this specific page, so the full path for this page is www.todo.com/webportal/users. With secured setting, we are defining who can access this page, and we have put value ADMIN.

  #PAGE
  usersPage page[path /users, secured ADMIN](...)

Now it is a good time to take a more detailed look at the security setting we have added for the server element, and then we can return to this point. In the server element, we have defined security settings that will be used both by server and client applications. Principal keyword is used to define a model name we will use for user identification, in this case, we will use User model. When you define a certain model as principal, Sifu postprocessor adds fields needed for user identification. As we have defined with type keyword a method we will use to authenticate the user to be the username, this means that in postprocessing we will add two more fields to User model: username and passwordHash.

 #SERVER
 backend server[
   template java-springboot
   developer (your-profile-name)
   security (principal User, role UserRole, type(username))
 ](...)

This also means we will generate two more pages for you: signUp page and signIn page, with forms you can use to sign up new user and sign in existing user based on the enriched User model. In our example, you can access this pages through next URLs: www.todo.com/webportal/sign-up and www.todo.com/webportal/sign-in. With role keyword, we have chosen to use role-based security in our applications, and we have used enum element with name UserRole to list available roles. In this server enum element, we have listed two enumerations: ADMIN and MEMBER, as these roles will be enough for this example.

  #ENUMS
  UserRole enum(ADMIN, MEMBER)

Let's go back where we left in defining a page for users. Now it should be clearer why we have added ADMIN for the secured setting. We want to allow access to this page only to administrator accounts, as they only should have the possibility to manage users. For page element, inside round brackets, we continued with adding page elements. We have one button element and two table elements. We have named button element addUser and defined its behaviour inside curly brackets. We used on click behaviour to activate open action on createUser form. Open action will open the form in a modal window.

  #BUTTON
  addUser button{on click open createUser}

As we want to display all users in a table, in order to provide necessary information we have added to server API elements new find endpoint named users, exposed as rest, and secured so only user accounts with role ADMIN can access it.

# APIs
UserApi api(
  ...
  users find[from User, rest, secured ADMIN]
  ...
)

Table element with name users will be used to display all users, that is why we have defined load endpoint in settings and with value UserApi.users. This endpoint will be used when fetching data from web server. Data returned from this endpoint will define which fields will be created within the table. Next, inside users table, we have added three link elements, so when this table is generated it will have three additional columns, each column will contain one link element for each row in the table. For first link viewUserTodos, we defined on click beaviour to fire event named ViewTodos and passed a parameter (item.id). This parameter is taken from an active record - row in the table. Next two links, editUser, and deleteUser are calling on click behaviour to activate open actions on editUser and deleteUser forms with passing (item.id) parameter. This parameter will be used as the input value for forms load endpoint. For table behaviour we have defined reload action initiated with on event behaviour named UserUpdated.

  #TABLE
  users table[load UserApi.users](
    #LINKS
    viewUserTodos link{on click fire ViewTodos(item.id)}
    editUser link{on click open editUser(item.id)}
    deleteUser link{on click open deleteUser(item.id)}
  ){
    on UserUpdated reload
  }

In order to provide needed data for the second table, we had to add another find endpoint to UserApi. We have named it userTodos, defined the inline query to fetch the list of Todo`s for selected user (id is passed as a parameter), exposed it as rest, and secured to allow access only to user accounts with role ADMIN.

# APIs
UserApi api(
  ...
  ... 
  userTodos find[from Todo where Todo.user.id == userId, rest, secured ADMIN]
)

Second table element on our page is named userTodos and is used to display the list of Todos for selected user. We have used hidden setting to make this table hidden when the page is initiated, and load setting to define UserApi.userTodos as endpoint which will be used when creating table and loading data into it. On event ViewTodos behaviour will show this table on page and load data for selected user, as we are sending selected user id parameter (item.id) when we click on row in table and will use it for reload action which receives (event.id) parameter from fired event.

  #TABLE
  userTodos table[hidden, load UserApi.userTodos]{
    on ViewTodos (show, reload(event.id))
  }

Next, we have three form elements, which will generate modals for creating, editing and deleting users. Modal is created when the form is initiated using on click behaviour with the open action. For createUser form in settings we have defined an endpoint which will be used to submit data. Also, this endpoint will be used when the form is created to provide information which input fields to generate. Endpoint UserApi.createUser is one of generated crud endpoints based on the User model, so it will put 4 input fields on the form: firstname, lastname, username, and passwordHash. As a behaviour, we have added on success which will close modal and fire event UserUpdated. This event will be used to initiate reloading of data into users table.

#FORMS
createUser form[submit UserApi.createUser]{
  on success (close, fire UserUpdated)
}
...

For editUser form in settings we have used both load and submit endpoints. In this way, we have defined UserApi.readUser as load endpoint, which will be used when creating form and populating data into it. Data is populated based on item id sent from users table when we click editUser link located in users table row for some user. UserApi.updateUser we have defined as submit endpoint and it will be used to update user record with data populated in editUser form. If submit action is successful it would trigger on success behaviour, same as above.

  #FORMS
...
  editUser form[load UserApi.readUser, submit UserApi.updateUser]{
    on success (close, fire UserUpdated)
  }
...

In deleteUser form, we have defined UserApi.readUser as load endpoint, and UserApi.deleteUser as submit endpoint, and in this way, when generating form we will create confirmation modal window for deleting selected user.

  #FORMS
...
  deleteUser form[load UserApi.readUser, submit UserApi.deleteUser]{
    on success (close, fire UserUpdated)
  }

As we have finished modeling part of requirements related to Users, we would recommend you to take a short break, and run sifu generate. In this way, you will check to see if your specification is valid and if the code can be generated. If you are using Atom with Sifu language plugin validation will be done on each save. After successful generation, take a look at the code we have generated from changes you have made in this section.
After pushing changes to remote repository Github merge report shows we have updated 49 lines in todo.sifu, including comments, which has produced changes to 73 files with 5.022 additions and 39 deletions. What do you think, how much time did you save?

6. Continue modeling web server and client application, extend models and APIs, add new web elements

Now that we have seen how to define Users page using Sifu specification language, we will apply same principles when writing specification part for Todos page.

todo project[
  url www.todo.com
  namespace com.todo
](

 #SERVER
 backend server[
   template java-springboot
   developer (your-profile-name)
   security (principal User, role UserRole, type(username))
 ](
    #ENUMS
        UserRole enum(ADMIN, MEMBER)
        Status enum(NOT_STARTED, IN_PROGRESS, DONE)
      
    # MODELS
    User model(
      firstName text[min 1, max 40]
      lastName text[min 1, max 60]
    )

    Todo model(
      user User
      task text[min 1, max 255]
      date date[default 2016-1-14]
      status Status
    )

    # APIs
    UserApi api(
      user crud[model User, rest, secured ADMIN]
      users find[from User, rest, secured ADMIN]
      userTodos find[from Todo where Todo.user.id == userId, rest, secured ADMIN]
    )

    TodoApi api(
      todo crud[model Todo, rest]
      todos find[from Todo join User on Todo.user,
                              response(Todo.id, User.username, 
                              Todo.task, Todo.date, Todo.status),
                              rest,
                              secured (ADMIN, MEMBER)]
    )

 )

 #CLIENT
 webapp client[
   template js-angular
   connectedTo backend
   path /webportal
   home signInPage
      loggedin todosPage
 ](

      #EVENTS
      UserUpdated event
      ViewTodos event(id integer)
      TodoUpdated event

      #PAGE
      usersPage page[path /users, secured ADMIN](

        #BUTTON
        addUser button{on click open createUser}

        #TABLE
        users table[load UserApi.users](
          #LINKS
          viewUserTodos link{on click fire ViewTodos(item.id)}
          editUser link{on click open editUser(item.id)}
          deleteUser link{on click open deleteUser(item.id)}
        ){
          on UserUpdated reload
        }

        #TABLE
        userTodos table[hidden, load UserApi.userTodos]{
          on ViewTodos (show, reload(event.id))
        }
      )

      #FORMS
      createUser form[submit UserApi.createUser]{
        on success (close, fire UserUpdated)
      }

      editUser form[load UserApi.readUser, submit UserApi.updateUser]{
        on success (close, fire UserUpdated)
      }

      deleteUser form[load UserApi.readUser, submit UserApi.deleteUser]{
        on success (close, fire UserUpdated)
      }

     #PAGE
          todosPage page[path /todos, secured (ADMIN, MEMBER)](

          #BUTTON
          addTodo button{on click open createTodo}

          #TABLE
          todos table[load TodoApi.todos](
          #LINKS
            editTodo link{on click open editTodo(item.id)}
            deleteTodo link{on click open deleteTodo(item.id)}
          ){
            on TodoUpdated reload
          }
          )

          #FORMS
          createTodo form[submit TodoApi.createTodo]{
            on success (close, fire TodoUpdated)
          }

          editTodo form[load TodoApi.readTodo, submit TodoApi.updateTodo]{
          on success (close, fire TodoUpdated)
          }

          deleteTodo form[load TodoApi.readTodo, submit TodoApi.deleteTodo]{
            on success (close, fire TodoUpdated)
          }       
 )
)


As you might have noticed, when we were defining Todo model we have forgotten (could say it was on purpose) to add a field which will be used to set status for our Todo task. No problem, without much fuss, we now have added new Status enum, and expanded Todo model with Status enum element named status. To support logic for displaying data on Todos page, we have added todos find endpoint. For this endpoint, we have used inline query element to define request, and we defined how the response will be mapped to joined model elements. We have extended security to allow MEMBER role also to access todos endpoint.

#ENUM
Status enum(NOT_STARTED, IN_PROGRESS, DONE)
#MODEL
Todo model(
...
  status Status
)
#API
TodoApi api(
...
todos find[from Todo join User on Todo.user,
                        response(Todo.id, User.username, 
                          Todo.task, Todo.date, Todo.status),
                        rest, secured (ADMIN, MEMBER)]
)

To define which page will be used as the homepage for our web application we have added home setting with value signInPage, as we do not want to allow unauthorized access to our web application. Even we did not define Sign in page in the specification, we will generate this page for you when you specify security type for your backend application. Next, we have defined loggedin setting with value todosPage. This setting is used to set the page which will open after the user is successfully logged in.

 #CLIENT
 webapp client[
...
   home signInPage
      loggedin todosPage
 ](...)

Using approach already described for usersPage, we have defined new page element named todosPage. This page has it`s own settings for path and security, to allow logged in users with roles ADMIN and MEMBER to access the page through www.todo.com/webportal/todos url. We have defined same elements on todosPage page as we have on usersPage but connected to TodoApi endpoints.

We could say that with this last changes we have added our requirements for this tutorial have been covered, so it is time to run Sifu and generate code again.
Run command sifu generate - this will do several things: switch to sifu branch, re-generate project code, and settings, create database migration file for updating database model, commit changes on sifu branch (will prompt for commit message), switch back to initial branch (i.e. master or develop) and merge sifu branch into it.

After pushing changes to the remote repository, this time, Github merge report shows we have added or updated 41 line in todo.sifu, including comments, which has produced changes to 43 files with 1.607 additions and 20 deletions. What do you think, how much time did you save this time?

In the meantime you can start adding your custom code, extending business logic, adapting UI design, continuing the process until applications are production ready. One thing we should point at this time is to use initial (master, develop etc) branch for any kind of customization, and NEVER do any customization on sifu branch. In this way, you will avoid any inconvenience you could encounter when merging generated and custom code.

7. Run Sifu generated AngularJS web application connected to a Java Spring Boot web server using Docker

Prerequisites for this part of tutorial:



We can now continue and see how to run the web client and the web server applications using Docker. Instructions in this tutorial cover running Docker on Ubuntu Linux, if you are using different OS minor adjustments may apply.

Assuming you have done all steps previous steps from this tutorial and finished the setup of Docker and Docker Compose, starting generated AngularJS web application connected to a Java Spring Boot web server using Docker is trivial. Inside you project folder we have generated docker folder containing Docker Compose files with configuration for services. Using terminal navigate into docker folder and run sh docker-start.sh. You will be prompted to choose which environment you wish to start. Accept default value dev to start development environment, give it some time to download images, create containers and initialize database, backend, and frontend applications, and soon you should see in terminal output similar to this:
Docker-started

This means Docker containers have been started successfully, and you can proceed and open your web app. Open the browser of your choice and navigate to http://localhost:3000/. It should automatically redirect you to Sign in page on address http://localhost:3000/#/webportal/sign-in, like this:
Webportal-signIn-page

To proceed you will need to open first http://localhost:3000/#/webportal/sign-up page, just click on provided link below Submit button.
Webportal-signUp-page
Populate all fields and submit data to create a new user. This will create a new user and assign it to ADMIN role, as this role is first in our UserRole enum list and is used as default role if default role is not explicitly defined. After success, you will be re-directed to http://localhost:3000/#/webportal/sign-in page again to proceed with signing in to the web portal. On Sign in page enter username and password, you have used in the previous step and submit. After submitting you should be redirected to Todos page, and it should look like this:
Todos-page

By clicking on Add todo button you will be shown modal window for creating new Todo:
Create-Todo
populate all fields and create one. Tip: for User id set value 1, as this would be your id if you have created only one user so far. Depending on how you populate fields, after creating Todo, you should see it in table on todos page, like this:
Todo-list

Let`s check how does the page for users looks like. In browser address field enter http://localhost:3000/#/webportal/users, it will open Users page, similar to this one:
Users-page
where you can add a new user by clicking on Add user button which will open a modal window, like this:
Create-User
and, you can click on View user todos link in the table for some user to see Todos he/she has created:
View-Todos-for-user

You can now continue and explore web application and implemented functionalities in a way you prefer.

8. Wrap-up

Congratulations!!! You have finished the Sifu tutorial for making basic Todo application. We hope you have got a valuable insight into how you can be faster using Sifu. In less than an hour you have written the specification, generated the project which contains code for a Java Spring Boot web server and connected AngularJS application, security settings, database, configurations for development, testing and production, and a made it easy to deploy applications using Docker.

In this tutorial we have shown you how to unlock the full power of Sifu using it in combination with Git, how you can model requirements and easily add security using Sifu specification language, how specification can evolve through time and help you develop your applications much faster. Now you can proceed with adding the business logic to the application, customizing the design and other more interesting things, as we have done the dull work instead of you.

If you have liked this tutorial, you might want to check Petclinic app - part 1 tutorial for more advanced server side concepts and Petclinic app - part 2 tutorial for more advanced client side concepts we have to offer.

If you think that we can improve this tutorial in any way, feel free to send us feedback, we will appreciate it.