NextJS 15 FullStack Course - Build an Inventory Management Website

By PedroTech

Share:

Key Concepts

  • Next.js App Router: Modern routing paradigm for Next.js applications, enabling server components and server actions.
  • Server Components: Next.js components rendered on the server, optimizing performance and data fetching.
  • Server Actions: Functions executed directly on the server from client-side interactions, simplifying data mutations and form submissions.
  • Authentication: User verification and session management.
  • Neon: A serverless PostgreSQL database service, offering fast, scalable, and hosted database solutions.
  • Stack O: An authentication service providing pre-built UI components and seamless integration with databases like Neon for user management.
  • Prisma: An Object-Relational Mapper (ORM) that simplifies database interactions (queries, mutations) by providing a type-safe API.
  • Prisma Schema: A declarative way to define database models and their relationships in Prisma.
  • Prisma Migrations: Tools to evolve database schemas in a controlled manner, applying changes defined in the Prisma schema to the actual database.
  • Data Seeding: The process of populating a database with initial data, often for development or testing purposes.
  • Tailwind CSS: A utility-first CSS framework for rapidly building custom designs.
  • Lucid React: A library for easily integrating customizable icons into React applications.
  • Recharts: A composable charting library for React, used to visualize data.
  • Zod: A TypeScript-first schema declaration and validation library, used for validating form data.
  • Pagination: A technique to divide a large set of data into smaller, manageable pages for display.
  • Search Params: URL query parameters used to pass data between client and server, often for filtering or pagination in server components.
  • use client / use server directives: Next.js directives to explicitly mark components or functions as client-side or server-side respectively.
  • Promise.all: A JavaScript method to execute multiple asynchronous operations concurrently and wait for all of them to complete.
  • redirect (from next/navigation): A Next.js function to programmatically redirect users to a different route.

Comprehensive Summary of Building a Full-Stack Next.js Inventory Management App

This video provides a detailed, step-by-step guide to building a full-stack inventory management application using Next.js, focusing on key concepts like server actions, authentication, route handling, and server components. The project aims to equip learners with skills for in-demand web development and resume enhancement.

1. Project Setup and Initial Structure

The project begins by initializing a Next.js application using the npx create-next-app command. The configuration choices made were:

  • Using the current directory (.) for the project name.
  • Enabling TypeScript and ESLint.
  • Integrating Tailwind CSS for styling.
  • Opting not to use a src directory.
  • Crucially, selecting the App Router for modern Next.js features.
  • Declining Turbopack and import aliases.

After setup, the application is run with npm run dev, displaying the Next.js boilerplate. The project structure is then organized by creating dedicated folders for different routes: dashboard, add-product, inventory, settings, and sign-in. The initial page.tsx serves as a minimalist landing page with "Learn More" and "Sign In" buttons, with its UI code provided rather than written manually.

2. Authentication and Database Integration

The application leverages two free services for authentication and data storage:

  • Neon: A serverless PostgreSQL database. A new project named "inventory management app" is created in Neon, specifying PostgreSQL version 17 and an AWS region closest to the user for optimal connection.
  • Stack O: An authentication service offering pre-built UI components and integration with Neon.

Database Setup with Prisma:

  • Prisma is chosen as the ORM to simplify database interactions.
  • npx prisma init is run, generating a prisma folder with schema.prisma and a .env file.
  • The DATABASE_URL in .env is replaced with the connection string obtained from the Neon console.
  • Stack O is then integrated by enabling "Neon O" in the Neon console, copying environment variables (including STACK_PROJECT_ID, STACK_PUBLISHABLE_CLIENT_ID, STACK_SECRET_SERVER_KEY) into .env, and running npx @stackframe/init-stack --no-browser. This command automatically sets up authentication routes (app/handler/page.tsx) and client/server wrappers (stack/client.tsx, stack/server.tsx) for Stack O.
  • The emphasis is placed on building with server components for performance, with client components (use client) reserved only for interactive UI elements requiring React hooks.

