Building a Realtime Trello Board with Supabase and Angular

Building a Realtime Trello Board with Supabase and Angular

Trello Board Clone with Superbase

Introduction to the Tutorial

  • The tutorial focuses on building an Angular application that replicates a Trello board, sponsored by Superbase, which is highlighted as an open-source alternative to Firebase.
  • Superbase utilizes SQL databases instead of NoSQL, offering functionalities like database management, authentication, cloud storage, edge functions, and real-time capabilities.

Application Features

  • The application will include features such as magic link sign-in, adding boards and lists, creating cards within those lists, user collaboration on boards, and real-time updates.
  • Emphasis is placed on following along with the tutorial and utilizing source code snippets for better understanding; Tailwind CSS will be used for styling.

Setting Up Superbase

  • Users can quickly set up a cloud backend using Superbase without needing extensive backend skills. It’s suitable for various frameworks including Angular and React.
  • Signing up for Superbase can be done via GitHub; users are encouraged to create a new project called "Trello" under a free pricing plan.

Authentication Configuration

  • The tutorial begins with configuring authentication settings in the Angular app using magic link sign-in for ease of use.
  • Changes made include disabling email confirmation during sign-up to streamline the process.

Database Structure

  • Five tables will be created: users (to track registered users), boards (the main domain), lists (within each board), cards (within each list), and a table linking users to boards for authentication rules.
  • SQL snippets will be utilized throughout the coding process to efficiently build out these tables without excessive live coding time.

Table Creation Details

  • The creation of tables involves referencing internal authentication tables from Superbase while ensuring proper cascading deletions when related entities are removed.

Getting Started with User Boards and Security Policies

Function Definition for User Boards

  • A function named get boards for authenticated user is introduced, which retrieves board IDs associated with the current user's ID.
  • This functionality allows easy verification of which boards a user belongs to, crucial for implementing security rules.

Database Setup and Table Management

  • The speaker discusses altering the replica to retrieve full objects from cards in real-time, even if deleted.
  • Emphasis on creating tables rather than dropping them; all table definitions should be visible in the table editor.

Enabling Row Level Security (RLS)

  • The importance of enabling Row Level Security (RLS) is highlighted to ensure data security on the backend using Supabase.
  • RLS can be enabled through SQL commands or manually via UI, allowing for various policies related to insert, select, update, or delete operations.

Policy Definitions and User Access

  • Policies are defined so that users can only view their own boards based on IDs returned by the previously defined function.
  • Similar policies are established for user boards and cards, ensuring only authorized users can edit content related to their boards.

Triggers for Board Management

  • Two triggers are created: one (handle board edit) executes after a new board is added to manage user-board relationships effectively.
  • The second trigger runs when a new user is created (handle new user), adding necessary data into a custom users table since direct access to Supabase's internal users table isn't available.

Finalizing Database Configuration

Successful Implementation of SQL Code

  • All SQL code executed successfully without issues; RLS is now enabled across all tables with implemented rules.

Transitioning to Angular Project Development

Setting Up Angular Project Structure

  • An Angular project named "trailer board" has been initiated with routing configured and SCSS chosen as the styling method.
  • Three components are generated: login page, workspace displaying boards, and an actual board page where core functionalities will occur.

Service Separation and Package Installation

  • Two services will be created—one for authentication logic and another for data logic—to maintain clean separation of concerns within the application architecture.

Setting Up Angular with ngx-spinner and Tailwind

Importing Necessary Modules

  • The speaker discusses the need to import the grav module and ngx-spinner module into the application.
  • Mentions the requirement of the BrowserAnimationsModule, which is essential for animations in Angular applications.

Running the Application

  • The command ng serve -o is used to open a preview of the application, but an issue arises due to a port conflict from a previous run.
  • A change is needed in the Angular JSON file to include configurations for ngx-spinner.

