LiveTable LLM Usage Guidelines
View SourceThis document provides clear rules and patterns for AI assistants to help developers use the LiveTable library correctly. Follow these guidelines when generating code suggestions or helping with LiveTable implementation.
Core Principles
1. Field Key Mapping is Critical
RULE: Field keys in fields()
function MUST match exactly with:
- Schema field names (for simple tables)
- Select clause keys (for custom queries)
2. Two Primary Usage Patterns
LiveTable supports exactly two patterns - choose the correct one:
Pattern A: Simple Tables (Single Schema)
use LiveTable.LiveResource, schema: YourApp.Product
- Use when querying a single Ecto schema
- Field keys must match schema field names exactly
- No custom
data_provider
needed inmount/3
Pattern B: Complex Tables (Custom Queries)
use LiveTable.LiveResource
# Must define custom data provider in mount/3
- Use for joins, computed fields, or complex logic
- Field keys must match select clause keys exactly
- Requires custom data provider assignment
Critical Don'ts
DON'T Mix Patterns
NEVER use schema:
parameter with custom queries:
# WRONG - Don't do this
use LiveTable.LiveResource, schema: User # Remove this line
def mount(_params, _session, socket) do
socket = assign(socket, :data_provider, {MyApp.Users, :complex_query, []})
{:ok, socket}
end
DON'T Misalign Field Keys
NEVER use field keys that don't match your data source:
# WRONG - Field key doesn't match schema field
def fields do
[
user_name: %{label: "Name"} # Schema field is 'name', not 'user_name'
]
end
DON'T Forget Required Dependencies
NEVER generate LiveTable code without the core dependency:
# REQUIRED in mix.exs
{:live_table, "~> 0.3.1"}
# Add {:oban, "~> 2.19"} only if using export functionality
DON'T Skip Asset Setup
NEVER implement LiveTable without proper asset configuration
Required Setup Checklist
When implementing with LiveTable, ALWAYS ensure:
1. Dependencies
# In mix.exs deps function
{:live_table, "~> 0.3.1"}
# Add {:oban, "~> 2.19"} only if using exports
2. Configuration
# In config/config.exs
config :live_table,
repo: YourApp.Repo,
pubsub: YourApp.PubSub
# Add Oban config only if using exports
# config :your_app, Oban,
# repo: YourApp.Repo,
# queues: [exports: 10]
3. JavaScript Assets
// In assets/js/app.js
import hooks_default from "../../deps/live_table/priv/static/live-table.js";
const liveSocket = new LiveSocket("/live", Socket, {
hooks: hooks_default, // Required
// ... other config
});
4. CSS Assets
/* In assets/css/app.css */
@source "../../deps/live_table/lib";
@import "../../deps/live_table/priv/static/live-table.css";
Implementation Templates
Template A: Simple Table (Single Schema)
defmodule YourAppWeb.ProductLive.Index do
use YourAppWeb, :live_view
use LiveTable.LiveResource, schema: YourApp.Product
def fields do
[
# Keys MUST match Product schema fields exactly
id: %{label: "ID", sortable: true},
name: %{label: "Product Name", sortable: true, searchable: true},
price: %{label: "Price", sortable: true},
stock_quantity: %{label: "Stock", sortable: true}
]
end
def filters do
[
in_stock: Boolean.new(:stock_quantity, "in_stock", %{
label: "In Stock Only",
condition: dynamic([p], p.stock_quantity > 0)
})
]
end
end
Template B: Complex Table (Custom Query)
defmodule YourAppWeb.OrderReportLive.Index do
use YourAppWeb, :live_view
use LiveTable.LiveResource # NO schema parameter
def mount(_params, _session, socket) do
# REQUIRED: Assign custom data provider as {Module, Function, Arguments}
socket = assign(socket, :data_provider, {YourApp.Orders, :list_with_details, []})
{:ok, socket}
end
def fields do
[
# Keys MUST match select clause keys exactly
order_id: %{label: "Order #", sortable: true},
customer_name: %{label: "Customer", sortable: true, searchable: true},
total_amount: %{label: "Total", sortable: true}
]
end
end
# Corresponding context function
defmodule YourApp.Orders do
def list_with_details do
from o in Order,
join: c in Customer, on: o.customer_id == c.id,
select: %{
order_id: o.id, # Field key must match this
customer_name: c.name, # Field key must match this
total_amount: o.total_amount
}
end
end
Field Configuration Rules
Basic Field Options
field_name: %{
label: "Display Name", # Always provide
sortable: true, # REQUIRED if field should be sortable
searchable: true, # REQUIRED if field should be searchable
component: custom_component # Optional, for custom rendering
}
Association Sorting (Custom Queries Only)
# When sorting by joined table fields
product_name: %{
label: "Product",
sortable: true,
assoc: {:order_items, :name} # Must match query alias and field
}
Filter Types
Boolean Filter
Boolean.new(:field_name, "param_name", %{
label: "Filter Label",
condition: dynamic([alias], alias.field_name > 0)
})
Range Filter
Range.new(:field_name, "param_name", %{
type: :number, # or :date
label: "Range Label",
min: 0,
max: 1000
})
Select Filter
Select.new({:table_alias, :field_name}, "param_name", %{
label: "Select Label",
options: [
%{label: "Display", value: ["actual_value"]},
%{label: "All Active", value: ["active", "pending"]}
]
})
Template Usage
Required Template Structure
# In your .html.heex template
<.live_table
fields={fields()}
filters={filters()}
options={@options} # Required
streams={@streams} # Required
/>
Common Error Patterns to Avoid
1. Field Key Mismatch
# Schema has 'email' field, but using wrong key
email_address: %{label: "Email"} # Wrong
email: %{label: "Email"} # Correct
2. Missing Data Provider for Custom Queries
# Wrong - Custom query without data provider
use LiveTable.LiveResource
def fields do
[complex_field: %{label: "Complex"}]
end
# Missing: data_provider assignment in mount/3
3. Schema with Custom Query
# Wrong - Using both schema and custom query
use LiveTable.LiveResource, schema: User
def mount(_params, _session, socket) do
socket = assign(socket, :data_provider, {App.Users, :custom_query, []})
end
Decision Tree for LLMs
When helping with LiveTable implementation:
Is it a single table query?
- YES → Use Pattern A (with
schema:
) - NO → Use Pattern B (custom data provider)
- YES → Use Pattern A (with
Are there joins or computed fields?
- YES → Must use Pattern B
- NO → Can use Pattern A
Do field keys match the data source?
- Schema pattern → Keys match schema fields
- Custom pattern → Keys match select clause
Are all required assets configured?
- Check deps, config, JS hooks, CSS imports
Is the template structure correct?
- Verify
fields()
,filters()
,@options
,@streams
- Verify
Quick Reference
Must-Have Functions
fields()
- Always requiredfilters()
- Optional but recommended
Must-Have Template Props
fields={fields()}
filters={filters()}
options={@options}
streams={@streams}
Must-Have Dependencies
{:live_table, "~> 0.3.1"}
(always required){:oban, "~> 2.19"}
(only if using exports)
Must-Have Config
- LiveTable repo and pubsub config (always required)
- Oban queue configuration (only if using exports)
- JavaScript hooks import
- CSS imports
This document ensures LLMs provide accurate, complete LiveTable implementations every time.