Interfaces
Building Interfaces

Building Interfaces

Learn how to create and customize interfaces in Lux Studio.

Creating a New Interface

  1. Open Lux Studio
  2. Navigate to Interfaces in the sidebar
  3. Click New Interface
  4. Enter a name and optional description
  5. 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 helper

Interface 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:

FilePurpose
lib/auth.config.tsAuth configuration
lib/auth-client.tsClient-side auth helpers
app/api/auth/[...all]/route.tsAuth 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 CaseHelperComponent Type
Load data on pageexecuteFlow()Server Component
Form submissioncallFlow()Client Component
Button actioncallFlow()Client Component
Filter/sort client-sideBothSSR + 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 →