Advanced

Team-Based Authentication

Scope data and API calls to specific teams

Enable team-based authentication to automatically scope all data and API calls to the current team context.

Enable Team Utilities

Add the team utility flag to your Crouton config:

// crouton.config.js
export default {
  collections: [
    { name: 'products', fieldsFile: './schemas/product-schema.json' },
  ],
  targets: [
    {
      layer: 'shop',
      collections: ['products']
    }
  ],
  flags: {
    useTeamUtility: true  // Enable team-based multi-tenancy
  }
}

What This Enables

When useTeamUtility: true is set, the generator automatically:

  1. Adds database fields to all collections:
    • teamId (text, required) - References the team/organization
    • userId (text, required) - References the user who created the record
  2. Generates simplified API endpoints that:
    • Automatically inject teamId and userId from the authenticated session
    • Include team membership validation via resolveTeamAndCheckMembership
    • Scope all database queries to the current user's team
  3. Provides team-scoped queries:
    • All getAll* queries filter by teamId
    • All create operations automatically set teamId and userId
    • Team switching triggers automatic query invalidation
Important: Do NOT manually define teamId or userId in your schema JSON files. The generator adds these automatically when useTeamUtility: true, and manual definitions will cause duplicate key errors.See Schema Format - Auto-Generated Fields for details.

Use in Components

The useTeam composable provides team context throughout your app:

Query Examples: For complete useCollectionQuery patterns, see Querying Data.
<script setup lang="ts">
const { currentTeam } = useTeam()

// All API calls include team context
const { items } = await useCollectionQuery('shopProducts')
// → Fetches /api/teams/[teamId]/shop-products
</script>

API Routes

When team utilities are enabled, create team-scoped API routes:

// server/api/teams/[team]/shop-products/index.get.ts
export default defineEventHandler(async (event) => {
  const teamId = getRouterParam(event, 'team')

  // Query scoped to team
  const products = await db
    .select()
    .from(products)
    .where(eq(products.teamId, teamId))

  return products
})

Team Switching

Allow users to switch between teams with automatic query refetching:

<script setup lang="ts">
const { currentTeam, teams, switchTeam } = useTeam()

const handleSwitchTeam = async (teamId: string) => {
  await switchTeam(teamId)
  // All queries auto-refetch for new team!
}
</script>

<template>
  <USelectMenu
    v-model="currentTeam"
    :options="teams"
    @update:model-value="handleSwitchTeam"
  />
</template>

How It Works

When team utilities are enabled:

  1. All queries automatically include the current team ID
  2. API routes receive the team parameter
  3. Switching teams invalidates and refetches all queries
  4. Data is automatically scoped to the active team