webapp-starter

repository·main·Indexed 21 days ago

https://github.com/sullyo/webapp-starter

A modern full-stack SaaS template built with Turborepo, featuring a Hono and Bun API backend and a Next.js frontend. It integrates Supabase for database management via Drizzle ORM and Clerk for authentication and webhooks. The template includes a streaming chat interface using the Vercel AI SDK v2, a post management system, and end-to-end type safety via Hono RPC.

Tokens
11.2K
Snippets
45
Records
54
Agent score
74%

What's inside webapp-starter

  1. Set up Clerk Webhooks for local development

    main

    To sync user data (like user.created, user.updated, and user.deleted) from Clerk to your local API, you must expose your local server to the internet using ngrok and configure a webhook endpoint in the Clerk Dashboard.

    Steps:

    1. Expose local server: Install ngrok and obtain a forwarding URL (e.g., https://your-url.ngrok-free.app).
    2. Configure Clerk: In the Clerk Dashboard, navigate to Webhooks and add a new endpoint pointing to https://your-url.ngrok-free.app/api/webhooks. Select the desired events.
    3. Configure Environment: Copy the Signing Secret from Clerk and add it to your environment variables.
    4. Start Listener: Use the provided CLI command to start ngrok and forward the API port automatically.
    DATABASE_URL="your_database_url"
    CLERK_WEBHOOK_SECRET="your_signing_secret"
    pnpm clerk:listen
  2. Install the webapp-starter template

    main

    To set up the project locally, follow these steps:

    1. Install dependencies: Use pnpm to install all workspace dependencies.
    2. Install Bun: Ensure Bun is installed on your system (required for the API backend).
    3. Configure Environment Variables: Create .env files in apps/api, apps/web, and packages/db as specified in the environment setup guide.
    pnpm install
    
    # Install Bun (macOS/Linux/WSL)
    curl -fsSL https://bun.sh/install | bash
    
    # Install Bun (via npm)
    npm install -g bun
    
    # Install Bun (via Homebrew)
    brew install oven-sh/bun/bun
  3. Deploy the API backend to Render

    main

    To deploy the Bun API backend to Render:

    1. Create a new Web Service on Render.
    2. Connect your repository.
    3. If not using a render.yaml file, configure the following manually:
      • Root Directory: apps/api
      • Build Command: pnpm install
      • Start Command: pnpm start
    4. Add all required environment variables from apps/api/.env in the Render dashboard.
  4. Deploy the web application to Vercel

    main

    The recommended way to deploy this Next.js application is via the Vercel Platform. You can follow the official Next.js deployment documentation for detailed steps on connecting your repository and configuring your project for production.

    https://nextjs.org/docs/app/building-your-application/deploying
  5. Configure environment variables

    main

    The project requires specific environment variables in three different locations to function correctly.

    API Backend (apps/api/.env)

    Required for database connection and Clerk authentication/webhooks.

    • DATABASE_URL
    • CLERK_SECRET_KEY
    • NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
    • CLERK_SIGNING_SECRET

    Web Frontend (apps/web/.env)

    Required for Clerk authentication and connecting to the API.

    • NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY
    • CLERK_SECRET_KEY
    • NEXT_PUBLIC_API_URL

    Database Package (packages/db/.env)

    Required for running migrations and pushing schema changes.

    • DATABASE_URL
    # apps/api/.env
    DATABASE_URL=your_database_url
    CLERK_SECRET_KEY=your_clerk_secret_key
    NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_clerk_publishable_key
    CLERK_SIGNING_SECRET=your_clerk_webhook_secret
    
    # apps/web/.env
    NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your_clerk_publishable_key
    CLERK_SECRET_KEY=your_clerk_secret_key
    NEXT_PUBLIC_API_URL=your_api_url
    
    # packages/db/.env
    DATABASE_URL=your_database_url
  6. Run the web application in development mode

    main

    To start the Next.js development server, use your preferred package manager to run the dev script. Once running, the application will be available at http://localhost:3000. You can modify app/page.tsx to see real-time updates via Fast Refresh.

    npm run dev
    # or
    yarn dev
    # or
    pnpm dev
    # or
    bun dev
  7. Set up Clerk authentication and webhooks

    main

    Clerk is used for user authentication. To enable full functionality:

    1. Create a Clerk application and copy the API keys to your .env files.
    2. Configure OAuth providers in the Clerk dashboard if needed.
    3. Webhooks: Configure a Clerk webhook to sync user creation and authentication events with your API backend. This ensures your local user database stays in sync with Clerk.
  8. Initialize and migrate the database

    main

    The project uses Drizzle ORM and supports any PostgreSQL database (Supabase is recommended).

    1. Initialize: Use pnpm db:push to push your current schema to the database for local testing.
    2. Generate: Use pnpm db:generate to generate the schema files.
    3. Migrate: Use pnpm db:migrate to apply the generated schema to the database.
    pnpm db:push
    pnpm db:generate
    pnpm db:migrate
  9. Manage Chats via React Query hooks

    main

    The chats.api.ts module provides a set of TanStack React Query hooks for interacting with the chat API. These hooks handle data fetching, mutations, and automatic cache invalidation to keep the UI in sync with the backend.

    Available Hooks

    Fetching Data

    • useGetChats(): Fetches a list of all chats. Uses query key ['chats'].
    • useGetChat(params: GetChatParams): Fetches a specific chat by ID. Uses query key ['chat', { id: params.param.id }]. Only runs if params.param.id is present.
    • useGetChatMessages(params: GetChatMessagesParams & { disable?: boolean }): Fetches messages for a specific chat. Uses query key ['chat-messages', { chatId: params.param.id }]. Only runs if params.param.id is present and disable is not true.
    • useGetChatMessage(params: GetChatMessageParams): Fetches a specific message. Uses query key ['chat-message', { chatId: params.param.chatId, messageId: params.param.messageId }].

    Mutations

    • useCreateChat(): Creates a new chat. Invalidates ['chats'] on success.
    • useUpdateChat(id: string): Updates an existing chat. Invalidates ['chats'] and ['chat', { id }] on success.
    • useDeleteChat(id: string): Deletes a chat. Invalidates ['chats'] on success.
    • useCreateChatMessage(chatId: string): Sends a new message in a chat. Invalidates ['chat-messages', { chatId }] on success.
    • useUpdateChatMessage(chatId: string, messageId: string): Updates a message. Invalidates ['chat-messages', { chatId }] and ['chat-message', { chatId, messageId }] on success.
    • useDeleteChatMessage(chatId: string, messageId: string): Deletes a message. Invalidates ['chat-messages', { chatId }] on success.
    import { useGetChats, useCreateChat } from '@/api/chats.api';
    
    // Example: Fetching chats
    const { data: chats, isLoading } = useGetChats();
    
    // Example: Creating a chat
    const createChatMutation = useCreateChat();
    const handleCreate = (params: CreateChatParams) => {
      createChatMutation.mutate(params);
    };