lvt) - Complete GuideThe lvt CLI is a Phoenix-inspired code generator for building LiveTemplate applications with CRUD functionality, authentication, and real-time features.
go install github.com/livetemplate/lvt/cmd/lvt@latest
Or build from source:
git clone https://github.com/livetemplate/lvt
cd lvt
go build -o lvt ./cmd/lvt
Verify installation:
lvt --help
# 1. Create a new application
lvt new myblog
cd myblog
# 2. Generate a CRUD resource
lvt gen posts title content published:bool
# 3. Run migrations (auto-generates database code)
lvt migration up
# 4. Run the app
go run cmd/myblog/main.go
# 5. Visit http://localhost:8080/posts
That's it! You have a fully functional CRUD application with:
lvt new <name>Creates a new LiveTemplate application.
Usage:
# Interactive mode (recommended for beginners)
lvt new
# Direct mode
lvt new myapp
# Specify kit (CSS framework)
lvt new myapp --kit multi # Tailwind CSS (default)
lvt new myapp --kit simple # Pico CSS
What it generates:
myapp/
├── cmd/myapp/main.go # Application entry point
├── go.mod # Go module with tools directive
├── internal/
│ ├── app/ # Handlers and templates
│ ├── database/
│ │ ├── db.go # Database connection
│ │ ├── schema.sql # Database schema
│ │ ├── queries.sql # SQL queries (for sqlc)
│ │ ├── sqlc.yaml # sqlc configuration
│ │ └── models/ # Generated code
│ └── shared/ # Shared utilities
├── web/assets/ # Static assets
└── README.md
Kit Options:
multi - Multi-page app with Tailwind CSS (default)single - Single-page app with Tailwind CSSsimple - Simple app with Pico CSSlvt gen <resource> <field:type>...Generates a full CRUD resource with database integration.
Usage:
# Interactive mode
lvt gen
# With explicit types
lvt gen users name:string email:string age:int
# With type inference (smart defaults)
lvt gen products name price quantity enabled created_at
# → Infers: name:string price:float quantity:int enabled:bool created_at:time
What it generates:
internal/app/{resource}/{resource}.go - CRUD handlerinternal/app/{resource}/{resource}.tmpl - UI templateinternal/app/{resource}/{resource}_test.go - E2E testsinternal/app/{resource}/{resource}_ws_test.go - WebSocket testsqueries.sqlmain.goFeatures:
Type Mappings:
| CLI Type | Go Type | SQL Type |
|---|---|---|
| string | string | TEXT |
| int | int64 | INTEGER |
| bool | bool | BOOLEAN |
| float | float64 | REAL |
| time | time.Time | DATETIME |
Relationships:
# Basic foreign key (ON DELETE CASCADE)
lvt gen comments post_id:references:posts author text
# Custom ON DELETE behavior
lvt gen audit_logs user_id:references:users:set_null action
# Multiple references
lvt gen likes user_id:references:users post_id:references:posts
# Restrict deletion
lvt gen invoices customer_id:references:customers:restrict amount:float
lvt gen view <name>Generates a view-only handler without database integration.
Usage:
# Interactive mode
lvt gen view
# Direct mode
lvt gen view dashboard
What it generates:
internal/app/{view}/{view}.go - View handlerinternal/app/{view}/{view}.tmpl - UI templateinternal/app/{view}/{view}_test.go - E2E testsinternal/app/{view}/{view}_ws_test.go - WebSocket testsmain.goUse cases:
lvt gen authGenerates a complete authentication system similar to Phoenix's mix phx.gen.auth.
Usage:
# Default: User struct, users table
lvt gen auth
# Custom struct name (table name auto-pluralized)
lvt gen auth Account # Creates Account struct, accounts table
# Custom struct and table names
lvt gen auth Admin admin_users # Creates Admin struct, admin_users table
# With feature flags
lvt gen auth --no-magic-link # Password only
lvt gen auth Account --no-email-confirm # Custom names + no confirmation
lvt gen auth Admin admin_users --no-password # Custom names + magic-link only
Flags:
--no-password - Disable password authentication--no-magic-link - Disable magic-link authentication--no-email-confirm - Disable email confirmation flow--no-password-reset - Disable password reset functionality--no-sessions-ui - Disable session management UI--no-csrf - Disable CSRF protection middlewareNote: At least one authentication method (password or magic-link) must be enabled.
What it generates:
internal/app/auth/auth.go - Complete auth handler with all flowsinternal/app/auth/auth.tmpl - LiveTemplate UI with Tailwind CSSinternal/app/auth/middleware.go - Route protection middlewareinternal/shared/password/password.go - Password hashing (bcrypt)internal/shared/email/email.go - Email sender interfaceinternal/database/migrations/YYYYMMDDHHMMSS_create_auth_tables.sql - Migrationinternal/database/queries.sqlDatabase Tables:
Default names (can be customized):
users (or custom table name) - User accounts (email, optional password)users_tokens (or {table}_tokens) - Tokens for magic links, email confirmation, password resetFeatures:
mix phx.gen.authgo.mod dependenciesNext Steps:
# 1. Run migrations
lvt migration up
# 2. Generate sqlc code
sqlc generate
# 3. Wire routes in main.go (see internal/app/auth/auth.go for examples)
# 4. Configure email sender (see internal/shared/email/email.go)
Example main.go setup:
import (
"yourapp/internal/app/auth"
"yourapp/internal/shared/email"
"github.com/livetemplate/livetemplate"
)
// Create auth handler
emailSender := email.NewConsoleEmailSender()
authHandler := auth.NewUserHandler(db, emailSender, "http://localhost:8080")
// Create template and register routes
tmpl, err := livetemplate.New("auth")
if err != nil {
log.Fatal(err)
}
if _, err := tmpl.ParseFiles("internal/app/auth/auth.tmpl"); err != nil {
log.Fatal(err)
}
http.Handle("/auth", tmpl.Handle(authHandler, livetemplate.AsState(&auth.State{})))
http.HandleFunc("/auth/logout", authHandler.HandleLogout)
http.HandleFunc("/auth/magic", authHandler.HandleMagicLinkVerify) // if magic-link enabled
http.HandleFunc("/auth/reset", authHandler.HandleResetPassword) // if password-reset enabled
http.HandleFunc("/auth/confirm", authHandler.HandleConfirmEmail) // if email-confirm enabled
// Protected route example
protectedHandler := authHandler.RequireAuth(http.HandlerFunc(myHandler))
http.Handle("/dashboard", protectedHandler)
Customizing CSS Framework:
The generated auth templates use Tailwind CSS by default. To use a different CSS framework (Bulma, Pico, or plain HTML), see the Auth Customization Guide for complete examples and instructions.
E2E Testing:
The auth command generates comprehensive E2E tests using chromedp that test all auth flows:
To run E2E tests:
# Requires Docker to run Chrome in a container
go test ./internal/app/auth -run TestAuthE2E -v
# Skip E2E tests in short mode
go test ./internal/app/auth -short
The E2E tests include:
lvt migration <command>Manages database migrations using Goose.
Commands:
# Apply all pending migrations (and run sqlc generate)
lvt migration up
# Rollback one migration
lvt migration down
# Show migration status
lvt migration status
# Create a new migration
lvt migration create add_user_roles
Auto-generated Migrations:
When you run lvt gen, migrations are automatically created:
lvt gen posts title content
# Creates: internal/database/migrations/20240315120000_create_posts.sql
Migration Format:
-- +goose Up
CREATE TABLE posts (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
content TEXT,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
-- +goose Down
DROP TABLE posts;
sqlc Integration:
lvt migration up automatically runs sqlc generate after applying migrations, ensuring your Go database code stays in sync.
lvt kits <command>Manages CSS framework kits.
Commands:
# List all available kits
lvt kits list
# Show kit information
lvt kits info tailwind
# Customize a kit for your project
lvt kits customize tailwind
# Customize globally (all projects)
lvt kits customize tailwind --global
# Validate kit structure
lvt kits validate .lvt/kits/tailwind
Available System Kits:
| Kit | Framework | Description |
|---|---|---|
| multi | Tailwind | Multi-page app (default) |
| single | Tailwind | Single-page app |
| simple | Pico CSS | Minimal semantic HTML |
Kits are complete starter packages that include:
Kits are loaded with this priority:
.lvt/kits/<name>/ (highest)~/.config/lvt/kits/<name>/This allows:
.lvt/kits/)~/.config/lvt/kits/)# 1. Copy kit to project
lvt kits customize multi
# 2. Edit templates
cd .lvt/kits/multi/templates
# Edit resource.go.tmpl, resource.tmpl, etc.
# 3. Generate with custom templates
lvt gen products name price
# Uses your customized templates
The CLI automatically infers types from field names:
lvt gen articles title content published_at author email price
# Infers: title=string, content=string, published_at=time,
# author=string, email=string, price=float
Inference Rules:
String (default):
name, title, description, email, username, url, slug, addressInteger:
age, count, quantity, views, likes, score, rank, year*_count, *_number, *_indexFloat:
price, amount, rating, latitude, longitude*_price, *_amount, *_rateBoolean:
enabled, active, published, verified, approved, deletedis_*, has_*, can_*Time:
created_at, updated_at, deleted_at, published_at*_at, *_date, *_timestr, text → stringinteger → intboolean → boolfloat64, decimal → floatdatetime, timestamp → timeEach generated resource includes comprehensive tests.
*_ws_test.go)Fast unit tests for WebSocket protocol:
# Run WebSocket tests
go test ./internal/app/users -run WebSocket
# Features:
# - Dynamic port allocation
# - WebSocket connection testing
# - CRUD action testing
# - Server log capture
# - Fast execution (~2-5 seconds)
*_test.go)Full browser tests with Chromedp:
# Run E2E tests
go test ./internal/app/users -run E2E
# Features:
# - Real browser interactions
# - Visual verification
# - Screenshot capture
# - Console log access
# - Comprehensive (~20-60 seconds)
go test -short ./...
Generated apps follow idiomatic Go conventions:
myapp/
├── cmd/myapp/main.go # Application entry point
├── go.mod # Go module
├── internal/
│ ├── app/ # Handlers and templates (co-located!)
│ │ ├── posts/
│ │ │ ├── posts.go # Handler
│ │ │ ├── posts.tmpl # Template
│ │ │ ├── posts_test.go # E2E tests
│ │ │ └── posts_ws_test.go # WebSocket tests
│ │ └── users/
│ ├── database/
│ │ ├── db.go # Database connection
│ │ ├── migrations/ # Migration files
│ │ ├── queries.sql # SQL queries (sqlc)
│ │ ├── sqlc.yaml # sqlc config
│ │ └── models/ # Generated code
│ └── shared/ # Shared utilities
│ ├── password/ # Password hashing
│ └── email/ # Email sender
└── web/assets/ # Static assets
Key Design Decisions:
internal/ prevents external imports# 1. Create app
lvt new myapp
cd myapp
# 2. Generate resources
lvt gen users name email
lvt gen posts title content user_id:references:users
# 3. Run migrations (auto-generates DB code)
lvt migration up
# 4. Run tests
go test ./...
# 5. Run app
go run cmd/myapp/main.go
# Add a field to existing resource
lvt migration create add_users_bio
# Edit migration file to add bio column
# Run migration
lvt migration up
# Update queries.sql to include bio
# Update handler and template
# Test changes
go test ./internal/app/users
Begin with core resources, add features incrementally:
lvt new blog
cd blog
lvt gen posts title content # Start here
lvt gen comments post_id:references:posts author text # Add later
Let the CLI infer types for common fields:
# Instead of:
lvt gen users name:string email:string created_at:time
# Do this:
lvt gen users name email created_at
Run tests after each change:
go test ./...
Copy and modify templates for your needs:
lvt kits customize multi
cd .lvt/kits/multi/templates
# Edit templates
Always use migrations for schema changes:
lvt migration create add_user_roles
# Edit migration file
lvt migration up
If creating an app inside an existing Go workspace:
GOWORK=off go run cmd/myapp/main.go
Check migration status:
lvt migration status
Rollback if needed:
lvt migration down
Manually run sqlc:
sqlc generate
Run with verbose output:
go test -v ./internal/app/users
lvt new myblog
cd myblog
lvt gen posts title content published:bool
lvt gen categories name description
lvt gen comments post_id:references:posts author text
lvt migration up
go test ./...
go run cmd/myblog/main.go
lvt new mystore
cd mystore
lvt gen products name price:float stock:int
lvt gen customers name email
lvt gen orders customer_id:references:customers total:float
lvt migration up
go test ./...
go run cmd/mystore/main.go
lvt new mysocial
cd mysocial
# Generate auth first
lvt gen auth
lvt gen profiles user_id:references:users bio avatar_url
lvt gen posts user_id:references:users content
lvt gen likes user_id:references:users post_id:references:posts
lvt migration up
go test ./...
go run cmd/mysocial/main.go
lvt gen authFor more information: