Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.auction-rise.com/llms.txt

Use this file to discover all available pages before exploring further.

Adding Features

This guide shows how to add new features following the conventions used throughout the codebase.

Directory Conventions

LayerLocationContains
Pagesapp/(platform)/your-feature/Next.js App Router pages
API routesapp/api/your-feature/Route handlers
Server actionslib/your-feature/actions.ts"use server" functions
Typeslib/your-feature/types.tsTypeScript types
Context/hookslib/your-feature/context.tsxReact context + hooks
UI componentscomponents/your-feature/Feature-specific components
Migrationssupabase/migrations/Timestamped SQL files

Migration Naming

Use a timestamp prefix that puts your migrations after the template’s own migrations:
supabase/migrations/20260401000000_create_projects.sql
The template’s migrations use dates in the 2026XXXX range. Use a date after the latest existing migration to ensure correct ordering.

Example: Adding a “Projects” Feature

1

Create the migration

-- supabase/migrations/20260401000000_create_projects.sql
CREATE TABLE projects (
  id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  workspace_id uuid NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
  name text NOT NULL CHECK (char_length(name) BETWEEN 1 AND 100),
  description text,
  created_by uuid REFERENCES auth.users(id),
  created_at timestamptz DEFAULT now(),
  updated_at timestamptz DEFAULT now()
);

ALTER TABLE projects ENABLE ROW LEVEL SECURITY;

CREATE POLICY "workspace members can access projects"
  ON projects FOR ALL
  USING (is_workspace_member(workspace_id));
2

Generate updated TypeScript types

pnpm run types:generate
This regenerates types/database.types.ts from your Supabase schema.
3

Create server actions

// lib/projects/actions.ts
"use server";

import { createServerClient } from "@/lib/supabase/server";

export async function createProject(workspaceId: string, name: string) {
  const supabase = await createServerClient();
  const { data: { user } } = await supabase.auth.getUser();
  if (!user) return { error: "Not authenticated" };

  const { data, error } = await supabase
    .from("projects")
    .insert({ workspace_id: workspaceId, name, created_by: user.id })
    .select()
    .single();

  if (error) return { error: error.message };
  return { project: data };
}
4

Add a page

// app/(platform)/projects/page.tsx
import { createServerClient } from "@/lib/supabase/server";
import { PageContainer } from "@/components/ui/page-container";

export default async function ProjectsPage() {
  const supabase = await createServerClient();
  const { data: projects } = await supabase
    .from("projects")
    .select("*")
    .order("created_at", { ascending: false });

  return (
    <PageContainer size="default">
      <h1>Projects</h1>
      {/* render projects */}
    </PageContainer>
  );
}
5

Add to sidebar navigation

// saas.config.ts
import { FolderOpen } from "lucide-react";

sidebar: {
  navItems: [
    { href: "/projects", label: "Projects", icon: <FolderOpen /> },
  ],
},

Caching Considerations

For workspace-scoped data protected by RLS, do not use unstable_cache(). It caches at the process level and bypasses RLS on cache hits, which can leak data across users. Instead, use React cache() for request-scoped deduplication:
import { cache } from "react";

export const cachedGetProject = cache(async (id: string) => {
  const supabase = await createServerClient();
  const { data } = await supabase.from("projects").select("*").eq("id", id).single();
  return data;
});
For cache invalidation after mutations, use revalidateTag() with tag constants in lib/cache/tags.ts.

Pulling Template Updates

If the template receives upstream fixes, use sync-upstream.sh to pull changes into your fork while preserving your domain code:
./sync-upstream.sh
The script merges template changes onto a separate branch so you can review diffs before applying them to your main branch.