Crafting a Role-Based File Storage System

InfoThis is a summary of the following YouTube video:

Build a File Storage App with Role Based Authorization (Next.js, Shadcn, Typescript)

Web Dev Cody

Feb 28, 2024

ยท

Education

Overview

  1. The tutorial is about building a full stack file storage application similar to Google Drive, featuring file upload, management, and role-based authorization.
  2. Authentication is handled using Clerk, and Convex is used for the backend as a service, both of which are sponsors of the video.
  3. The application includes a dashboard where users can upload files, with error handling for missing titles, and a UI built using ShadCN and Next.js.
  4. Users can search files by name, switch between grid and table views, and filter files by type, such as images, CSV, and PDF.
  5. A Convex cron job runs every minute to delete files marked for deletion, but users can restore files before they are permanently deleted.
  6. The application allows users to mark files as favorites, which can be viewed in a separate favorites section, and files can be downloaded directly from the app.
  7. The app supports organizational accounts, allowing users to switch between personal and team-based accounts, with role-based permissions for file management.
  8. Role-based authorization is implemented to restrict actions based on user roles, such as allowing only admins to delete files.
  9. Users can manage their accounts, including updating profile pictures, with changes reflected in real-time due to Convex's real-time database capabilities.
  10. The tutorial emphasizes the use of websockets in Convex for live updates, enhancing the user experience with real-time data changes.

Next + Convex Setup

  1. The tutorial begins with creating a new repository named 'file Drive' and making it public under the MIT license. This allows for commits throughout the tutorial, enabling users to revisit specific parts or skip setup steps if they are more advanced.
  2. The project setup involves cloning the 'file Drive' repository into a workspace folder and opening it with VSS code. The initial step is setting up a Next.js project using the command 'npx create-next-app@latest', with default settings for TypeScript and Tailwind.
  3. Convex, an npm package, is installed next. The project is initialized with 'npx convex dev', which may require signing in if it's the first time. The project is then associated with the 'web dev Cod' team, and it appears on the Convex dashboard for further development.
  4. A Convex client provider is created inside the source app directory. The code is copied and pasted to wrap all components, allowing access to Convex hooks. The provider is imported and used in the layout, ensuring the app can connect to the Convex backend.
  5. The environment variable 'NEXT_PUBLIC_CONVEX_URL' is verified to ensure the React app can connect to the Convex backend for queries and mutations. The Next.js app is then run using 'npm run dev', and the setup is confirmed by accessing the app on localhost:3000.

Clerk Setup

  1. The tutorial focuses on setting up authentication using Clerk in a full-stack file storage application built with Next.js and Convex.
  2. To begin, the Clerk setup guide for Next.js is followed, starting with creating a new project named 'file drive' on the Clerk dashboard, using Google and email for authentication.
  3. Various social media sign-in options are available in Clerk, which can be easily integrated if needed in the future.
  4. API keys from Clerk are copied into the local environment configuration file (EnV local) for integration with Convex.
  5. A first-class integration between Clerk and Convex is utilized by copying the issuer key from Clerk and applying it in Convex's configuration file (auth.conf.ts).
  6. Clerk is used for both front-end authentication (e.g., showing or hiding widgets) and verifying API requests to ensure the user has a valid Clerk token.
  7. The Clerk Next.js package is installed instead of Clerk React, as the application is built with Next.js.
  8. The Convex client provider is wrapped with the Clerk provider, and necessary imports are made to integrate Clerk with Convex.
  9. Middleware is created to authenticate endpoints, with a matcher ensuring all endpoints require authentication, except those specified as public routes.
  10. Public routes are configured to allow access without redirection to a login page, ensuring a smooth user experience on landing pages.

ShadCN

  1. ShadCN is a component library favored for its ease of use and fun integration into applications. It allows developers to install components using a CLI command, making it straightforward to incorporate into projects.
  2. To set up ShadCN, you can skip the initial setup command if you already have a Next.js project. Installation involves running a command that prompts a questionnaire, where you can choose default styles and CSS variables.
  3. ShadCN offers a variety of components that can be easily added to your application. The library provides examples of fully worked-out applications, allowing developers to view and integrate code directly from GitHub repositories.
  4. The process of adding a component, such as a button, involves running a command that imports the component into a designated directory. This simplifies the integration of UI elements into your project.
  5. Verification of ShadCN's setup involves adding a component to your main page, such as a button, and ensuring it displays correctly. This confirms that ShadCN is properly integrated and functional within your application.