Configuring Routing

  • The routing setup includes defining routes for different components: locking component for blank paths, workspace component, and wildcard routes with IDs.
  • After saving changes, only minimal content remains in the app component as Angular defaults render everything there.

Environment Configuration

  • To connect to Supabase, two keys (URL and anonymous key) must be added to the environment file. These can be obtained from Supabase's settings page.
  • Emphasizes that while using these keys in production is possible, they should be handled carefully due to security implications.

Integrating Tailwind CSS

  • The speaker expresses enthusiasm for integrating Tailwind CSS into their project by installing necessary packages via npm.
  • Instructions are provided on generating a Tailwind configuration file and modifying it to include content paths and plugins.

Finalizing Application Setup

Applying Tailwind Styles

  • To utilize Tailwind styles effectively, base components utilities must be included in SCSS files.
  • A test is conducted by applying Tailwind classes to an H1 element, confirming successful integration of Tailwind styling.

Preparing for Functionality Implementation

  • With foundational elements established (styling, routing), attention shifts towards implementing core functionalities like authentication services.

Setting Up Authentication with Supabase

Creating Authentication Service

  • The process begins with setting up an authentication service that connects to Supabase using its client library.

Establishing Connection

  • The connection involves calling createClient within the constructor using URL and key from environment variables. This object will facilitate API calls moving forward.

Adding State Change Listener

Understanding User Authentication in TypeScript

Handling Sign-In Events

  • The discussion begins with the importance of handling different sign-in events using TypeScript, which provides better code completion and clarity.
  • A function named signInWithEmail is introduced, requiring an email as a parameter. Future updates may change its name to signInWithOTP.
  • The speaker emphasizes the need to implement a logout functionality, noting confusion between terms like "sign out" and "logout" across different packages.

Managing User State

  • The concept of tracking user state is discussed, introducing a behavior subject initialized to null. This allows for dynamic user state management.
  • The behavior subject can hold various states (null, Boolean, or user object), crucial for determining if a user is signed in or not when the application loads.

Implementing User Checks

  • A fallback mechanism is proposed due to inconsistencies with the SDK's onAuthStateChange event; this ensures that user information is checked at application startup.
  • Future versions will include a promise-based method called getUser, enhancing how user data is retrieved and managed.

Emitting User States

  • When checking for users, if found, their information will be emitted to the behavior subject; otherwise, it will be set to false indicating no authenticated access.
  • In cases where users are signed in or not signed in, appropriate values are assigned based on session data or lack thereof.

Navigation and Access Control

  • Angular router integration is suggested for redirecting users back to the login page upon sign-out or failed authentication attempts.

Building the Login Page

Capturing Email Input

  • Transitioning to the login page design involves capturing an email input from users while displaying notifications about email verification status.

Integrating Services

  • Necessary imports include authentication services and spinner services for loading indicators during sign-in processes.

Simplifying Sign-In Logic

  • The sign-in function leverages previously established service methods; it shows a spinner while processing and checks results post-authentication attempt.

Error Handling and Feedback

  • If errors occur during sign-in attempts, alerts are displayed. There’s also consideration of implementing button click events versus direct function calls for improved UX.

Testing Functionality

Magic Link Sign-Up Implementation

Overview of Magic Link Sign-Up

  • The magic link sign-up feature can be implemented with just one line of code, showcasing its simplicity and effectiveness.
  • A flex layout is utilized for the UI, indicating a structured approach to design. An error message about "can't bind to NG model" suggests that the forms module has not been added yet.

User Interaction and Email Verification

  • The function send magic link sends an email containing a verification link, which triggers a spinner component during processing.
  • Upon receiving the email, users can follow the link to complete their sign-up process. The HTML structure is straightforward, primarily using Tailwind CSS for styling.

Session Management and User Authentication

  • After clicking the magic link, an event indicating successful sign-in occurs, along with a session object being stored for user management.
  • Manual retrieval of user objects is necessary at this stage since automatic updates may not occur consistently.

Routing Users Based on Authentication Status