3. Sign-In Page Implementation

The app/sign-in/page.tsx component is created. It uses a simple Tailwind CSS layout to center content and integrates the pre-built SignIn component from Stack O. This component automatically provides UI for various authentication methods (GitHub, Google, email/password). A "Go back home" link is also added. The default globals.css is cleared, and a Tailwind CSS gradient background (bg-gradient-to-br from-purple-50 to-purple-100) is applied. Authentication is tested by signing in with GitHub, and user creation is verified in the Neon O console. Stack O automatically handles the "You are already signed in" state.

4. Database Schema Definition and Seeding for Products

The schema.prisma file is updated to define the Product model:

  • id: String @id @default(cuid())
  • userId: String (links product to the creating user)
  • productName: String
  • sku: String? @unique (optional, unique)
  • price: Decimal @db.Decimal(12, 2) (decimal with two places)
  • quantity: Int @default(0)
  • lowStockAt: Int? (optional threshold)
  • createdAt: DateTime @default(now())
  • updatedAt: DateTime @updatedAt
  • Indexes: @@index([userId, name]) (composite) and @@index([createdAt]) are added for query optimization.

The schema changes are applied to the Neon database using npx prisma migrate dev --name init.

Data Seeding: A prisma/seed.ts file is created to populate the database with initial fake data. It uses prisma.product.createMany to insert 25 random products, associating them with the logged-in demoUserId. This script is executed via node prisma/seed.ts.

5. Dashboard UI Development

The dashboard (app/dashboard/page.tsx) is built as a server component, displaying key metrics and charts.

Sidebar Component (components/sidebar.tsx):

  • A fixed sidebar is created with bg-gray-900, text-white, w-64.
  • It includes a logo (using BarChart3 from lucide-react), navigation links (Dashboard, Inventory, Add Product, Settings) with dynamic styling based on the currentPath prop.
  • At the bottom, the UserButton component from Stack O is integrated, showing user info and providing quick access to account settings and sign-out functionality.

Dashboard Main Content:

  • The main content area has ml-64 to accommodate the sidebar.
  • Data Fetching: All data for the dashboard is fetched in the server component using Promise.all for concurrent execution of multiple Prisma queries:
    • totalCount: Total products for the logged-in user.
    • lowStockCount: Products where quantity <= lowStockAt (or 5 if lowStockAt is null).
    • allProducts: All products for the user, selecting price, quantity, createdAt.
    • A lib/prisma.ts file is created to export a singleton Prisma client instance.
    • A lib/auth.ts file contains getCurrentUser to retrieve the logged-in user's ID and redirect if not authenticated.
  • Calculations: totalValue, inStockCount, lowStockCount, outOfStockCount, and their respective percentages are calculated from the fetched data.
  • Key Metrics Section: Displays "Total Products", "Total Value" (formatted as currency), and "Low Stock" count in a responsive grid (grid-cols-1 lg:grid-cols-2).
  • Stock Levels Section: Shows recent products (fetched using prisma.product.findMany with take: 5 and orderBy: { createdAt: 'desc' }) with dynamic color-coded circles (red for out of stock, yellow for low stock, green for good stock) based on stockLevel logic.
  • New Products Per Week Chart:
    • Uses the recharts library (installed via npm install recharts).
    • A products-chart.tsx component is created and marked with 'use client' as charting libraries typically require client-side rendering.
    • Data for the chart (weeklyProductsData) is generated on the server, calculating product counts for the last 12 weeks.
    • The chart is an AreaChart with CartesianGrid, XAxis, YAxis, Area, and Tooltip components, styled with purple colors.
  • Efficiency Section: A custom-built (Tailwind CSS + HTML) circular progress bar displays the "In Stock" percentage, accompanied by a legend showing "In Stock", "Low Stock", and "Out of Stock" percentages with corresponding colored circles.

6. Inventory Page Development

