diff --git a/docs/content/packages/ui.md b/docs/content/packages/ui.md
index d12b0f3c..3a5d5e89 100644
--- a/docs/content/packages/ui.md
+++ b/docs/content/packages/ui.md
@@ -28,13 +28,46 @@ The simplest way to add an admin interface to your Next.js app:
```typescript
// app/admin/[[...admin]]/page.tsx
import { AdminUI } from '@opensaas/stack-ui'
-import { getAdminContext } from '@opensaas/stack-ui/server'
-import config from '@/opensaas.config'
+import type { ServerActionInput } from '@opensaas/stack-ui/server'
+import { getContext, config } from '@/.opensaas/context'
+import { getSession } from '@/lib/auth'
+import { redirect } from 'next/navigation'
+import { getUrlKey } from '@opensaas/stack-core'
import '@opensaas/stack-ui/styles'
-export default async function AdminPage() {
- const context = await getAdminContext()
- return
+async function serverAction(props: ServerActionInput) {
+ 'use server'
+ const session = await getSession()
+ const context = await getContext(session ?? undefined)
+ const result = await context.serverAction(props)
+ if (result && typeof result === 'object' && 'success' in result && result.success) {
+ redirect(`/admin/${getUrlKey(props.listKey)}`)
+ }
+ return result
+}
+
+interface AdminPageProps {
+ params: Promise<{ admin?: string[] }>
+ searchParams: Promise<{ [key: string]: string | string[] | undefined }>
+}
+
+export default async function AdminPage({ params, searchParams }: AdminPageProps) {
+ const resolvedParams = await params
+ const resolvedSearchParams = await searchParams
+ const session = await getSession()
+ if (!session) {
+ return
You must be signed in to access the admin interface.
+ }
+ return (
+
+ )
}
```
@@ -65,8 +98,8 @@ import { TextField, SelectField, RelationshipField } from '@opensaas/stack-ui/fi
// Standalone components - Composable CRUD components
import { ItemCreateForm, ItemEditForm, ListTable } from '@opensaas/stack-ui/standalone'
-// Server utilities - Context and session management
-import { getAdminContext } from '@opensaas/stack-ui/server'
+// Server utilities - Type imports for server actions
+import type { ServerActionInput } from '@opensaas/stack-ui/server'
// Styles - Tailwind CSS
import '@opensaas/stack-ui/styles'
@@ -80,19 +113,34 @@ The `AdminUI` component provides a complete admin interface with routing, naviga
```typescript
import { AdminUI } from '@opensaas/stack-ui'
-import { getAdminContext } from '@opensaas/stack-ui/server'
-import config from '@/opensaas.config'
+import type { ServerActionInput } from '@opensaas/stack-ui/server'
+import { getContext, config } from '@/.opensaas/context'
+import { getSession } from '@/lib/auth'
+
+async function serverAction(props: ServerActionInput) {
+ 'use server'
+ const session = await getSession()
+ const context = await getContext(session ?? undefined)
+ return context.serverAction(props)
+}
export default async function AdminPage() {
- const context = await getAdminContext()
- return
+ const session = await getSession()
+ return (
+
+ )
}
```
**Props:**
-- `context` - Admin context with session and database access
+- `context` - Access-controlled context from `.opensaas/context`
- `config` - OpenSaas configuration object
+- `serverAction` - `'use server'` wrapper around `context.serverAction` for mutations
**Features:**
@@ -156,10 +204,12 @@ A standalone form for creating new items.
```typescript
import { ItemCreateForm } from '@opensaas/stack-ui/standalone'
-import { getAdminContext } from '@opensaas/stack-ui/server'
+import { getContext } from '@/.opensaas/context'
+import { getSession } from '@/lib/auth'
export default async function CreatePostPage() {
- const context = await getAdminContext()
+ const session = await getSession()
+ const context = await getContext(session ?? undefined)
return (
@@ -488,20 +542,27 @@ The `FieldRenderer` resolves components in the following order:
## Server Utilities
-### getAdminContext
+The `@opensaas/stack-ui/server` export provides TypeScript types for server action integration.
-Get an admin context with session from request headers.
+### ServerActionInput
-```typescript
-import { getAdminContext } from '@opensaas/stack-ui/server'
+`ServerActionInput` is the type for the props passed to your server action wrapper. Import it to type the `serverAction` function you pass to ``.
-export default async function AdminPage() {
- const context = await getAdminContext()
- // context includes session if using @opensaas/stack-auth
- return
+```typescript
+import type { ServerActionInput } from '@opensaas/stack-ui/server'
+import { getContext } from '@/.opensaas/context'
+import { getSession } from '@/lib/auth'
+
+async function serverAction(props: ServerActionInput) {
+ 'use server'
+ const session = await getSession()
+ const context = await getContext(session ?? undefined)
+ return context.serverAction(props)
}
```
+There is no `getAdminContext` helper in this package. The host application is responsible for resolving the session and constructing the context using `getContext` from the generated `.opensaas/context` module.
+
## Styling
The UI package includes Tailwind CSS v4 styles. Import them in your root layout:
@@ -553,7 +614,7 @@ All components are fully typed with TypeScript:
The UI package is optimized for performance:
-- Server components by default (AdminUI, getAdminContext)
+- Server components by default (AdminUI, standalone components)
- Client components only where needed (forms, interactive elements)
- Minimal client-side JavaScript
- Data fetching on the server reduces bundle size
@@ -567,10 +628,12 @@ Build a custom dashboard using standalone components:
```typescript
import { ListTable, ItemCreateForm } from '@opensaas/stack-ui/standalone'
import { Card, CardHeader, CardContent } from '@opensaas/stack-ui/primitives'
-import { getAdminContext } from '@opensaas/stack-ui/server'
+import { getContext } from '@/.opensaas/context'
+import { getSession } from '@/lib/auth'
export default async function CustomDashboard() {
- const context = await getAdminContext()
+ const session = await getSession()
+ const context = await getContext(session ?? undefined)
return (