Clerk Components

  1. Clerk provides pre-built components for seamless integration with Next.js, allowing developers to easily implement authentication features without extensive coding. These components include a sign-in button that automatically triggers a modal for user authentication.
  2. The sign-in process can be customized to include options like signing in with Google, and upon successful authentication, users are redirected back to the homepage. This process is streamlined by Clerk's built-in functionalities.
  3. To manage user sessions, developers can use the 'useSession' hook, which requires conversion to a client component. This hook helps in determining the user's authentication status and dynamically displaying content based on whether the user is signed in or out.
  4. Clerk offers 'SignedIn' and 'SignedOut' components to conditionally render UI elements based on the user's authentication state. These components simplify the logic needed to show or hide elements like sign-in or sign-out buttons.
  5. Styling of authentication buttons can be customized to match the application's design, such as using styles from ShadCN. This ensures that the authentication components blend seamlessly with the rest of the application's UI.

First Convex Mutation

  1. The tutorial focuses on building a full stack file storage application using Convex and Clerk, with features like file upload, management, and role-based authorization.
  2. Convex is used to handle data operations, including creating mutations and queries for interacting with the database.
  3. A mutation in Convex is an endpoint for modifying data, such as storing entries in the database, while queries are used for fetching data.
  4. The tutorial demonstrates creating a TypeScript file for handling file storage, where a mutation is defined to store file names in the database.
  5. The mutation allows passing arguments from the front end, with built-in validation in Convex for data types like strings.
  6. A button is added to the front end to trigger the mutation, demonstrating how to use Convex's useMutation hook for type-safe operations.
  7. The real-time capability of Convex is highlighted, showing automatic updates in the UI when data changes in the database.

Convex Query

  1. The tutorial introduces the concept of a query in the context of a full-stack file storage application. Queries are used to retrieve data from a database, as opposed to mutations which are used to create and store data.
  2. A query is defined using an export statement, taking an empty object as arguments and a handler context. The query fetches all entries from a specified table and returns them to the front end.
  3. To implement this on the front end, a function is called using a query API. This function retrieves data from the database and displays it in the UI. The example provided involves mapping over the retrieved files and displaying each file's name in a div element.
  4. The tutorial highlights the real-time data capabilities of Convex. When data is created or deleted, notifications are sent via WebSocket events to update all connected clients in real-time, demonstrating the live data feature.
  5. Convex allows for schema definition, which enhances type safety by specifying the structure and required fields of database tables. This ensures that the front end knows exactly what data to expect from the back end.

Auth in Convex

  1. Authentication is crucial for backend operations in Convex to ensure that only logged-in users can create or fetch files. This is achieved by checking the user's identity through the context object in Convex, specifically using 'context.auth.getUserIdentity'.
  2. If the identity is defined, it indicates that the user is logged in and has been validated against Clerk, a third-party authentication service. If not, the user is considered not logged in.
  3. To prevent unauthorized file creation, the system throws a 'ConvexError' if a user without a valid identity attempts to create or upload a file. This ensures that only authenticated users can perform these actions.
  4. Similarly, when fetching files, the system checks for user identity. If no identity is found, it returns an empty array to prevent the UI from crashing, ensuring a smooth user experience even for unauthenticated users.
  5. The tutorial demonstrates setting up authentication in a full-stack application using Convex, Next.js, ShadCN, and Clerk, highlighting the importance of secure backend operations.

Header

  1. The tutorial focuses on enhancing the UI of a file storage application by adding a header that includes an avatar for user login status. This header is implemented across all pages by creating a header component in the layout file, styled with a border and centered using CSS properties.
  2. A user button from Clerk is integrated into the header, allowing users to view a dropdown menu for signing out and managing their account. This button also provides a modal for security configurations, such as updating or removing the user's image.
  3. The header is styled with flexbox properties to ensure elements are aligned properly, including a padding and background color to distinguish it from the body. The 'Hello World' placeholder is suggested to be replaced with a logo, named 'File Drive'.
  4. The tutorial introduces the concept of adding organizations to the application using Clerk's built-in organization support. An organization switcher component is added next to the user button, but requires enabling in Clerk's settings.
  5. Once organizations are enabled, users can create and manage organizations, inviting others via email. The tutorial demonstrates creating an organization named 'My Awesome Team', allowing multiple users to access shared files.
  6. Each organization is assigned an org ID, which is used to associate data within the application, enabling members to edit, modify, or delete files. Custom roles and permissions can be set up in Clerk to manage access levels within organizations.
  7. The tutorial concludes with a demonstration of viewing organization details, such as members and roles, through Clerk's interface, highlighting the admin's ability to manage organization settings.

Scope Files using OrgId

  1. The tutorial focuses on building a full-stack file storage application with features like file upload, management, role-based authorization, and more, using organizations to manage data complexity.
  2. To manage files by organization, a 'use organization' hook is used in the frontend to retrieve organization data, which is then passed to Convex to fetch files associated with a specific organization.
  3. The organization ID (org ID) is crucial for isolating data between different organizations. It is stored in the schema and required for file creation and retrieval processes.
  4. An index is created on the files table by org ID to enable efficient querying of files associated with specific organizations, enhancing performance.
  5. Handling cases where org ID might be null or undefined is important, especially for personal accounts. Logic is added to use user ID as a fallback when org ID is not available.
  6. The tutorial includes steps to refactor code to accommodate both organization and personal account scenarios, ensuring data is correctly associated and isolated.
  7. The process involves checking if organization and user data are loaded before proceeding with queries, ensuring dependencies are resolved before execution.
  8. The tutorial suggests using optional fields during development to avoid schema collisions and recommends clearing tables during rapid prototyping to simplify data management.
  9. The implementation allows switching between different organizations and personal accounts, ensuring data remains isolated and correctly associated with the respective org ID or user ID.