The inventory page (app/inventory/page.tsx) displays a table of products with search and pagination.

  • Header: "Inventory" title and "Manage your products and track inventory levels" description.
  • Search Functionality:
    • A form with method="GET" and action="/inventory" is used.
    • An input with name="q" captures the search query.
    • The page component receives searchParams (e.g., { q: 'product name' }).
    • The prisma.product.findMany query is filtered using name: { contains: q, mode: 'insensitive' } for case-insensitive search.
  • Products Table:
    • A standard HTML <table> is styled with Tailwind CSS.
    • <thead> defines columns: Name, SKU, Price, Quantity, Low Stock At, Actions.
    • <tbody> iterates through paginated products (items).
    • Actions Column: Each row includes a form with a hidden input for productId and a "Delete" button.
    • Delete Server Action (lib/actions/products.ts):
      • An async function deleteProduct(formData: FormData) (marked use server) is created.
      • It extracts productId from formData.
      • prisma.product.deleteMany({ where: { id: productId, userId: user.id } }) ensures only owned products can be deleted.
      • redirect('/inventory') is called after deletion to refresh the table.
  • Pagination:
    • pageSize is set to 10.
    • totalCount of products (filtered by search query) is obtained using prisma.product.count.
    • totalPages is calculated as Math.ceil(totalCount / pageSize).
    • A components/pagination.tsx component is created to handle pagination UI.
    • The pagination component takes currentPage, totalPages, baseURL, and searchParams as props.
    • A getVisiblePages function within pagination.tsx determines which page numbers to display, including "..." for large page ranges.
    • A getPageURL function constructs the URL for each page link by updating the page search parameter.
    • The prisma.product.findMany query for the table incorporates skip: (page - 1) * pageSize and take: pageSize to fetch only the products for the current page.

7. Add Product Page Development

The add product page (app/add-product/page.tsx) provides a form for creating new products.

  • Header: "Add Product" title and "Add a new product to your inventory" description.
  • Form:
    • Includes input fields for Product Name (required), Price (number, min 0, step 0.01), Quantity (number, min 0), SKU (optional), and Low Stock At (optional).
    • Validation with Zod:
      • A productSchema is defined in lib/actions/products.ts using Zod to validate the shape and constraints of the form data (e.g., Z.string().min(1, 'Name is required'), Z.number().min(0, 'Price cannot be negative')).
    • Create Product Server Action (lib/actions/products.ts):
      • An async function createProduct(formData: FormData) (marked use server) is implemented.
      • It uses productSchema.safeParse(formData) to validate the incoming data.
      • If validation fails, a generic error is thrown.
      • On success, prisma.product.create({ data: { ...parsedData, userId: user.id } }) creates the new product.
      • redirect('/inventory') is called to navigate the user to the inventory page after successful submission.
    • Buttons: "Add Product" (submit) and "Cancel" (link to /inventory).

8. Settings Page Development

The settings page (app/settings/page.tsx) is the simplest to implement.

  • Header: "Settings" title and "Manage your account settings and preferences" description.
  • Key Component: It directly integrates the AccountSettings component from Stack O with the fullPage prop. This component automatically provides a comprehensive UI for managing user account details, email, password, multi-factor authentication, and other preferences without requiring custom implementation.

9. Custom Loading State

To enhance user experience and prevent the sidebar from disappearing during navigation, a custom app/loading.tsx component is implemented. This component always renders the Sidebar and displays pulsating skeleton loaders in the main content area while data is being fetched for the current route. This provides a consistent and visually appealing loading state across the application.

10. Conclusion

The video successfully guides through building a complete inventory management system with a functional dashboard, product management (add, delete), search, pagination, and user account settings. It demonstrates effective use of Next.js server components and actions, integrated with external services like Neon and Stack O, and various libraries for UI and data handling. The project serves as a practical example for learning modern full-stack web development with Next.js.

Chat with this Video

AI-Powered

Load the transcript when you're ready to chat so the initial page stays lighter.

Ready to summarize another video?

Summarize YouTube Video