This document will outline the requirements of your next project. You’re going to build a simple To-do app with Vue.js that allows users to create an account, record tasks, edit them and mark them as complete. The app will be linked to a database, where all the user and task data will be stored. The database that we’ll use for this project is Supabase. We’ll also be using Vite as a build tool to compile our code and provide a development server while we work.
In the following lessons, you will find introductory notes on databases.
You’ll need to use the CSS skills you’ve learned earlier in the course to style your app. You can pick any UI library to work with such as Bootstrap, Vue Element Plus, Vuetify, or write your own styles for bonus points.
At the end of this project you will be able to:
- Use Vue.js to create an app
- Connect a Vue.js app to Supabase (Database as a Service)
- Have a repo on GitHub
- Commit your work at least once a day during the project development time
- Your app should be rendered in a browser
- Your app should be deployed online using a cloud service such as Netlify
- Stick with KISS (Keep It Simple, Stupid) and DRY (Don’t Repeat Yourself) principles.
- Your app should be styled using CSS
- Your app should be fully integrated with a Supabase database using all CRUD operations
- You should use Vue’s Pinia to fully implement status handling
- You should handle any asynchronous operations using Promises or Async/await
- You should document the application’s features, configuration and technical specifications within a README file
The functionality should include:
- Authentication (sign up, sign in, sign out)
- A front-end that displays the user’s personal to-do list
- An ability to add new tasks
- An ability to edit existing tasks
- An ability to mark tasks as complete/incomplete
- An ability to delete existing tasks
- A store and a database that your app can call data from
User stories allow us to build a simple narrative around business logic using a syntax called Gherkin. We use keywords such as given
, when
, then
, and
and but
, in addition to a few others. You can find a full list of keywords within the Gherkin documentation.
Gherkin is the best way to clarify business logic and user interactions whilst also maintaining a human-readable set of specifications.
This strategy is referred to as Behavior-Driven Development (BDD) and it will form the basis of this specification. We’ll consider our user stories throughout the development process. In the bonus section, you can test your code against them during the quality assurance (QA) stage of the project.
Here are the user stories you’ll need to consider to ensure that the app functions as required for this project:
Feature: Create an account
Background: As a new user, I want to register with the to-do app
Given I do not have an account
Scenario: As a user, I want to create an account
When I visit the signup page
And I set the email to "[email protected]"
And I set a password to "****"
And I set confirmPassword to "****"
And I click the register button
Then I expect to be shown a warning that instructs me to confirm my email address by clicking a link in an email
And I click the link provided in the email
Then I expect to be logged in to the app
And I expect to see the home screen
Feature: Log in to the app
Background: As a user, I want to log in to the to-do app
Given I already have an account
Scenario: As a user, I want to log in to the app
When I visit the login page
And I enter my email as "[email protected]"
And I enter my password as "****"
And I click the Log In button
Then I expect to be logged in to the app
And I expect to see the home screen
Feature: Log out from the app
Background: As a user, I want to be able to log out from the app
Given I am logged in to the app
Scenario: As a user, I want to log out
When I am viewing the home screen
And I click the log out button
Then I expect to be logged out of the app
And I expect to see the login page
Feature: Add a new task
Background: As a logged in user, I want to add a new task and have it appear on my to-do list
Given I am logged in
Scenario: As a logged-in user I want to create a new task
When I visit the home screen
And I enter "My cool task" in the NewTask field
And I click the submit button
Then I expect to see "My cool task" in the To-Do list of tasks
Feature: Edit a task
Background: As a logged in user, I want to edit an existing task and have the app display the updated content
Given I have already created a task
Scenario: As a user, I want to edit the title of my task
When I locate the task I'd like to edit
And I click the corresponding Edit button to the task
Then I expect the title of the task to become editable
When I enter a new description for the task
And I click submit
Then I expect to see my updated task on the To-Do list
Feature: Mark a task as complete
Background: As a logged in user, I want to be able to mark a task as complete and automatically move it to the completed section
Given I have already created a task
Scenario: As a logged-in user I want to mark a task as complete
When I locate the task I'd like to mark as complete
And I click the corresponding done button to the task
Then I expect to see that my task has immediately been moved to the completed section
Feature: Mark a task as incomplete
Background: As a logged in user, I want to be able to mark a task as incomplete and automatically move it back to the to-do section
Given I have already created a task and marked it as complete
Scenario: As a logged-in user I want to mark a task as incomplete
When I locate the task I'd like to mark it as incomplete
And I click the corresponding incomplete button to the task
Then I expect to see that my task has immediately been moved to the to-do section
Feature: Delete a task
Background: As a logged in user, I want to be able to permanently delete an existing task
Given I have already created a task
Scenario: As a logged-in user I want to delete a task
When I locate the task I'd like to delete
And I click the corresponding delete button to the task
Then I expect to see that my task has been permanently removed from every list
- Client: Vue.js, Vite (dev server)
- Router: Vue Router
- Store: Pinia and Pinia Persist for persistent login
- Database as a service: Supabase
VSCode + Volar (and disable Vetur) + TypeScript Vue Plugin (Volar).
See Vite Configuration Reference.
npm install
npm run dev
npm run build
Lint with ESLint
npm run lint
Basic setup for Vue.js and Supabase:
$ npm vite create "my-todo-project"
$ cd my-todo-project
$ npm add @supabase/supabase-js
$ npm add pinia
$ npm add vue-router
$ npm add pinia-plugin-persist
Vue Router
- You will need to set up a route for
Dashboard
andAuth
Pinia (for our store)
- You will need to set up two user stores:
user.js
andtask.js
- Create a sign up/sign in screen that will be displayed when the user is not logged in
- Ensure that the signup form requests an email address, password and password confirmation from the user
- Ensure that the sign in form requests an email and a password from the user
- Create a page where after logging in, the user is shown the main app content
- The app should fetch all tasks from the logged-in user’s task list stored in Supabase
Below we’ve prepared a suggested file structure for the codebase. Vite will automatically generate the files when you’ve created the project. You will need to create the components
folder and the pages
folder.
The
/pages
directory name is a choice for the developer. In other codebases, you may see it referred to as views.
Suggested file structure for the codebase (click to see)
├── src
│ ├── App.vue
│ ├── assets
│ │ └── logo.png
│ ├── components
│ │ ├── AppHeader.vue
│ │ ├── Nav.vue
│ │ ├── NewTask.vue
│ │ ├── SignIn.vue
│ │ ├── SignUp.vue
│ │ └── TaskItem.vue
│ ├── main.js
│ ├── pages
│ │ ├── Auth.vue
│ │ └── Dashboard.vue
│ ├── router
│ │ └── index.js
│ ├── static
│ │ └── main.css
│ ├── store
│ │ ├── task.js
│ │ └── user.js
│ └── supabase.js
├── vite.config.js
└── yarn.lock
We’ve provided some starter templates for you to use. You’ll need to expand upon these to build the application.
Here is a basic user
store. We’ve only given you two actions: fetchUser
and signUp
. You’ll need to create signIn
and signOut
.
// /store/user.js
import { defineStore } from "pinia";
import { supabase } from "../supabase";
export const useUserStore = defineStore("user", {
state: () => ({
user: null,
}),
actions: {
async fetchUser() {
const user = await supabase.auth.user();
this.user = user;
},
async signUp(email, password) {
const { user, error } = await supabase.auth.signUp({
email: email,
password: password,
});
if (error) throw error;
if (user) this.user = user;
},
},
persist: {
enabled: true,
strategies: [
{
key: "user",
storage: localStorage,
},
],
},
});
Here is a basic task
store. We’ve only given you one action: fetchTasks
. You’ll need to create your own store actions to update, create and delete the tasks.
// /store/task.js
import { defineStore } from 'pinia';
import { supabase } from '../supabase';
export const useTaskStore = defineStore('tasks', {
state: () => ({
tasks: null
}),
actions: {
async fetchTasks () {
const { data: tasks } = await supabase
.from('tasks')
.select('*')
.order('id', { ascending: false });
this.tasks = tasks;
}
}
});
Instead of checking authentication on router change. We’ll be checking it at the root level of the app. This means that the user request is only fired once and not on every page load. Different (especially larger) apps may need a different strategy when dealing with authentication. We’ve provided you with a basic App.vue
that nests the other pages inside.
<template>
<section>
<router-view class="app-main" /> <!-- your routes will load inside of these tags -->
</section>
</template>
<script setup>
import { onMounted } from 'vue'
import { storeToRefs } from 'pinia'
import { useRouter } from 'vue-router'
import { useUserStore } from './stores/user.js'
const router = useRouter()
const userStore = useUserStore()
const { user } = storeToRefs(userStore)
onMounted(async () => {
try {
await userStore.fetchUser() // here we call fetch user
if (!user.value) {
// redirect them to logout if the user is not there
router.push({ path: '/auth' });
} else {
// continue to dashboard
router.push({ path: '/' });
}
} catch (e) {
console.log(e)
}
})
</script>
It’s always important to consider the way in which you write your code. We suggest you add eslint
along with eslint-plugin-vue
to your codebase to automatically check and lint your code. You can find more detailed instructions on how to do this here.
We also suggest you follow the following principles when dealing with your store:
- Only update the state from actions
- After changing data via an action run
this.fetchTasks()
orthis.fetchUser()
inside of that same action. This ensures that the state is always updated the same way because we fetch the data again from the API after manipulating it with a singlefetchSomething()
action. - Use getters to select the data when applying it to the template. You’ll need to use
storeToRefs
- for more info take a look at these Pinia docs - When accessing the value of a variable with Vue 3 you’ll need to use
.value
. For example,let loading = ref(true);
then to update that value you’ll needloading.value
- Supabase requires users to confirm their email addresses. This can be turned off. However, we want you to handle the error from supabase and present it to the user so that when their email is not confirmed it states "email not confirmed " in the error.
Check the following lesson in the lesson plan to learn more about Databases and SQL.
Check the following lesson in the lesson plan to learn how to setup and use Supabase.
We’ve not defined a user interface or a design that we want you to use, so use your CSS skills and get creative. Because we’re using Vue, we can make it a single page that includes components for the new task input, task list items and headers, etc.
You’re welcome to apply your own design and layout. You can pick any UI library to work with such as Bootstrap, Vue Element Plus, Vuetify, or write your own styles.
You will be expected to demo this application. We’ve provided some tips and expectations below:
Your presentation demo is expected to last 5-10 mins.
- Plan what you are going to demo and practice it on the live site. That way you won’t be surprised if something breaks on the live version.
- Deploy early so you can squash bugs. There are always bugs on the live site at first.
- Add a link to your live project to your DEMO slide so you can start it smoothly.
- Technical Challenge a. What was the most important technical challenge you faced? b. How did you overcome that challenge?
- Big Mistake a. What was the biggest mistake you made during this project? b. What did you learn from it?
- Technical Requirements: Did you deliver a project that met all the technical requirements?
- Creativity: Did you add a personal spin or creative element to your project submission? Did you deliver something engaging and playable to the end user?
- Code Quality: Did you follow code style guidance and best practices covered in class, such as spacing, modularity and semantic naming?
- Deployment: Did you deploy your application to a public URL using GitHub Pages?
- Total: Your instructors will give you a total score on your project (check the table below for more insights)
Expectations | Score |
---|---|
Your app hasn’t been built to the desired standard or uses unsafe practices. If you received this grade, you’d be asked to resubmit your work, or a fail grade would be given. | 0 |
Your app has reached the basic standards and is capable of limited safe practice. Your work is rule-based with limited or no translation and interpretation of concepts, skills and procedures and limited adaptations to meet situational factors unless aided. If you meet these standards, your work should attract a passing grade! | 1 |
Your app has completely reached the standards expected. It can function independently in novel contexts, adapting concepts, skills and procedures to meet situational factors. This level would show that you can demonstrate an appreciation of your own limitations and can set personal learning goals. If you meet these standards, you would attract a credit grade! | 2 |
You’ve gone beyond the basic expected standards when creating your app! You have exhibited a high level of independence and can use principles to generate new understandings and ways of completing procedures and can provide theoretically defensible arguments for their new interpretations and adaptations. Your work is of professional-level quality and can engage in productive critical reflection. If you meet these standards, you’re a superstar and could attract a distinction or high distinction grade! | 3 |
In order to assess your final project and ensure all requirements are met, a rubric will be used. This rubric is used to evaluate your project by your teaching staff but also to communicate what constitutes incomplete, acceptable and excellent performance across each of the learning outcomes for the final project. Take some time to review the rubric and ask your lead teacher any questions about it if necessary.
Learning outcomes | Domains | 0 - Incomplete | 1 - Fair | 2 - Good | 3 - Excellent |
---|---|---|---|---|---|
Implement all CRUD operations | Databases, Software Architecture | Student showed no evidence of creating a database or created only one database. Student managed to implement only basic CRUD actions (GET & POST). | Student created 2 databases as expected. Student partially completed CRUD functionality with at most three out of four CRUD actions available. | Student created 2 databases as expected. All CRUD actions are set up. All databases have well-defined schemas and partially implemented validation. All of the CRUD actions are tested with an API Testing tool (Postman, Insomnia, or similar). | Student created 2 databases as expected. All CRUD actions are set up. Student has found a way to enhance the user’s experience by implementing all or some of the CRUD actions more than once in the app. All databases have robust schemas with well-defined data types and validation. All of the CRUD actions are tested with an API Testing tool. |
Create and integrate the client-side Vue application with the Supabase DB | Front-end Applications, Client-side development, Databases | Student failed to create a simple SPA and implement the basic integration with the Supabase DB. Integration with the Supabase DB is either absent or limited to the GET endpoint. | Student developed a SPA with limited integration with the Supabase DB. Student implemented multiple views and the basic routing allowing the user to navigate between the views. Student implemented stateful components that fetch, store and display the data from the Supabase DB. Student created a component that sends form data to a Supabase DB and creates resources in the database. Student used props to establish a one-way data flow between the child and parent components (pass data down). The frontend UI is contained within larger components. | Student adequately developed a SPA that is fully integrated with the Supabase DB. Student created components that integrate all CRUD actions. Student implemented dynamic SPA routing to display components with specific content in addition to the basic routing. Student successfully used props to establish the two-way data flow between the components (pass data/functions down, pass actions up). Student took the effort to break down some parts of the UI into smaller, reusable components. | Student successfully developed a well-structured SPA that is fully integrated with the Supabase DB. Student created components that perform all CRUD actions. Student implemented dynamic SPA routing to display components with specific content in addition to the basic routing. Student successfully used props to establish the two-way data flow between the components (data/functions down, actions up). Student developed a maintainable app with the UI made up of smaller, reusable components. |
Implement status handling | Databases, State Framework | Student did not implement Pinia as a state management library or it was a wrong implementation. | Student has applied only one of the two stores (user or tasks). Student created a store and used it to control the state of the components/pages with only minor bugs. | The two proposed stores have been used. Student has implemented both stores to manage all the states given with either no bugs or minor bugs. | The student successfully implemented the two store managers and integrated this with all features and the Composition API. The student has used getters to select the data when applying it from the template. All of the states given are successfully managed with no bugs. |
Implement Authentication and Authorization | Databases, Client-side development | Student didn’t implement the authentication and authorization. | Student implemented the basic authentication and authorization. Student implemented sign-up, log-in and log-out, despite some minor bugs. Student partially secured the routes, with some pages being unprotected or unnecessarily protected. | Student adequately implemented the authentication and authorization. Student implemented sign-up, log-in and log-out features that are stable and bug-free. Student secured all SPA routes well, providing access to the parts of the application based on the authentication status. | Student successfully implemented the authentication and authorization. Student implemented sign-up, log-in and log-out features that are stable and bug-free. Student secured all SPA routes well, providing access to the parts of the application based on the authentication status. In addition, student incorporated a role-based authorization or social login. |
Handle asynchronous operations using Promises or Async/await | Intermediate JavaScript, Advanced JavaScript | Student does not appear to possess a basic understanding of the promises and callback handling. The handling of the existing promises in the code is incomplete or non-functional. | Student handled resolved promises appropriately. Student only partially implemented or missed implementing catch blocks for some promises. Student had difficulty chaining promises together. | Student adequately handled all resolved and rejected promises and appropriately chained promises to execute asynchronous tasks in sequence. Nearly all promises have catch blocks with adequate error handling. | Student successfully handled all resolved and rejected promises and appropriately chained promises to execute asynchronous tasks in sequence. All promises have catch blocks with adequate error handling. Student successfully used advanced promise methods to coordinate the execution of multiple asynchronous operations. |
Style the application’s UI using CSS or a CSS Framework | Client-side development | Student used basic layouts without CSS styles or branding. | Student partially styled the application using CSS and simple branding. | Student adequately styled the whole application using CSS or a CSS framework. Student made an obvious effort to create a pleasant and appealing user interface and maintain consistent application branding. | Student adequately styled the whole application using CSS or a CSS framework. Student made an obvious effort to create a pleasant and appealing user interface and maintain consistent application branding. Student implemented a fully responsive layout. |
Write clean, modular, and efficient code following best practices | Code Quality | Student has not followed best practices in writing clean, modular and efficient code. Student has unused code in the project and functions that are considered too large or perform multiple tasks. Student has not followed a consistent approach in naming structure and organization of the files/folder. Student has not applied indentation conventions making the code hard to read. | Student has named files and folders for the backend and frontend logically and has organized them clearly and consistently. Student has partially applied indentation conventions to the source code and has mostly named functions and variables logically. Some unused code is within the projects. | Student has adequately named files and folders for the backend and frontend and has organized them clearly and consistently. Student has also applied indentation conventions to the source code and has named functions and variables logically. Student used destructuring to extract values from objects and arrays to enhance code readability. There is no unused code within the project and utility functions are contained in separate self-descriptive files. | Student has adequately named all files and folders for the backend and frontend and has organized them clearly and consistently. Student has applied indentation conventions to the source code and was meticulous in commenting the code. Student has named functions and variables logically following the industry conventions. There is no unused code within the project and utility functions are contained in separate self-descriptive files. Student used destructuring, rest parameters and/or other ES+ features to enhance code readability. Student abstracted part of the application login into services. |
Deploy a functioning app to a Cloud service | Client-side development | Student failed to deploy an application to a predefined Cloud service. The application can’t be accessed through the publicly available URL and/or the error message is shown. | Student deployed an application to a Cloud service but some of the application features not working. Some parts of the application UI can be accessed through the publicly available URL however some functionalities are not available or result in an error message being shown. | Student deployed an application to a Cloud service, with the app being fully operational. Some parts of the application UI can be accessed through the publicly available URL however some functionalities are not fully operational or have minor bugs. | Student successfully deployed an application to a Cloud service, with the app being fully operational. All parts of the application UI are accessible through the publicly available URL. The deployed application is fully operational and new deployments don’t cause interruptions. |
Save and track changes in the source code using Git and GitHub | Version Control | Student did not create a repository for an app or has less than one commit per day. | Student created a repository for the app and is making at least one commit per day. However, commits made have unclear and ambiguous messages and student has not used separate branches for development and deployment. | Student created a repository for the app and is making two or more commits per day. Student has used separate branches for development and deployment with clear and descriptive commit messages. | Student created a repository for the app and is making two or more commits per day. Student used atomic commits to clearly state every change made, with accurate and precise descriptions. Student used separate branches for development and deployment and additional branches for working on the features. |
Document the application’s features, configuration and technical specifications | Career development | Student did not make any attempt to document the project’s specifications. | Student provided a partially completed project README. Student has only partially documented application’s features, configuration or specifications in the README file. | Student has created a well-structured and clear README file that covers all of the application’s features, configuration and specifications. The student has included credits, clearly listing any collaborators, team members and resources used that contributed to the project. | Student has created a fully comprehensive and well-structured README file that not only clearly communicates the application’s features, configuration and specifications but goes into further detail justifying the choice for inclusion in the application. Student has added a license to the file and included credits, clearly listing any collaborators, team members and resources used that contributed to the project as well as badges. |
Practice communication, critical thinking, professionalism and teamwork skills | Career development | Student did not make time or effort to communicate with others during standups or other activities. Student depended on others (teammates or teaching staff) to do the heavy thinking and most of the work. Student did not make the effort to assist others or collaborate in any way. | Student communicated at times with others during standups but could be more clear and concise in their delivery. Student remained in their comfort zone by excluding themselves from conversations that would require teamwork skills and idea exchange during the development of the project. | Student demonstrated clear communication skills and attended all standups. Student adhered to a level of professionalism by acting emotionally mature and engaged in teamwork skills by listening to others’ ideas while contributing their own. | Student impressively demonstrated clear communication skills during standups and contributed to group discussions, going out of their way to help other students in the group. Student adhered to a level of professionalism by acting emotionally mature and engaged in teamwork skills by listening to others’ ideas while contributing their own. |
Build a presentation and perform a demo to deliver your final results, or the results of your group | Career development | Student did not present or demo their application or talk through their slides during the project presentations. | Student presented and demoed their work but struggled with the timing and the rhythm of the presentation. Student had to skip or rush through certain slides to keep up with the time. Student struggled to deliver a clear message, leaving the audience confused. | Student presented their work effectively. The presentation and demo appeared prepared and structured, conveying a clear message to the audience. Student used the allocated time effectively. | Student presented their work impressively. The presentation and demo appeared very well prepared and structured, conveying a clear message to the audience. Student used the allocated time effectively. Student’s tone and storytelling were well aligned with the subject of the project. Student kept the audience in awe for the duration of the presentation and demo. |