Clerk Webhooks

  1. The backend must be properly authenticated to ensure that users have access to the correct organization IDs. Simply checking if a user is logged in is insufficient for verifying access to specific organizations.
  2. One approach to verify user access is to make requests to the Clerk API for each request, but this can be inefficient and may lead to rate limiting as the application scales.
  3. An alternative approach is to use JWT tokens to track the active organization ID, but this method has limitations due to the OpenID spec requirements, which may require using unconventional fields.
  4. The recommended approach is to use webhooks from Clerk to update the schema when organizations or users are created, allowing for efficient access checks without constant API calls.
  5. Convex allows the creation of an HTTP endpoint to handle webhook requests, which must be verified using cryptographic signatures to ensure they are from Clerk.
  6. Convex supports different runtimes, and the svix package is used to sign and verify webhooks, requiring a Node.js runtime for certain actions.
  7. Internal actions in Convex are used to handle webhook data, ensuring that only authorized queries and mutations can access them.
  8. When a user is created in Clerk, a webhook event is sent to update the user table in the database with the token identifier and Clerk ID.
  9. The process involves creating a users table and defining mutations to handle user creation and organization membership updates.
  10. Webhooks are configured in Clerk to listen for specific events like user creation and organization membership creation, which trigger updates in the database.
  11. Environment variables are used to store webhook secrets for secure verification of incoming webhook requests.
  12. The system is tested by simulating user creation and organization membership events, ensuring that the database updates correctly with the new information.
  13. The overall goal is to authenticate users and verify their authorization to perform actions like file uploads to specific organization IDs.

OrgId Authorization

  1. The tutorial focuses on creating a file storage application with features like file upload, management, and role-based authorization. It includes UI components such as dialogs, modals, and toasts.
  2. The process begins with setting up the environment using Next.js and Convex, followed by integrating Clerk for authentication and authorization purposes.
  3. A key part of the tutorial is verifying the OrgId when creating a file. This involves checking if the OrgId is associated with the user, using helper functions to streamline the process.
  4. The tutorial explains how to handle errors when a user does not have access to a specific OrgId, ensuring that unauthorized actions are blocked.
  5. It demonstrates the use of context and token identifiers to manage user identities and permissions within the application.
  6. The tutorial includes testing scenarios to ensure that unauthorized users cannot access or manipulate files associated with different OrgIds.
  7. A function is created to abstract the authorization logic, making it reusable for both queries and mutations within the application.
  8. The tutorial concludes with committing the changes made to implement OrgId authorization, ensuring that the application is secure and functions as intended.

File Upload Dialog

  1. The tutorial begins with setting up a full stack file storage application, focusing on creating a user-friendly interface with a title and upload button. The title is styled using CSS classes for text size and boldness, and the layout is adjusted using flexbox for alignment.
  2. A modal dialog is introduced for file uploads, utilizing the ShadCN library. The dialog allows users to input a file title and select a file. The tutorial explains how to install and use the dialog component, emphasizing the importance of importing from the correct directory.
  3. Form handling is implemented using React Hook Form and Zod for validation. The tutorial details setting up a form schema with title and file inputs, ensuring type safety and validation. It explains the use of useForm hook and Zod resolver for managing form state and validation.
  4. The tutorial covers handling file input changes and ensuring the file is correctly captured for upload. It discusses using a custom type for file validation and managing file input changes with an onChange event handler.
  5. The process of uploading files to Convex storage is explained. The tutorial describes creating a backend mutation to generate an upload URL, ensuring user authentication before allowing file uploads. It details the steps to call this mutation from the frontend and handle the file upload process.
  6. The tutorial includes steps to reset the form and close the modal dialog after a successful file upload. It explains using state management to control the dialog's visibility and resetting form fields to ensure a clean state for subsequent uploads.
  7. Throughout the tutorial, the importance of reading documentation and understanding the integration of various components and libraries is emphasized. The tutorial provides a comprehensive guide to building a file upload feature with a focus on user experience and backend integration.