Automatic Redirection Post Sign-In

  • In the constructor of the login component, subscribing to the current user observable allows automatic redirection to the workspace if authenticated.
  • This routing logic prevents users from remaining on the login page unnecessarily after authentication.

Handling Logout Functionality

  • A logout function is introduced in the workspace page that removes user sessions upon clicking a button.
  • Despite logging out successfully, users still have access to protected pages due to insufficient front-end security measures.

Implementing Route Guards for Security

Creating Route Guards

  • To enhance security on internal pages, Angular route guards are generated using ng generate guard, implementing CanActivate interface.
  • Initial implementation returns true by default; thus additional logic is required to restrict access based on authentication status.

Logic for Access Control

  • The guard will utilize observables from the authentication service to determine if a user is authenticated before granting access.

Authentication and Data Management in Superbase

Initial Setup and Filtering Null Values

  • The speaker discusses the initial value of a behavior subject, noting that if it is null, it should be filtered out to avoid issues.
  • A filter will be added to exclude null values, along with a take one block to ensure observables complete properly.

User Authentication Flow

  • If the user is authenticated, access is granted; otherwise, they are routed to the landing page using a URL tree.
  • The speaker demonstrates being redirected due to unauthenticated status but successfully logs back in using a magic link.

Transitioning from Authentication to Workspace Logic

  • With authentication completed, the focus shifts to implementing workspace logic and creating boards within the Superbase project.
  • The next step involves setting up a data service for managing board data.

Board Creation Functionality

  • A function named startBoard will be created to add new boards using Superbase's insert functionality.
  • It’s recommended to store table names as constants for ease of use and error prevention during coding.

SQL Integration and Default Values

  • When inserting into the boards table, default values such as timestamps and titles (e.g., "Untitled board") are automatically handled by SQL.
  • An entry in the user boards table is created automatically when adding a new board.

Implementing Get Boards Functionality

  • In addition to starting boards, there will also be an implementation for retrieving existing boards from the user boards table.
  • The getBoards function will select data rather than insert it, ensuring that all relevant information is retrieved correctly.

Managing State in Workspace Component

  • Variables for tracking both boards and users will be established within the workspace component for display purposes.
  • During initialization (onInit), loading of board data occurs while logging actions for debugging purposes.

User Interface Enhancements

  • A header bar featuring logout functionality and user avatar based on email is implemented using ngx gravatar package.

Understanding Row Level Security in Supabase

Encountering Row Level Security Issues

  • The speaker discusses an error encountered when trying to create a new board, indicating that the row level security policy for the boards table is violated.
  • The issue arises from the default selection rules in Supabase, which only allow selecting a board if it exists in the user boards table.
  • A timing problem occurs where an entry is created in the boards table before it can be selected due to security constraints.

Solutions and Workarounds

  • To resolve this, it's necessary to prevent immediate selection of the newly created board until after it has been added to user boards via a trigger.
  • The speaker mentions using "returning minimal" as a solution to avoid selecting data immediately after insertion, which will become a default behavior in future versions.

Data Retrieval and UI Updates

  • After implementing changes, they check for logs and confirm that no data issues arise upon refreshing the page.
  • The speaker emphasizes resolving board IDs to actual board information within select statements for better clarity in data representation.

Enhancing User Experience with Automatic Routing

  • They discuss updating UI elements by retrieving information right after starting a new board and routing users automatically based on their actions.
  • This automatic routing enhances user experience by directing them to their newly created workspace seamlessly.

Implementing CRUD Functionalities

Preparing for List Management

  • As they prepare for more complex functionalities like managing lists and cards within workspaces, they plan to implement multiple CRUD operations at once rather than individually.

Defining Board Functions

  • Three functions are outlined: one for fetching specific board information, another for updating details, and a third for deleting entries. Each follows similar patterns with match clauses based on board ID.

Managing Lists Within Boards

Adding Functionality to a Board Application

