Building Interfaces
Learn how to create and customize interfaces in Lux Studio.
Creating a New Interface
- Open Lux Studio
- Navigate to Interfaces in the sidebar
- Click New Interface
- Enter a name and optional description
- Choose interface type (external or internal)
Interface Structure
Interfaces are Next.js applications with the following structure:
app/ # Pages (Server Components by default)
├── page.tsx # Home page
├── layout.tsx # Root layout
├── dashboard/
│ └── page.tsx # Dashboard page
components/ # React components
├── ui/ # shadcn/ui components
lib/
├── flows.ts # Auto-generated flow definitions
├── executeFlow.ts # Server-side flow helper
├── callFlow.ts # Client-side flow helper
├── auth.config.ts # Better Auth configuration
└── auth-client.ts # Auth client helperInterface Builder Tabs
Code Tab
Direct access to the Next.js source code.
- File Browser - Navigate project files
- Monaco Editor - Full-featured code editor
- Live Preview - See changes in real-time
Auth Tab
Configure authentication for your interface.
- Better Auth - Built-in authentication system
- Protected Routes - Restrict access to authenticated users
- User Management - View and manage users
Logs Tab
View runtime logs and debug your interface.
- Console Logs - Browser console output
- Server Logs - Next.js server logs
- Error Tracking - Identify and debug issues
Component Library
Lux interfaces include shadcn/ui components:
- Forms - Input, Select, Checkbox, Radio, etc.
- Layout - Card, Dialog, Sheet, Tabs, etc.
- Display - Table, Badge, Avatar, etc.
- Feedback - Alert, Toast, Progress, etc.
Connecting to Flows
Server-Side (SSR)
Use executeFlow() in Server Components (pages):
// app/products/page.tsx (Server Component - no 'use client')
import { executeFlow } from '@/lib/executeFlow';
export default async function ProductsPage() {
// Data is fetched server-side before rendering
const products = await executeFlow('get_products');
return (
<div>
{products.map((p) => (
<ProductCard key={p.id} product={p} />
))}
</div>
);
}Client-Side
Use callFlow() in Client Components for user interactions:
// components/ContactForm.tsx
'use client';
import { useState } from 'react';
import { callFlow } from '@/lib/callFlow';
export function ContactForm() {
const [submitting, setSubmitting] = useState(false);
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
setSubmitting(true);
const result = await callFlow('submit_contact', {
name: formData.name,
email: formData.email,
message: formData.message,
});
if (result.success) {
// Handle success
}
setSubmitting(false);
}
return (
<form onSubmit={handleSubmit}>
{/* Form fields */}
</form>
);
}Authentication
Interfaces use Better Auth for authentication. Key files:
| File | Purpose |
|---|---|
lib/auth.config.ts | Auth configuration |
lib/auth-client.ts | Client-side auth helpers |
app/api/auth/[...all]/route.ts | Auth API routes |
Using Auth in Components
'use client';
import { useSession, signOut } from '@/lib/auth-client';
export function UserMenu() {
const { data: session } = useSession();
if (!session?.user) return <SignInButton />;
return (
<div>
Welcome, {session.user.name}
<button onClick={() => signOut()}>Sign Out</button>
</div>
);
}Protecting Pages
// app/dashboard/page.tsx
import { auth } from '@/lib/auth.config';
import { redirect } from 'next/navigation';
export default async function DashboardPage() {
const session = await auth();
if (!session) {
redirect('/sign-in');
}
return <Dashboard user={session.user} />;
}Best Practices
SSR-First Architecture
- Use Server Components (default) for data display
- Add
'use client'only for interactive components - Fetch data server-side with
executeFlow()for better performance
When to Use Each Helper
| Use Case | Helper | Component Type |
|---|---|---|
| Load data on page | executeFlow() | Server Component |
| Form submission | callFlow() | Client Component |
| Button action | callFlow() | Client Component |
| Filter/sort client-side | Both | SSR + Client |
Component Structure
// Good: Page fetches data, passes to client component
// app/orders/page.tsx (Server Component)
export default async function OrdersPage() {
const orders = await executeFlow('get_orders');
return <OrderList orders={orders} />;
}
// components/OrderList.tsx (Client Component for interactivity)
'use client';
export function OrderList({ orders }) {
// Can now add delete buttons, sorting, etc.
}Next: Deploying →