Toast Component

  1. The tutorial focuses on implementing a toast notification component to provide user feedback when actions occur, such as file uploads.
  2. To add a toast, import the component into the layout file and set it up using the 'useToast' method, allowing it to display messages like 'file uploaded'.
  3. Customization of the toast component involves defining new color variants in the global CSS and Tailwind config, enabling changes like making the toast green for success messages.
  4. The tutorial demonstrates handling errors by showing a 'destructive' toast variant when a file upload fails, enhancing user feedback for unsuccessful actions.
  5. To improve user experience, the tutorial suggests resetting form values when modals are closed, ensuring old values do not persist when reopened.

Button Loader

  1. The tutorial focuses on enhancing user experience by implementing a button loader in a modal form. This ensures users receive feedback during submission delays.
  2. To achieve this, the form's state object is utilized to manage the button's disabled state, preventing multiple submissions during loading.
  3. The button is disabled using the form's state, specifically checking if the form is in a loading state to prevent further clicks.
  4. A spinner or loader is added to the button to visually indicate the loading process, using Lucid icons for a spinning effect.
  5. Adjustments are made to the button's styling, such as adding a flex gap to separate the spinner from the text, ensuring a polished look.
  6. The tutorial emphasizes the importance of polishing applications for better usability, even if it requires spending more time on details.
  7. The process concludes with committing the changes to the repository, highlighting the addition of the upload file dialog.

Styling Homepage

  1. The tutorial focuses on improving the homepage's appearance by offering two display options for files: a table or a collection of cards. A toggle feature is suggested to allow users to choose their preferred view.
  2. Before styling, the code undergoes refactoring to enhance structure and manageability. A new file, 'upload button TSX,' is created to encapsulate the upload button component, simplifying the main page code.
  3. Unnecessary code is removed to streamline the file, focusing on keeping only essential elements like the dialog and form submission logic. This results in a cleaner and more efficient codebase.
  4. The tutorial introduces a 'card component' to replace the existing list display of files. This involves importing necessary elements and creating a 'file card TSX' component to handle file display.
  5. The 'file card' component is designed to accept file properties, such as title and type, and includes a footer with a download button. The component is flexible to accommodate different file types.
  6. The layout is adjusted to display files in a grid format, enhancing visual appeal. Grid properties like column count and gap are configured to ensure a neat and organized presentation.

Delete File Dropdown

  1. The tutorial focuses on adding a delete file feature to a file storage application, emphasizing the importance of this functionality.
  2. A dropdown menu is used to facilitate file deletion, with the component imported and integrated into the file card actions.
  3. The delete action is highlighted with a trash icon, and the UI is adjusted for better alignment and spacing.
  4. A confirmation dialog is implemented to ensure users are certain about deleting a file, using an alert dialog component from ShadCN.
  5. The delete operation is linked to a Convex endpoint, which checks user authorization and file existence before deletion.
  6. Error handling is incorporated to manage cases where the file does not exist or the user lacks permission to delete it.
  7. A toast notification is added to inform users of successful file deletion, with adjustments made to the notification's appearance.
  8. The code is committed with a message indicating the addition of the delete file feature, marking progress in the tutorial.

Empty States

  1. The tutorial focuses on enhancing a file storage application's user interface by implementing an 'empty state' when no files are present. This involves displaying a placeholder image and message to prompt users to upload files.
  2. To achieve this, the tutorial suggests using open-source illustrations from a site like undraw, which offers Creative Commons images. The chosen image should match the application's theme, such as black and white for ShadCN.
  3. The process involves downloading an SVG image, adding it to the project's public folder, and using a Next.js image component to display it. The image is set with specific dimensions and an alt text for accessibility.
  4. The logic to display the image only when no files are present is implemented using a conditional check. If the files array is undefined or empty, the image and a prompt message are displayed.
  5. The tutorial emphasizes using CSS classes to style the UI, such as centering the image and text using flexbox properties. This ensures the UI remains user-friendly and visually appealing.
  6. Additional UI enhancements include adding an upload button below the message, which is conditionally displayed based on the presence of files. This button allows users to easily upload new files.
  7. The tutorial demonstrates how to dynamically update the UI when files are uploaded or deleted, ensuring the 'empty state' and file list are correctly displayed based on the current state of the file system.

Page Spinner

  1. The initial page load currently lacks a visual indicator, resulting in a blank screen, which can be improved for better user experience.
  2. To address this, a spinner can be displayed when files are undefined, indicating that content is loading.
  3. The spinner implementation can be borrowed from the existing button loader, and its size can be adjusted to 24 or 32 for better visibility.
  4. A 'Loading' text can be added below the spinner, centered on the page, with a gray text color to make it less intense than black.
  5. The spinner should only be shown when files are undefined, and the page can be refreshed to test this functionality.
  6. For a more seamless experience, server-side rendering can be considered to prefetch data, reducing the need for a full-page spinner.
  7. The code can be cleaned up by defining a constant 'isLoading' to check if files are undefined, improving readability and maintainability.