Inserting New Lists and Cards

  • The process begins with adding new lists to the list table, which involves inserting information and selecting the newly created list.
  • Functions for managing cards are introduced, including adding a card to a list, following a consistent pattern established earlier.
  • The discussion emphasizes tracking board ID and list ID while retrieving all cards for a specific list, along with updating and deleting cards.

User Invitations to Boards

  • A simplified approach is proposed for inviting users to boards without creating complex invitation logic or additional tables.
  • The method involves adding a user by looking up their email in the users table and creating an entry in the user-board relation table if found.
  • While this method bypasses formal invitations, it allows immediate access for new users; more sophisticated options could include sending transactional emails.

Transitioning Focus to Board Component

  • With backend functionalities established, attention shifts entirely to developing the board component of the application.
  • Initial steps involve importing necessary modules and retrieving the board ID from the URL; some services may not be needed at this stage.

Loading Board Information

  • The activated route is used alongside data services to load essential information about the board, including its title and lists.
  • Utilizing ngOnInit, the board ID is fetched, allowing retrieval of general board information through asynchronous service calls.

Managing Lists and Cards

  • After obtaining board details, lists are set up using previously defined functionalities; care is taken not to duplicate code unnecessarily.
  • Each list's cards are organized into an object structure that maps IDs to arrays of associated cards for efficient management.

Real-Time Updates and Additional Functionalities

  • Plans for handling real-time updates are discussed early on to ensure they are integrated seamlessly later in development.

Implementing Board and List Logic

Deleting Boards and Adding Lists

  • The process begins with deleting a board, which removes it from the interface. This action also resets the view since there is no longer a board present.
  • A helper function is introduced to edit list titles, showcasing an example of how to manage complexity in the application while maintaining clarity.

Card Management Features

  • Logic for managing cards is implemented, allowing users to add, edit, update, and delete cards within lists. This mirrors the functionality established for lists.
  • Invitation logic is briefly discussed; user email input will be connected to server-side processing for handling invitations.

User Interface Enhancements

  • The header area of the application now includes a title and functions for deleting boards and navigating back. An input field allows users to change names dynamically.
  • Users can save changes made to titles through an interactive input field that becomes active upon clicking.

Editing Functionality Improvements

  • The current implementation lacks a cancel option when editing titles. A solution using Angular's host listener is proposed to listen for keydown events (specifically the escape key).
  • When pressing escape, editing ends for any open list or card, enhancing user experience by providing an easy way out of editing mode.

Structuring Lists and Cards on One Page

Layout Design Choices

  • The main area features a flexible layout where all lists are iterated over. A button allows users to add new lists seamlessly.
  • Each list contains logic similar to that found in the top bar for editing purposes, ensuring consistency across functionalities.

Iterating Through Cards

  • Within each list iteration, cards are displayed using another ngFor directive. Users can edit or delete these cards as needed.

Real-Time Updates and Database Interaction

  • Although real-time updates aren't yet functional without refreshing the page, adding new lists demonstrates potential interactivity once fully implemented.

Finalizing Features and Database Integration

Adding Cards and Refreshing Data

  • Users can create new cards within their lists; however, they won't appear until after refreshing due to lack of real-time data binding at this stage.

Exploring Database Entries

  • The Superbase database interface allows users to view entries created in the editor. It provides advanced options like direct table editing.

Achievements So Far

Real-Time User Invitation and Debugging Process

Inviting Users to a Board

  • The speaker discusses adding an input field in HTML to invite users by email, indicating the need for multiple users in the application.
  • A different email is used to send a magic link for user authentication, emphasizing the importance of copying the link instead of clicking it directly.
  • After inviting a new user, there’s uncertainty about whether an entry was created in the user boards table, prompting a refresh to check.

Debugging User Invitations

  • The speaker reflects on potential issues with user invitations, such as missing users or incorrect insertions into the database.
  • They confirm that they have an ID for the user being added but are unsure why it isn't working as expected.
  • An error related to signing in is identified; confusion arises over whether they were signed in previously.

