Your mission, should you choose to accept it, is to build a simplified Trello clone.
Trello is a simple task management tool with three components: boards, lists and cards. Each board has multiple lists, each list has multiple cards, and cards have names. Here's what Trello looks like.
In this exercise, we'll be building a single Trello-like board.
Don't try to do all of these tasks at once. Tackle them one at a time and move on once you've completed task. It's OK if you don't complete all tasks, we give partial credit ✅.
Your solutions should store and read data from the server. API endpoints listed below may be helpful for this. You can render your interface on the client or on the server.
The app currently has no styling; it's up to you to add style and interactivity to it as you go through these tasks. Be creative!
- View lists, create new list [frontend]
Allow users to view and create lists. Lists should be displayed as vertical columns in a Trello-like manner.
See:GET /api/lists
andPOST /api/lists
. - Fix
POST /api/list/:id
endpoint [backend]
There's a bug 🪲 in the API endpoint for updatingList
s inapp.js
. Find it and fix it. - Create new card in a list [frontend]
Allow users to create new cards in existing lists.
See:POST /api/lists/:id
. - Rename list [frontend]
Allow users to rename existing lists.
See:POST /api/lists/:id
. - Change card contents [frontend]
Allow users to change the contents of cards.
See:POST /api/lists/:id
. - Delete card [frontend]
Allow users to delete single cards.
See:POST /api/lists/:id
. - Move cards [frontend]
Allow users to move cards within and between lists.
See:POST /api/lists/:id
. - Reorder lists [frontend]
Allow users to reorder whole lists. You can use drag-and-drop or buttons.
See:POST /api/lists/:id
. - Implement
DELETE /api/lists/:id
[backend]
Create a new Express endpoint that takes aDELETE
request and anid
and deletes a single list. This endpoint should return400 Bad Request
if list withid
can't be found.
See: functionstorage.del(kind, id)
instorage.js
- Delete list [frontend]
Allow users to delete whole lists.
See:DELETE /api/lists/:id
.
Legend:
- [frontend]: Task involves work in the browser with HTML, CSS and JavaScript.
- [backend]: Task involves work in the server with Node and Express
We recommend that you don't publicly fork this repository.
-
Make sure all your changes are committed to
git
.$ git status On branch master nothing to commit, working directory clean
-
Create a zip archive of your project.
$ git archive master --format zip -o "horizonello-[YOUR NAME].zip"
-
Email us
horizonello-[YOUR NAME].zip
.
You work will be evaluated based on the following criteria (in decreasing order of importance):
- Correctness (most important): The features you implement work correctly. There are no errors in the console. It's not easy to make your code break.
- Completeness: Every feature is implemented.
- Visual styling and ease of use (least important): The user interface is easy to use and looks good.
❗ Important: Your app MUST start successfully with
npm install && npm start
command.
We will be using this command to start and test your app. ❗
Feel free to add any dependencies or 3rd party libraries to this project. You can also modify any files in this project.
To run the project, clone this repository and open it up in your terminal and run:
npm install && npm start
You should see:
BLAH BLAH BLAH
> horizonello@0.0.1 start /Users/user/horizonello
> node app.js
Initializing storage...
Done initializing storage. Read 0 entities.
Express started on port 3000
You can now visit localhost:3000 to see your app.
To delete all List
data run: npm run clean
We represent our Trello-like board using a single entity: List
s. Our board
has cards too but every card lives under a list
. You can't create a card
without a list.
List
s have the following properties:
id
(integer) (required): Provided by the storage layer. Uniquely identifies eachlist
.name
(string) (required): Name of thelist
.pos
(integer) (required): Position of the list on the board. Lists should be displayed in increasingpos
order from left to right. Sopos
0 is the leftmost list.cards
(array of strings) (optional): Each string in this array represents a card on the list. These cards should be displayed in top to bottom order. In other words, first card in this array should be the topmost card in the current list.
Example valid List
:
{
"id": 0,
"name": "List name",
"pos": 0,
"cards": ["Card 1", "Card 2"]
}
On the backend, we've set up Express with express-handlebars
for templates for you. The index page lives in views/index.handlebars
.
The boilerplate and header footer code lives in views/layouts/main.handlebars
.
The main Express JavaScript file is app.js
. You can find the route definitions here.
storage.js
contains code for reading and storing persisted data.
Client-side assets are in the static/
folder. CSS styles are in
static/css/styles.css
. Client-side JavaScript is in
static/js/script.js
; you will find example code for
interacting with API endpoints here. styles.css
and script.js
are included
in every page.
Your solution should use Node.js and Express but otherwise feel free to change anything else in this project.
You can use these endpoints to read and update data from the server in the browser.
For endpoints that take POST
requests request parameters must be passed
through the request body (i.e. not the URL). You can use regular jQuery AJAX
request serialization (i.e. form-encoded) or JSON.
- Method:
GET
- Path:
/api/list
- Response codes and contents
-
200: Success. Response will contain an object with a single key
rows
, alllist
objects are returned under this.{ "rows": [{"name": "List name", "pos": 1, "cards": ["Card 1"]}] }
-
- Method:
GET
- Path:
/api/list/:id
- Response codes and contents
-
200: Success. Response will contain list.
{ "name": "List name", "pos": 1, "cards": ["Card 1"] }
-
404: Not found. If no
list
with id is found.
-
- Method:
POST
- Path:
/api/list
- Request parameters: All request parameters are expected to be passed in through the request body (i.e. not the URL).
- name (required): name of the list
- pos (required): number representing the position of this list on the screen.
pos
counts up left-to-right. - cards (optional): array of strings representing cards under the current list.
- Responses:
- 200: Success. Response will be the
list
object that was just created. - 400: Invalid request. Missing required fields or bad field values. Check the logs.
- 200: Success. Response will be the
Note: There's a bug 🪲 in this endpoint. One of your tasks is to find it and fix it.
- Method:
POST
- Path:
/api/list/:id
- id (required): id of the list to update
- Request parameters: All request parameters are expected to be passed in through the request body (i.e. not the URL).
- name (required): name of the list
- pos (required): number representing the position of this list on the screen.
pos
counts up left-to-right. - cards (optional): array of strings representing cards under the current list.
- Responses:
- 200: Success. Response will be the
list
object that was just created. - 400: Invalid request. Missing required fields or bad field values. Check the logs.
- 200: Success. Response will be the