# Creating a real-time Trello board with Phoenix LiveView-Part-1

<!---
This will be three-part series on creating a Trello board using Phoenix LiveView.

### Part - I
- Introduction
- Generate project
- Add Task and User migrations
- Add Task and User struct
- Add API Layer
- Add dummy data
- Test the API layer in the console

### Part - II
- Add HTML
- install `sortablejs`
- Add hook
- complete the flow

### Part - III
- Add subscribe
- Add broadcast
- Read the broadcast with `info`
- Minor Refactoring
-->

[Trello](https://trello.com/home) cards help you to collaborate, manage projects, and reach new productivity peaks(As per their official Website 😊). You may have used it earlier or some similar board like [Jira](https://www.atlassian.com/software/jira) to manage projects and tasks. When I joined one of my previous organizations, my training was tracked using the Trello board which helped me and other new joiners in learning and track our progress. In this Blog, we are about to create a similar board with a real-time update feature. 

### What are going to build?
We are going to build a Trello look-alike board. It will have different cards belonging to different sections. We can drag and drop cards to different sections with a smooth transition. Along with the drag-and-drop transition of cards to different sections, the whole experience will be real-time. If any user makes any change in the card section then any other user watching the application screen doesn't have to explicitly refresh the browser to see the effect. Refer to the `gif` below to get an idea.

![tasker.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1660508087985/GazzESvF0.gif align="center")

### Blog series!!! 
This is a 3 part blog series. 
- **Part 1:** We will be generating the application, adding the different tables, and the API layer, and we will test the API layer in the `iex` shell (This is Part 1)
- **[Part 2](https://abulasar.com/creating-a-real-time-trello-board-with-phoenix-liveview-part-2):** We will build the board, add tasks UI, and integrate the board with the functions (API) we created in Part 1
- **Part 3:** We will be adding real-time behavior to our board (under development)

### Action Plan
- Creating a LiveView project
- Adding User and Task Tables.
- Adding Task and User struct
- Designing the API Layer

Let's start building 👷
### Creating LiveView project
- First of all, our system should have Elixir installed. We can confirm this by running `Elixir -v`.
- Once confirmed we need to create/generate the Phoenix LiveView application.
- This can be done by running `mix phx.new trello_app  --live`
- if you get this error 
```
** (Mix) The task "phx.new" could not be found
Note no mix.exs was found in the current directory
```
Then run  `mix archive.install hex phx_new`
- Then navigate to project directory `cd trello_app` and run `mix phx.server`. Once, the project starts running navigate to localhost:4000 to see the welcome phoenix screen.

### Adding User and Task Tables.
- As per our requirement, we have two entities that need to be created, the `card` and the `user` to which this card belongs. We will call these cards `Task`.
- So, we will add two tables the `User` table and the `Task` table. 
- Let's add migration files for these two Tables.
- For the sake of clarity we will add two separate migration files for these two tables.
- For `User` table run `mix ecto.gen.migration create_user` and for `Task` table run `mix ecto.gen.migration create_task`
- Now open `trello_app/priv/repo/migrations/{{some_time_stamp}}_create_user.exs` migration file at and the add following fields in the migration file.
```
defmodule TrelloApp.Repo.Migrations.CreateUser do
    use Ecto.Migration

    def change do
       create table(:users) do
          add :first_name, :string, null: false
          add :last_name, :string, null: false

          timestamps()
       end
    end
end
```
- Similarly for `task` table open `trello_app/priv/repo/migrations/{{some_time_stamp}}_create_task.exs` migration file and the following fields
```
 defmodule TrelloApp.Repo.Migrations.CreateTask do
     use Ecto.Migration

     def change do
        create table(:tasks) do
           add :title, :string, null: false
           add :description, :text
           add :user_id, references(:users)
           add :state, :string, null: false

           timestamps()
       end
   end
end
```
- Now we will now run the command `mix ecto.migrate`. This will create tables `User` and `Task` in the database.

### Adding Task and User struct
- We have created `User` and `Task` tables now we are going to add `User` and `Task` structs so that we can use `Ecto` queries effectively.
- First, we will add the `Task` struct. For that we will create a file `trello_app/lib/trello_app/organization/task.ex `.
- Add the following code to the file.
```
defmodule TrelloApp.Organization.Task do
    use Ecto.Schema
    import Ecto.Changeset
  
    alias TrelloApp.Organization.{ Task, User }
  
    schema "tasks" do
       field :title, :string
       field :description, :string
       field :state, :string
  
       belongs_to :user, User
  
       timestamps()
    end
  
    def changeset(%Task{} = task, attrs) do
      task
      |> cast(attrs, [:title, :description, :state, :user_id])
    end
end
```
- Similarly, we will add the `User` struct in the same organization directory with a file name `user.ex`.
- We will add a similar code here as well.
```
defmodule TrelloApp.Organization.User do
    use Ecto.Schema
    import Ecto.Changeset

    alias TrelloApp.Organization.{ Task, User }
    schema "users" do
      field :first_name
      field :last_name
  
      has_many :task, Task
      timestamps()
    end
  
    def changeset(%User{} = user, attrs) do
       user
       |> cast(attrs, [:first_name, :last_name])
    end
end
```
- In the above code, both the structs i.e `User` and `Task` has fields defined in the `schema` macro similar to the migration files. 
- We've also defined the relationship between the structs(Tables). It is a `one-to-many` relationship between `User` and `Task` which means `User` can have many `Task`. We've also defined the `changeset` functions for manipulating the data.
- Now, to test if everything is working fine we will add some dummy data in both the tables using the `iex` shell.
- Open the terminal and navigate to the root directory level of the project. Now run the `iex` shell by typing `iex -S mix`.
- Now alias both the structs and `Repo` to avoid typing long struct names.
```
alias TrelloApp.Organization.{ Task, User }
```
- First, we will insert the `User` record for that we will run the following code.
```
  User.changeset(%User{}, %{first_name: "Michael", last_name: "Jordan"}) 
  |> Repo.insert
  
  User.changeset(%User{}, %{first_name: "Andrew", last_name: "Flintoff"}) 
  |> Repo.insert
```
- This will insert two `User's` records with `id` of 1 and 2.
- Similarly, we will add a few `Task` records for both `users` but with different states. For testing purposes, we will add four tasks with the states "planning", "progress", and "completed".
```
  %Task{} 
  |> Task.changeset(%{title: "Designing API", description: "designing api", state: "planning", user_id: 1}) 
  |> Repo.insert
  
  %Task{} 
  |> Task.changeset(%{title: "Take Backup", description: "take backup", state: "progress", user_id: 2}) 
  |> Repo.insert
  
  %Task{} 
  |> Task.changeset(%{title: "Add Migrations", description: "write migrations", state: "progress", user_id: 1}) 
  |> Repo.insert
  
  %Task{} 
  |> Task.changeset(%{title: "Write Script", description: "write script", state: "completed", user_id: 2}) 
  |> Repo.insert
```
- After running the above queries we will have one `User` record and three `Task` records.

### Designing the API Layer
- As per our requirement we only want two functions in our API Layer, which are `get_grouped_tasks` and `change_task_state`.
- #### What `get_grouped_tasks` will do?
- If you remember in the `Task` struct we have a `state` field. We've added three `tasks` records with state `planning`, `progress`, and `completed`.
- We want our tasks should be grouped (as per the `state` mentioned in the task) and placed in the respective `states` column.
![grouped_tasks (1).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661375604438/eFulSAFQG.png align="center")
- In this function, we will have three stages of data transformation
  - *Fetch all tasks*
  - *Preload the owner of the tasks (Just for beautification of the task to mention the owner of the task)*
  - *Grouping the tasks*
- Below is the code of the above pseudo-code.
```
  def get_grouped_tasks() do
    Task
    |> Repo.all()
    |> Repo.preload(:user)
    |> Enum.group_by(fn %{state: state} -> state end)
  end
```
- Our second method will be `change_task_state`.
- #### What `change_task_state` will do?
![add_task (1).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661375619056/7CsOQK3Ex.png align="center")
- When we move our task (say) from `Progress` to `Completed`, we want to change the `state` field of the task from `progress` to `completed`.
- This function will take two parameters `task_id` and `transition_state` i.e the `column` we want our task should be moved.
- In this function, we will have three stages of data transformation
  - *Get `task` by `task_id` parameter*
  - *Change the `state` of the `task` as per provided `transition_state` using `changeset` function in `Task` struct*
  - *Update the `Task`*
- Below is the code of the above pseudo-code.
```
def change_task_state(task_id, transition_state) do
    Task
    |> Repo.get(task_id)
    |> Task.changeset(%{state: transition_state})
    |> Repo.update
end
```
- We are going to place both functions in a separate module `organization.ex` under `trello_app/lib/trello_app` folder.
- This module will be the provider of the two functions, which we will use in the LiveView module later.
```
  defmodule TrelloApp.Organization do
    alias TrelloApp.Repo
    alias TrelloApp.Organization.Task
    
    def get_grouped_tasks() do
      Task
      |> Repo.all()
      |> Repo.preload(:user)
      |> Enum.group_by(fn %{state: state} -> state end)
    end
  
    def change_task_state(task_id, transition_state) do
      Task
      |> Repo.get(task_id)
      |> Task.changeset(%{state: transition_state})
      |> Repo.update
    end
  end
```

### Testing the API Layer in the `iex` shell
- We've created our Task and User structs as well as designed our API Layer. Let's test the API Layer in the iex shell.
- If you remember, we've added a few records of `task` and `user`.
- So, as per our API layer, we have to functions `get_grouped_tasks/0` and `change_task_state/2`. First, we will test `get_grouped_tasks/0`,
- For testing, we will alias the `Organization` module 
  ```
    alias TrelloApp.Organization
  ```
- Now run `Organization.get_grouped_tasks()`, this will return grouped tasks as per their `states`
```
%{
  "planning" => [
      %TrelloApp.Organization.Task{
        __meta__: #Ecto.Schema.Metadata<:loaded, "tasks">,
        description: "designing api",
        id: 2,
        inserted_at: ~N[2022-08-25 09:30:08],
        state: "planning",
        title: "Designing API",
        updated_at: ~N[2022-08-25 09:30:08],
        user: %TrelloApp.Organization.User{
          __meta__: #Ecto.Schema.Metadata<:loaded, "users">,
          first_name: "Michael",
          id: 1,
          inserted_at: ~N[2022-08-25 08:45:25],
          last_name: "holding",
          tasks: #Ecto.Association.NotLoaded<association :tasks is not loaded>,
          updated_at: ~N[2022-08-25 08:45:25]
        },
        user_id: 1
      }
  ],
  "progress" => [
      // two tasks under progress
      %TrelloApp.Organization.Task{ id: 2 },  
      %TrelloApp.Organization.Task{ id: 3 }
   ],
   "completed" => [
      // one task under completed
      %TrelloApp.Organization.Task{id: 4}
   ]
}
```
- We got one task for `planning`, one task for `completed`, and two for `progress`. This is exactly as per the `tasks` we added with different states.
- So far so good, now we will test `change_task_state` for first `task` i.e id=1.
- `change_task_state/2` expects two parameters `task_id` and `transtion_state`.
- We will move our task with `id=1` to the `completed` state. So, we will run ```Organization.change_task_state(1, 'completed')``` in our shell.
- This will transition our task of `id=1` to the `completed` column. We can test this by again running the `get_grouped_task`. It will not return the `planning` group since there is no task left with the `planning` state.

This completes the first blog of this series. In the next part as per our planning, we will build the board, add tasks UI along with drag and drop functionality and will integrate the board with our API layer. I hope you like this blog. If you have any questions then please comment below. Thanks for reading 😊. 

### References
- [Github Repo](https://github.com/abulsayyad123/trello-board-liveview)