Understanding Role-Level Policies

  • The speaker encounters an error regarding role-level policies when trying to add a user to boards, highlighting their lack of understanding of these policies.
  • They discuss how role-level security impacts data insertion and mention that future implementations may simplify this process.

Successful User Addition

  • After troubleshooting, they successfully add a new user (Simon), confirming that both users can now collaborate on the shopping list board.
  • This success illustrates effective debugging and understanding of real-time functionalities within their application.

Enabling Real-Time Functionalities

Setting Up Real-Time Capabilities

  • The speaker explains enabling real-time features for both cards and lists tables within their database setup using SQL commands.
  • They plan to create a function called getTableChanges which will allow tracking changes across tables effectively.

Listening for Changes

  • The function will return observable changes from the cards table by listening for all events using wildcard syntax (*).
  • This approach allows capturing updates from both cards and lists tables simultaneously through one stream.

Subscribing to Updates

  • The board component needs to subscribe to these updates and handle them appropriately; existing code snippets are referenced for managing real-time updates.

Real-Time Updates in Angular with Supabase

Troubleshooting Real-Time Updates

  • The user is not receiving real-time updates, which could be due to project misconfiguration or a mistake in the code.
  • The speaker suspects that the issue may not stem from calling functions incorrectly this time, indicating a different underlying problem.
  • A misunderstanding of hot vs. cold observables is revealed; subscribing to an observable is necessary for it to function properly.

Implementing Changes and Observables

  • After ensuring subscription to changes, the speaker tests adding a card and confirms that updates are reflected in real-time across both interfaces.
  • Deleting items triggers multiple delete updates due to cascading effects, emphasizing the importance of understanding event types in database operations.

Updating Views Based on Database Changes

  • The need arises to update views based on database changes; the speaker plans to implement code for handling insertions, updates, and deletions effectively.
  • The process involves checking if records exist based on event types and managing how data is pushed or filtered out accordingly.

Finalizing Functionality

  • The implementation covers all CRUD operations (Create, Read, Update, Delete), ensuring that lists and cards are updated correctly within the application.
  • Testing reveals successful creation of new lists and cards with real-time synchronization across interfaces.

Course Conclusion and Future Directions

  • The project achieves its goal of creating boards with secure user invitations while utilizing real-time functionalities through Supabase.
  • Although the tutorial has covered significant ground, there remains potential for exploring additional features like Supabase storage or cloud functions.

Key Learnings from the Tutorial

  • This extensive course provided insights into SQL databases, Supabase integration, Angular observables, and guards—valuable knowledge applicable for future projects.
Video description

In this tutorial we will build a full blown Angular application with Supabase backend including authentication, SQL definition and realtime functionality! This video is sponsored by Supabase - Build in a weekend. Scale to millions. https://supabase.com 🔥 The fastest way to learn Ionic: https://ionicacademy.com/ ⚡️ Just getting started? Grab a free 46 pages eBook: https://ionicacademy.com/ionic-quickstart-guide/ ############################# 👨‍💻 Want to read instead of watch? Here's the link tot the tutorial: https://supabase.com/blog/building-a-realtime-trello-board-with-supabase-and-angular 🤷‍♂️ Want more tutorials? There you go: https://devdactic.com/ ############################# ❤️ You can also find me on: Instagram: http://instagram.com/simongrimm_ Twitter: https://twitter.com/schlimmson Facebook: https://www.facebook.com/devdactic TikTok: https://www.tiktok.com/@simongrimm_ Or join the Simonics Facebook group: https://www.facebook.com/groups/simonics/ ############################# 00:00 Intro to Supabase 02:22 Supabase Project Configuration 11:43 Angular Project Setup 18:45 Magic Link Sign in & Authentication 36:04 Create & Read Supabase Data 47:30 Supabase Database CRUD Functions 52:23 Working with Supabase Data 64:20 Supabase Realtime Functionality 77:43 Outro