File Types

  1. The tutorial focuses on building a full stack file storage application with features like file upload, management, and role-based authorization.
  2. The application supports different file types such as images, CSVs, and PDFs, and the tutorial emphasizes the importance of tracking these file types for better display and management.
  3. A schema is created to define file types using a union in Convex, allowing for shared type validation between the schema and mutations.
  4. The front end is set up to pass the file type during uploads, using a map to convert MIME types to user-friendly labels like 'image', 'PDF', and 'CSV'.
  5. The tutorial demonstrates how to handle errors related to file type validation and how to ensure the Convex runner processes files correctly.
  6. Icons are used to represent different file types in the UI, with a lookup map to associate file types with specific icons.
  7. The tutorial includes steps to display image previews for image files and discusses potential enhancements for displaying previews of other file types.
  8. A utility function is created to generate URLs for accessing stored files, and Next.js configuration is updated to allow image loading from specific domains.
  9. The UI is adjusted to improve the display of file icons and previews, ensuring a consistent and visually appealing layout.

Download Button

  1. The tutorial explains how to implement a download button that opens a new tab to access file locations on Con X. This feature allows users to download files directly or preview them in a new tab.
  2. The process involves handling different file types such as images, PDFs, and CSVs. Images are displayed in a new tab, PDFs open in a previewer, and CSVs are downloaded directly.
  3. The tutorial notes that this functionality may not work consistently across all browsers, suggesting a need for testing and verification on different platforms.
  4. The final step in the tutorial involves committing the changes to the codebase, with a commit message indicating the addition of image preview capabilities and file download functionality.

Search Bar

  1. The tutorial focuses on adding a search bar to a file storage application, allowing users to filter files by title.
  2. A new component, 'search bar', is created using TypeScript, which includes a form with an input box and a search button.
  3. The form schema is set up to track search criteria, with the default query set to an empty string.
  4. The search bar is integrated into the UI, initially placed under the page header, and later moved to the header for better layout.
  5. Flexbox is used to align the search bar components horizontally, and unnecessary labels are removed for a cleaner interface.
  6. The search functionality is implemented by modifying the Convex query to filter files based on the search input.
  7. State management is handled using React's useState hook to keep track of the search query.
  8. The backend logic is adjusted to perform case-insensitive searches by converting both file names and queries to lowercase.
  9. UI improvements include resizing the search button for better aesthetics and ensuring the search bar is always visible.
  10. The tutorial addresses handling empty states and refactoring code for better user experience and cleaner logic.

Side Nav

  1. The text discusses the addition of a side navigation feature to a web application, emphasizing its importance for functionalities like favoriting or starring documents. This feature is initially added directly to the page, but the possibility of using Next.js layouts for nested navigation is mentioned.
  2. The author prefers a simple initial implementation, planning to refactor later. A basic side navigation is created using a div element, with a 'testing' label to ensure visibility. The layout is split into left and right sections using a flex wrapper, with the side navigation on the left and main content on the right.
  3. The side navigation is given a fixed width, initially set to 32 units and adjusted to 40 for better appearance. The layout is expanded to fill the full page width, acknowledging some loss of horizontal space due to the side navigation.
  4. A button is added to the side navigation for viewing all files, with plans to convert buttons to links later. The button includes a file icon and is styled with flex and gap properties to ensure proper spacing and alignment.
  5. The text describes the process of aligning the button to the left and adjusting spacing using flex properties. A gap of eight units is set between elements for better visual separation.
  6. A link for 'favorites' is added to the side navigation, featuring a star icon. The text notes the need for additional spacing between buttons, achieved by setting a flex column layout with a gap of four units.
  7. The 'favorites' link is intended to lead to a new page, which is not yet created. The text concludes with a note on restructuring the code to support nested navigation.

Refactor Layout

  1. The tutorial involves creating a full stack file storage application with features like file upload, management, and role-based authorization.
  2. The focus is on setting up routes in Next.js, specifically for a dashboard that includes 'favorites' and 'all files' pages.
  3. The dashboard page will incorporate a layout where pages are passed as children, allowing for a structured navigation system.
  4. The process involves copying existing code, organizing it into a dashboard layout, and ensuring proper import of necessary components like buttons and icons.
  5. The files page is simplified by removing unnecessary elements, relying on the layout to handle common components.
  6. A blank 'favorites' page is created, with plans to add content similar to the files page, such as a title.
  7. Adjustments are made to import paths to ensure components are correctly linked after moving files.
  8. The navigation between the 'files' and 'favorites' pages is tested to ensure functionality, with plans to add more content to the 'favorites' page.

