This section provides complete "recipes" for common application features. These examples demonstrate how to combine schemas, permissions, and custom logic to build real-world functionality.
This recipe demonstrates how to create a simple "Subscribe" form where public users can add their email address, but cannot see who else has subscribed.
Create a table to store email addresses.
// server/database/schema/subscribers.ts
import { sqliteTable, text } from 'drizzle-orm/sqlite-core'
import { systemFields } from './utils'
export const subscribers = sqliteTable('subscribers', {
...systemFields,
email: text('email').notNull().unique(),
})
We want Public users to be able to Create (subscribe), but NOT List or Read (privacy). Admins or Managers can have full access.
Database Seed / Permission Setup:
publicsubscribers['create']{ "email": "..." }.403 Forbidden (protecting your list).This recipe demonstrates a "User-Generated Content" system where the public submits content, but it requires Admin approval before being displayed on the site.
We include a status field to manage visibility.
// server/database/schema/testimonials.ts
import { sqliteTable, text } from 'drizzle-orm/sqlite-core'
import { systemFields } from './utils'
export const testimonials = sqliteTable('testimonials', {
...systemFields,
// Default to 'inactive' so new submissions aren't immediately visible
status: text('status', { enum: ['active', 'inactive'] }).default('inactive'),
name: text('name').notNull(),
role: text('role').notNull(),
content: text('content').notNull(),
avatar: text('avatar'),
company: text('company'),
})
publictestimonials['create'] (and optionally ['read', 'list'] if you want them to see all testimonials, otherwise restrict this).In our template, we allow ['create', 'read', 'list'] for simplicity, but we use a Custom Endpoint to serve only "Approved" testimonials to the landing page.
Since the generic /api/testimonials endpoint might be restricted or return all items (including inactive ones if public has list access), we create a specific endpoint for the frontend display.
// server/api/active-testimonials.get.ts
import { eq, desc } from 'drizzle-orm'
import { testimonials } from '../database/schema'
import { useDrizzle } from '../utils/drizzle'
export default defineEventHandler(async () => {
const db = useDrizzle()
// Fetch only 'active' testimonials
return await db.select()
.from(testimonials)
.where(eq(testimonials.status, 'active'))
.orderBy(desc(testimonials.createdAt))
.limit(9)
.all()
})
On your landing page, fetch from the custom endpoint:
<script setup lang="ts">
const { data: testimonials } = await useFetch('/api/active-testimonials')
</script>
And use the Auto CRUD Form for submissions:
<CrudCreateRow
resource="testimonials"
:schema="{
resource: 'testimonials',
fields: [
{ name: 'name', type: 'text', required: true },
{ name: 'role', type: 'text', required: true },
{ name: 'content', type: 'textarea', required: true }
]
}"
/>
The CrudCreateRow component automatically handles the POST request to /api/testimonials.