ToDo app with Sifu code generator
Tags: angular, java, webdev, programming
Published: 2021-11-04 07:56:34

As part of promoting DRY (don't repeat yourself), MDD (model-driven development), and code generator, I would like to show its full power on a real-life example.

We will implement a simple ToDo app with backend and client app. Let's start.

## ToDo project
First we will define the project with basic informations.

```
todo project[
    url www.todo.com 
    namespace com.todo
    version 1 . 0 . 0 . 0
    environments prod
    developer(duskovesin)
]( 
```

### Backend
Now we will define the #backendpart of the app. 

```
backend server[
        owners(duskovesin)
        template springboot(tests fabut)        
    ]
```

We are starting with the definition of User and Todo #models, with a few fields and Todo Status #enums.

```
        UserRole enum(
            ADMIN
            MEMBER
        )

        Status enum(
            NOT_STARTED
            IN_PROGRESS
            DONE
        )

        User model(
            firstName text[min 1, max 40, searchable]
            lastName text[min 1, max 60]
        )

        Todo model(
            user User
            task text[min 1, max 255]
            date date
            status Status
        )
```

We also need to specify the type of security that we want to use in the app, in this case, we are using role-based security on top of the User model with #username and #password as security #authentication.

```
        security(
            principal User
            role UserRole
            type username
        )
```

Now we can focus on APIs. We will create two sets of #REST APIs. 

#### UserApi
UserApi will have #CRUD API endpoints for manipulation with users in the system, that can be accessed only by ADMIN users, users endpoint to access to all users in the system, and one that Admin can use to check other users Todos. 

```
UserApi api(

            user crud[model User, rest, secured ADMIN]

            users read[
                select from User
                rest
                secured ADMIN
            ]

            userTodos read[
                select from Todo
                     where Todo.user == user
                     orderable by Todo.task
                rest
                secured ADMIN
            ]
        )
```

#### TodoApi
TodoApi with CRUD endpoints for users to be able to create ToDo and userTodos endpoint that will be used by any users to access ti his own ToDos.

```
        TodoApi api(

            todo crud[model Todo, rest]

            todos read[
                select from Todo
                     join User on Todo.user
                response list dto(
                    Todo.id
                    userUsername User.username
                    Todo.task
                    Todo.date
                    Todo.status
                )
                rest
                secured(ADMIN, MEMBER)
            ]
        )
```

On average, for developers to implement all controllers, APIs, DTOs, models, enums and repositories, db-changelogs and all other parts of sping boot infrastructure code would take at least a few days...


### WebApp
Now lets move to the client part of the app.

First, let's define the client app and specify which type of applications it will be generated to. Also, we will define, to which backend it will be connected. Also, we will define the application path and which page is the home page for admin and member users.

```
webapp client[
        owners(duskovesin)
        connectedTo backend
        template angular
        path /webportal
        home todosPage(ADMIN, MEMBER)
    ]
```

Now we need to create two pages, one for users to organize their ToDos and the other one for admins to administrate with users.

####ToDo page
ToDo page will have a list of user todos, add a button for creating new todo, edit button for opening edit form and delete button for todo deletions. All components will be connected with appropriate API calls which can be seen in the spec.

```
        todosPage page[
            path /todos
            secured(ADMIN, MEMBER)
        ](
            addTodo button {
                on click open createTodo(none) {
                    on closed do todos.load
                }
            }
            todos table[
                load TodoApi.todos
            ](
                editTodo button {
                    on click open editTodo(item.id)
                }
                deleteTodo button {
                    on click open deleteTodo(item.id)
                }
            )
        )

        createTodo form[
            submit TodoApi.createTodo
        ] {
            on success close
        }

        editTodo form[
            load TodoApi.readTodo
            submit TodoApi.updateTodo
        ] {
            on success close
        }

        deleteTodo form[
            load TodoApi.readTodo
            submit TodoApi.deleteTodo
        ] {
            on success close
        }
```

#### Users page
The users page will be organized in the same way, with a small difference that the admin user will be able to access the ToDos of the other users.

```
        usersPage page[
            path /users
            secured ADMIN
        ](
            addUser button {
                on click open createUser(none) {
                    on closed do users.load
                }
            }
            users table[
                load UserApi.users
            ](
                viewUserTodos button {
                    on click fire ViewTodos(item.id)
                }
                editUser button {
                    on click open editUser(item.id)
                }
                deleteUser button {
                    on click open deleteUser(item.id)
                }
            ) {
                ViewTodos event(id integer)
                external {
                    on ViewTodos do userTodos.reload(event.id, none, none)
                }
            }
            userTodos table[
                input(*, *, *)
                load UserApi.userTodos
            ]
        )

        createUser form[
            submit UserApi.createUser
        ] {
            on success close
        }

        editUser form[
            load UserApi.readUser
            submit UserApi.updateUser
        ] {
            on success close
        }

        deleteUser form[
            load UserApi.readUser
            submit UserApi.deleteUser
        ] {
            on success close
        }
```

Security page with sign-in form is automatically generated according to the best practices.

The amount of code that's necessary to write to do this basic implementation is:

```
Language                     files          blank        comment           code
-------------------------------------------------------------------------------
Java                           148           2056             93           9193
TypeScript                      45            660            113           3083
HTML                            19              1              0           1114
XML                             14              0              4            881
JSON                             9              0              0            654
Maven                            3              0              4            246
Sass                            11             44             12            152
YAML                             3              2              0            102
JavaScript                       2              3              4             61
Markdown                         2             13              0             16
-------------------------------------------------------------------------------
SUM:                           256           2779            230          15502
-------------------------------------------------------------------------------


```

Thanks to code generator sifu we are able to implement it in under 30 minutes...

You can check the [code on github](https://github.com/alchemycloud/todo)