Active Link Style

  1. The tutorial focuses on creating a dynamic side navigation component in a Next.js application. This involves abstracting the navigation into a client component, which can be named 'side nav'.
  2. The component is created in a new file, sv.TSX, and is exported as a function. The 'use client' directive is used to ensure the component is client-side rendered.
  3. The component uses the 'usePathname' hook from Next.js to determine the current path. This allows the application to style navigation links differently based on the active route.
  4. The 'clsx' library is introduced to manage conditional styling. It allows the application to apply different styles, such as changing text color, based on whether a navigation link is active.
  5. The tutorial demonstrates how to implement this by checking if the current path includes specific routes like 'dashboard files' or 'dashboard favorites'. If a route is active, the link is styled with a different color.
  6. The process involves testing and adjusting the component to ensure that the side navigation updates correctly as different links are clicked.

File Browser

  1. The discussion focuses on creating a shared component for the favorites page that can be reused across different pages. This involves abstracting common functionalities into a single component to handle different data queries.
  2. The idea is to create a common component that can be used on the dashboard, potentially replacing the current browser component. This involves moving most of the existing code into a new directory for better organization.
  3. The plan includes renaming the component to 'file browser' and using it across multiple pages. This allows for consistent functionality and appearance between the files and favorites pages.
  4. To implement this, the component will be modified to accept a title as a prop, allowing different pages to display different titles such as 'Your Files' or 'Favorites'.
  5. The main distinction between the pages will be the type of data query each uses, which will be passed into the shared component.

Mark as Favorite

  1. The tutorial focuses on adding a 'Mark as Favorite' feature to a file storage application, enhancing user interaction by allowing files to be marked as favorites through a dropdown menu.
  2. Initially, the dropdown menu is modified to include a 'Favorite' option alongside existing options like 'Delete'. The visual appearance is adjusted by removing the red color and adding a separator for better UI clarity.
  3. The core functionality involves creating a new table in the database schema to store favorite records, linking files to users and organizations. This setup allows for efficient management of favorite files across different user accounts and organizations.
  4. An index is added to the favorites table to facilitate quick lookups, using user ID, file ID, and organization ID as keys. This indexing strategy optimizes the process of checking if a file is already marked as a favorite.
  5. A toggle function is implemented using Convex, which handles marking a file as a favorite or removing it from favorites. This function checks user access and file existence before performing database operations.
  6. The code is refactored to improve readability and reusability by creating utility functions. These functions handle access checks and database interactions, reducing code duplication and potential errors.
  7. Testing involves invoking the toggle function from the file card component, ensuring that clicking the 'Favorite' option correctly updates the database by adding or removing entries in the favorites table.
  8. The final steps include updating the UI to reflect the favorite status of files, such as filling the star icon for favorited files and displaying them in a dedicated favorites list.

Favorites Page

  1. The tutorial focuses on building a query system to retrieve files marked as favorites in a file storage application. It involves converting the file browser to an Ed client and running a query when the page loads.
  2. A new query function is proposed, which can either be a separate function or an argument added to an existing function to filter for favorite files. The argument is a Boolean indicating whether to retrieve only favorite files.
  3. The process involves querying the database to get all favorite files associated with a user and organization ID. If the user is not defined, the function returns the files without filtering.
  4. The files are filtered to include only those marked as favorites by checking if their file IDs are in the favorites list. This method is suitable for smaller datasets, with a note on potential adjustments for larger datasets.
  5. The implementation is tested by passing necessary parameters like org ID and favorites status, ensuring the system only displays favorite files. The code is structured to allow reuse across different pages by passing different options.
  6. The tutorial concludes with a successful test showing the system correctly displays and updates favorite files, demonstrating the flexibility and efficiency of the implemented solution.

Favorite Star

  1. The tutorial focuses on enhancing a file storage application by implementing a feature to visually indicate if a file is marked as a favorite. This involves changing the star icon to a filled-in version when a file is favored, making it easier for users to identify their favorite files.
  2. To determine if a file is favored, the application can retrieve a list of all favorite files for a user. This list is then used to check each file's status on the front end, allowing the star icon to be toggled accordingly.
  3. A new method, 'get all favorites,' is introduced to fetch all favorite files associated with a user and organization ID. This method checks for user access and returns an array of favorites, which is then used to update the UI.
  4. The code is refactored to reduce redundancy by creating utility functions that handle user access checks and favorite retrieval. This refactoring helps streamline the codebase and improve maintainability.
  5. The application uses a query to fetch favorite files and passes this data to the file cards, which display the favorite status. A computed property, 'is favored,' is used to determine if a file should display a filled or half-filled star icon.
  6. The UI is updated to include text labels 'Favorite' and 'Unfavorite' next to the star icon, providing clear feedback to users about the action they are performing when clicking the icon.
  7. The tutorial concludes with testing the implementation to ensure that the favorite status is correctly displayed and updated in the UI, confirming the functionality of the new feature.

Role Based Authorization

  1. The tutorial focuses on implementing role-based authorization in a file storage application, ensuring only admins or moderators can access certain features like the delete button.
  2. The process involves using Clerk to manage user roles within an organization, allowing only admins to perform specific actions such as deleting files.
  3. A Protect component from Clerk is used to hide UI elements based on user roles, ensuring that only users with the appropriate permissions can see and interact with certain features.
  4. The backend must also verify user roles to prevent unauthorized actions, even if a user attempts to bypass the UI restrictions by making direct network requests.
  5. Webhooks are utilized to track role assignments and updates, ensuring that the backend is aware of any changes in user roles within an organization.
  6. The tutorial demonstrates how to store and manage user roles in a database, using a schema that associates roles with organization IDs for fine-grained access control.
  7. Edge cases, such as handling personal accounts and ensuring at least one admin remains in an organization, are considered to maintain system integrity.
  8. The implementation includes updating user roles dynamically and ensuring that changes are reflected in both the frontend and backend, using webhooks to listen for role updates.
  9. Testing is conducted to ensure that role-based restrictions are enforced, with errors thrown when unauthorized actions are attempted, and successful actions when permissions are correct.

Delete Cron

  1. In file storage systems, files are not immediately deleted but marked for deletion, allowing a cron job to permanently delete them after a set period, such as 30 days.
  2. The tutorial suggests adding a trash subnavigation to view files marked for deletion, utilizing Convex's cron job capabilities to automate the deletion process.
  3. A new link called 'Trash' is added to the side navigation, leading to a trash dashboard where files marked for deletion can be managed.
  4. In the file browser, a filter is implemented to show only files marked for deletion, using a Boolean flag 'should delete' to identify these files.
  5. The schema is updated to include an optional Boolean 'should delete' to mark files for deletion, which the cron job will use to permanently delete files.
  6. When a file is marked for deletion, it is updated in the database with 'should delete' set to true, rather than being immediately removed.
  7. The user interface is adjusted to reflect the status of files marked for deletion, including changes to modals and navigation icons.
  8. Files marked for deletion are filtered out from the main file view, ensuring they only appear in the trash section until permanently deleted.

Restore Item

  1. The tutorial focuses on building a full stack file storage application with features like file upload, management, and role-based authorization.
  2. A method for restoring deleted files is introduced, allowing users to recover files marked for deletion by setting 'should delete' to false.
  3. The UI is updated to include a restore icon, possibly using an undo icon, and changes the text color to green for restored items.
  4. A cron job feature in Convex is utilized to automate file deletions, running actions or mutations at specified intervals, such as every minute.
  5. The cron job is designed to delete files marked for deletion by querying the database and removing both the storage files and their entries.
  6. The tutorial suggests handling large numbers of files by processing them in smaller batches to avoid timeouts during deletion.
  7. The cron job can be configured to run at different intervals, such as daily, and can notify users about scheduled deletions.

Upload User

  1. The tutorial focuses on enhancing a file storage application by adding user identification features, allowing users to see who uploaded files and when. This involves modifying the webhook to capture additional user information such as name and profile image during user registration.
  2. To implement this, the tutorial suggests updating the internal mutation to accept and store the user's name and image. This requires changes to the schema to include these fields, which are initially set as optional.
  3. The tutorial also covers handling user updates by creating a new internal mutation called 'update user'. This mutation fetches the user by their token identifier and updates their name and image in the database.
  4. To ensure the application responds to user updates, the tutorial instructs on subscribing to the 'user updated' event in Clerk, ensuring that any changes to user profiles are captured and reflected in the application.
  5. The tutorial addresses the issue of hardcoded values by suggesting the use of environment variables to store repeated values, improving maintainability and reducing redundancy.
  6. For displaying user information on file cards, the tutorial proposes fetching user profiles from the UI using a new query endpoint. This involves adding user IDs to files in the schema and ensuring the UI can access this data efficiently.
  7. The tutorial includes steps to integrate an avatar component for displaying user images and names on file cards, along with styling adjustments to improve the user interface.
  8. Finally, the tutorial demonstrates how to format and display the upload date using a date library, ensuring the information is presented clearly and accurately.

Minor Tweaks

  1. The tutorial focuses on refining the user interface and user experience of a file storage application. It begins by addressing the issue of overly long file names that extend beyond their designated space. The solution involves setting a base text size and normal font weight, with an option to truncate names exceeding 20 characters, adding ellipses for clarity.
  2. Icon sizes are standardized to ensure consistency across the application. The file icon is adjusted to match the size of other icons, using a class name to set the width and height to four units each.
  3. The tutorial emphasizes the importance of user experience by rearranging the order of actions. Downloading files is prioritized over marking them as favorites, reflecting its significance in the application's functionality.
  4. A logo is added to the application to enhance its branding. The logo is placed in the header, using the Next.js image component for optimal loading. The size is adjusted to ensure it is visible yet not overwhelming.
  5. Navigation improvements are made by ensuring the logo is clickable, redirecting users to the homepage. Additionally, a new link labeled 'Your Files' is added to the header, directing users to the dashboard or file management page.
  6. The tutorial suggests using a button with an outline variant for the 'Your Files' link, making it less intrusive while still clearly indicating its functionality.
  7. The session concludes with a commit to version control, summarizing the changes made, including logo and header updates, display of creation time and user avatars in cards, and repositioning of the download button.

Table

  1. The tutorial discusses the implementation of a data table for file management, highlighting the benefits of using a table view over a card view for certain applications. This approach can enhance user experience by allowing users to filter, sort, and perform actions like downloading or deleting files directly from the table.
  2. The tutorial introduces the use of a third-party library, TanStack React Table, to facilitate the creation of a data table with sorting features. The guide follows a step-by-step process to set up the table, including defining data and columns, and integrating it into the file browser.
  3. A toggle feature is suggested to switch between a file table and a file card view, enhancing the flexibility of the user interface. The tutorial explains how to define columns and pass data to the table, addressing potential TypeScript errors and refactoring needs.
  4. The tutorial details the customization of table columns, such as displaying the creation date and user information. It explains how to use custom functions to render specific data, like formatted dates and user profiles, within the table cells.
  5. An actions column is added to the table, allowing users to perform actions like downloading or deleting files. The tutorial describes how to extract and reuse components, such as file actions, to maintain code cleanliness and functionality across different parts of the application.
  6. The tutorial addresses the integration of favorite functionality within the table, ensuring that favorite files are correctly displayed and managed. It explains how to modify data structures to include favorite status and update the UI accordingly.

View Toggle

  1. The tutorial focuses on adding a view toggle feature to a file storage application, allowing users to switch between grid and table views. This enhances user experience by providing flexibility in how files are displayed.
  2. Tabs are introduced to facilitate the view toggle. The tutorial explains how to install and import necessary components, and how to integrate these tabs under the main header (H1) of the application.
  3. The grid and table views are placed within the tab contents, allowing users to switch between these views. The tutorial addresses issues with hardcoded widths and suggests removing them for better layout flexibility.
  4. Icons are added to the tabs for visual clarity, with adjustments made to styling using Flexbox to ensure proper alignment and spacing.
  5. The tutorial discusses persisting the user's view choice using local or session storage, although this is not implemented in the example.
  6. A select component is introduced to filter files by type (e.g., images, PDFs, CSVs). The tutorial covers installing the component, setting default values, and updating backend queries based on the selected file type.
  7. The tutorial emphasizes improving user experience by adjusting loading indicators to be more context-specific, such as changing 'loading your images' to 'loading your files' and positioning spinners appropriately.
  8. Accessibility improvements are suggested, such as adding labels to the select component and ensuring proper HTML attributes are used for better user interaction.

Personal Account Bug

  1. The issue addressed is the absence of a delete button for files in personal accounts, which is due to the current logic checking only for admin roles.
  2. The solution involves changing the logic to a condition that checks if the user ID of the file matches the current user's ID, allowing non-admin users to delete their own files.
  3. A new endpoint is created to fetch the current user's information using their Convex ID, not just the token identifier, ensuring accurate user identification.
  4. The process involves exporting a query function to retrieve user data based on the token identifier, returning null if no user is found, and providing the user object if successful.
  5. The front-end can now invoke this query to obtain the authenticated user's information, specifically the user ID, to compare with the file's user ID.
  6. The back-end logic is updated to replace the admin check with a 'can delete' condition, allowing file deletion if the user owns the file or is an admin.
  7. A utility function 'can delete file' is created to encapsulate the deletion logic, taking a user and a file as parameters, and determining access rights.
  8. This function is used in multiple places to ensure consistent logic application, reducing errors and improving maintainability.
  9. The changes are tested by uploading, deleting, and restoring files to ensure the new logic works correctly for both personal and admin accounts.
  10. The final step involves committing the changes with a message indicating the fix for the file deletion issue on personal accounts.

Footer & Landing Page

  1. The tutorial focuses on adding a footer to enhance the application's appearance. The footer is created using a new component, 'footer.TSX', with a specified height and background color. It includes links like 'Privacy Policy', 'Terms of Service', and 'About', styled with flexbox for alignment and hover effects.
  2. The landing page is improved by incorporating a pre-designed Tailwind component. The existing header is removed to avoid redundancy, and the landing page is customized with text promoting the application's features, such as easy file management.
  3. An icon representing the application is added to the landing page for branding purposes. Adjustments are made to ensure elements are centered and properly aligned, addressing issues with padding and layout.
  4. A 'Get Started' button is implemented to direct users to the dashboard. The button is linked using Next.js routing, ensuring users are redirected appropriately based on their authentication status.
  5. A bug is identified where the header is obscured by other elements. This is resolved by adjusting the header's z-index, ensuring it remains clickable and functional.
  6. The tutorial concludes with a commit of the changes and a note of thanks to the sponsors, Convex and Clerk, for supporting the tutorial. Viewers are encouraged to join the Discord channel for community interaction and support.