Advanced Features

This guide covers Tenrankai’s advanced features for power users and cloud deployments.

Admin UI

Tenrankai includes a built-in web-based administration interface for managing users, viewing galleries, and configuring permissions without editing files.

Accessing the Admin UI

The Admin UI is available at /_admin/ and requires:

  • Authentication (must be logged in)
  • owner_access permission in any gallery

Features

User Management:

  • View all registered users
  • Create new users
  • Delete users
  • Send login invitation emails (72-hour expiry)

Gallery Management:

  • See all configured galleries
  • View gallery permissions and role assignments
  • See folder structures and image counts
  • Configure watermarks (text and PNG image)
  • Enable/disable tile zoom
  • Adjust gallery settings with live reload

Role Viewer:

  • View built-in roles and their permissions
  • See permission groups organized by category

Admin API

The Admin UI communicates with a REST API that you can also use programmatically:

# List all sites
curl -H "Cookie: session=..." https://example.com/_admin/api/sites

# Get site configuration
curl -H "Cookie: session=..." https://example.com/_admin/api/sites/default

# List galleries for a site
curl -H "Cookie: session=..." https://example.com/_admin/api/sites/default/galleries

# Get/update permissions
curl -H "Cookie: session=..." https://example.com/_admin/api/sites/default/permissions

# Reload site configuration
curl -X POST -H "Cookie: session=..." https://example.com/_admin/api/sites/default/reload

See the API Reference for complete Admin API documentation.

Theme Editor

The Admin UI includes a visual theme editor for customizing colors and fonts without editing CSS files.

Accessing the Theme Editor

Navigate to /_admin/theme (requires admin access). The editor provides:

  • Dark/Light Mode Tabs: Customize colors for each mode independently
  • Color Pickers: Visual color selection with hex input
  • Font Selectors: Choose from 42 curated Google Fonts
  • Force Color Scheme: Lock users to dark or light mode
  • Reset to Defaults: Restore original theme

Customizable Colors

Color VariableDescription
Background PrimaryMain page background
Background SecondaryAlternate sections
Background CardCard and panel backgrounds
Background HoverHover state backgrounds
Header BackgroundSite header
Text PrimaryMain text color
Text SecondarySecondary text
Text MutedSubtle text, captions
Link ColorLink text
Link HoverLink hover state
Border ColorBorders and dividers
Accent ColorHighlights and accents
Danger ButtonDelete/destructive actions

Font Options

Three font categories can be customized:

  • Body Font: Main content text
  • Heading Font: Titles and headers
  • Monospace Font: Code blocks and technical text

Fonts are organized by style: Sans-serif, Serif, Slab Serif, Display, Script, Rounded, and Monospace. The editor shows a live preview of each font before selection.

Force Color Scheme

Override user preferences to lock the site to a specific theme:

  • User Choice (default): Respects system preference and manual toggle
  • Always Dark: Forces dark mode for all visitors
  • Always Light: Forces light mode for all visitors

How It Works

  1. Changes are saved to the site’s configuration storage
  2. Site automatically reloads to apply changes
  3. Theme CSS is generated dynamically at /theme.css
  4. Cache-busting ensures browsers receive updated styles

Theme API

# Get current theme
curl -H "Cookie: session=..." https://example.com/_admin/api/theme

# Update theme
curl -X PUT -H "Cookie: session=..." \
  -H "Content-Type: application/json" \
  -d '{"dark":{"bg_primary":"#1a1a2e"},"font_body":"Inter"}' \
  https://example.com/_admin/api/theme

# Reset to defaults
curl -X DELETE -H "Cookie: session=..." https://example.com/_admin/api/theme

Manual CSS Override

For advanced customization beyond the theme editor, create theme-override.css in your static directory:

:root {
  --custom-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

[data-theme="dark"] {
  --bg-primary: #0d1117;
}

The theme editor and manual overrides work together - editor changes are applied first, then theme-override.css additions.

S3 Storage Support

Tenrankai supports Amazon S3 for storing galleries, caches, templates, and static files.

S3 URL Format

Use S3 URLs anywhere a path is accepted:

s3://bucket-name/prefix?region=us-west-2

Configuration Examples

Hybrid: Local Source, S3 Cache (Recommended):

# In gallery TOML file
name = "photos"
source_directory = "photos"
cache_directory = "s3://my-bucket/cache?region=us-west-2"

Full S3 Gallery:

# In gallery TOML file
name = "archive"
source_directory = "s3://my-bucket/photos?region=us-west-2"
cache_directory = "s3://my-bucket/cache?region=us-west-2"

Static Files with Redirects (in site.toml):

static_files = ["s3://my-bucket/static?region=us-west-2"]
# static_use_redirects = true  # Direct S3 downloads

Templates with S3 Fallback (in site.toml):

templates = ["templates-local", "s3://my-bucket/templates"]

AWS Credentials

Tenrankai uses the standard AWS credential chain:

  1. Environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
  2. AWS credentials file (~/.aws/credentials)
  3. IAM role (EC2, ECS, Lambda)

For production on AWS, use IAM roles.

S3 Components

ComponentS3 SupportNotes
Gallery SourceImages from S3
Gallery CacheProcessed images
Static FilesWith signed URL redirects
TemplatesMulti-directory support
PostsMarkdown from S3

Performance Tips

  1. Use hybrid config: Local source + S3 cache
  2. Enable redirects: Reduces server bandwidth for static files
  3. Pre-generate cache: Warm S3 cache before deployment
  4. Choose nearby region: Lower latency

Multi-Site Virtual Hosting

Run multiple independent sites from a single Tenrankai instance, each with its own domain, templates, galleries, and settings.

Overview

Virtual hosting allows:

  • Multiple domains: Serve different sites on different hostnames
  • Per-site isolation: Each site has its own templates, static files, galleries, and posts
  • Hot reload: Update configuration without downtime via Admin API or SIGHUP
  • Wildcard subdomains: Match patterns like *.clients.example.com

Directory Structure

Multi-site uses the ConfigStorage directory structure with one directory per site:

config.d/
└── sites/
    ├── default/              # Default site (catch-all)
    │   ├── site.toml
    │   ├── permissions.toml
    │   └── galleries/
    │       └── main.toml
    ├── photos/               # Portfolio site
    │   ├── site.toml
    │   ├── permissions.toml
    │   └── galleries/
    │       └── portfolio.toml
    └── blog/                 # Blog site
        ├── site.toml
        └── posts/
            └── articles.toml

Setting Up Multi-Site

Bootstrap config (config.toml):

[server]
host = "0.0.0.0"
port = 3000

[app]
name = "Multi-Site Gallery"
cookie_secret = "CHANGE_ME_generate_with_openssl_rand_base64_32"
config_storage = "config.d"

Default site (config.d/sites/default/site.toml):

hostnames = ["*"]
templates = ["templates"]
static_files = ["static"]

Default gallery (config.d/sites/default/galleries/main.toml):

name = "main"
url_prefix = "/gallery"
source_directory = "photos"
cache_directory = "cache/default/main"

Portfolio site (config.d/sites/photos/site.toml):

hostnames = ["photos.example.com"]
templates = ["templates-photos", "templates"]
static_files = ["static"]

Portfolio gallery (config.d/sites/photos/galleries/portfolio.toml):

name = "portfolio"
url_prefix = "/"
source_directory = "portfolio"
cache_directory = "cache/photos"
image_indexing = "unique_id"

Blog site (config.d/sites/blog/site.toml):

hostnames = ["blog.example.com"]
templates = ["templates-blog", "templates"]
static_files = ["static"]

Blog posts (config.d/sites/blog/posts/articles.toml):

name = "articles"
url_prefix = "/"
source_directory = "blog-posts"

CLI Setup

Use the CLI to create sites without editing files:

# Initialize ConfigStorage
tenrankai config init config.d

# Add a new site
tenrankai config add-site photos --hostname photos.example.com

# Add a gallery to the site
tenrankai config add-gallery portfolio --site photos \
  --source portfolio --url-prefix /

# Add another site for blog
tenrankai config add-site blog --hostname blog.example.com
tenrankai config add-posts articles --site blog \
  --source blog-posts --url-prefix /

Hostname Matching

Hostnames are matched in priority order:

  1. Exact match (highest): photos.example.com
  2. Glob pattern: *.clients.example.com
  3. Default catch-all: *

Configure hostnames in each site’s site.toml:

# Exact hostnames
hostnames = ["example.com", "www.example.com"]

# Wildcard subdomain
hostnames = ["*.clients.example.com"]

# Catch-all default
hostnames = ["*"]

Per-Site User Databases

Each site can have its own user authentication by setting user_database in site.toml:

# config.d/sites/photos/site.toml
hostnames = ["photos.example.com"]
user_database = "users-photos.toml"

# config.d/sites/clients/site.toml
hostnames = ["*.clients.example.com"]
user_database = "users-clients.toml"

Client Delivery Example

Serve client galleries on wildcard subdomains with authentication.

Site config (config.d/sites/clients/site.toml):

hostnames = ["*.clients.example.com"]
user_database = "users-clients.toml"
templates = ["templates-clients", "templates"]
static_files = ["static"]

Gallery config (config.d/sites/clients/galleries/delivery.toml):

name = "delivery"
url_prefix = "/"
source_directory = "clients"
cache_directory = "cache/clients"

Permissions (config.d/sites/clients/permissions.toml):

public_role = "none"
default_authenticated_role = "viewer"

[roles.viewer]
name = "Viewer"

[roles.viewer.permissions]
can_view = true
can_download_large = true

Hot Reloading

Update configuration without restarting:

# Via Admin API
curl -X POST -H "Cookie: session=..." \
  https://example.com/_admin/api/sites/default/reload

# Or send SIGHUP
kill -HUP $(pgrep tenrankai)

What can be hot-reloaded:

  • Add/remove sites
  • Modify site hostnames
  • Add/remove galleries or posts
  • Change templates or static files
  • Update gallery settings

What requires restart:

  • Server host/port changes

AI Image Analysis

Tenrankai integrates with OpenAI Vision to automatically generate keywords and alt-text.

Configuration

[openai]
api_key = "sk-your-openai-api-key"
model = "gpt-5.2"
rate_limit_ms = 1000      # Delay between API calls
max_tokens = 300          # Max response tokens

# Optional: Background processing
enable_background_analysis = true
background_interval_minutes = 60
background_batch_size = 50

CLI Commands

# Analyze all images in a gallery
tenrankai analyze-images -g photos

# Analyze specific folder
tenrankai analyze-images -g photos -f "2026-vacation"

# Limit images per run
tenrankai analyze-images -g photos --limit 100

# Preview what would be analyzed
tenrankai analyze-images -g photos --dry-run

# Force re-analyze already processed images
tenrankai analyze-images -g photos --force

# Clear AI-generated data
tenrankai clear-analysis -g photos
tenrankai clear-analysis -g photos -f "folder" --dry-run

What Gets Generated

  • Keywords: Descriptive tags extracted from image content
  • Alt-text: Accessibility descriptions for screen readers

Data is stored in image metadata sidecars and displayed in the gallery.

CLI Tools

Server Commands

# Start server
tenrankai serve
tenrankai serve --config custom.toml
tenrankai serve --port 8080 --host 0.0.0.0

# Auto-shutdown (for testing)
tenrankai serve --quit-after 10

# Debug logging
tenrankai --log-level debug serve

User Management

# Add user (username and email)
tenrankai user add jane jane@example.com

# List users
tenrankai user list

# Update a user's email
tenrankai user update jane newemail@example.com

# Remove user
tenrankai user remove jane

Site Administration

# Add a site admin
tenrankai admin add alice

# List site admins
tenrankai admin list

# Remove a site admin
tenrankai admin remove alice

# Specify a site (for multi-site deployments)
tenrankai admin add alice --site photos

Cache Management

# View cache coverage report
tenrankai cache report -g photos

# Clean outdated cache files
tenrankai cache cleanup -g photos

# Invalidate specific entries (force regeneration)
tenrankai cache invalidate -g photos -t image -p "IMG_001.jpg"
tenrankai cache invalidate -g photos -t composite -p "folder-path"

# Invalidate all images in a folder (useful after replacing photos)
tenrankai cache invalidate -g photos -t folder -p "2026-vacation"
tenrankai cache invalidate -g photos -t folder -p "2026-vacation" --dry-run

# List cached composite images
tenrankai cache list-composites -g photos

Cache invalidation types:

  • image: Single image (all sizes/formats)
  • composite: Folder preview composite image
  • folder: All images in a folder (thumbnails, gallery, medium, large)

AVIF Debugging

# Analyze AVIF metadata
tenrankai avif-debug image.avif

# Verbose output
tenrankai avif-debug image.avif --verbose

Shows:

  • Dimensions and file size
  • Color space properties
  • HDR detection
  • Gain map presence
  • ICC profile info

HEIC/HEIF Support

Tenrankai natively supports HEIC/HEIF images (iPhone photos) with full HDR pipeline:

  • Apple Photos: Direct support for iPhone HEIC files
  • HDR Preservation: Gain maps extracted and converted to AVIF format
  • Metadata: Full EXIF extraction (camera, GPS, dates)
  • Color Profiles: ICC profiles preserved through processing

HEIC images are automatically converted to web-friendly formats (WebP, AVIF, JPEG) while preserving HDR data when outputting to AVIF.

Multi-File Image Support

Associate multiple files with a single gallery image for RAW workflows and version management.

RAW File Association

Place RAW files alongside processed images:

photos/
├── IMG_0001.jpg      # Displayed in gallery
├── IMG_0001.dng      # Associated RAW (downloadable)
├── IMG_0002.arw      # Sony RAW
└── IMG_0002.jpg      # Processed version

Supported RAW formats: .dng, .arw, .crw, .cr2, .cr3, .nef, .orf, .raf, .rw2, .pef, .srw

Users with can_download_raw permission see a RAW download button.

Image Versions

Track multiple versions using suffixes or a versions folder:

Version Suffixes:

photos/
├── IMG_0001.jpg       # Primary (displayed)
├── IMG_0001_v1.jpg    # Previous version
└── IMG_0001_v2.jpg    # Older version

Versions Folder:

photos/
├── IMG_0001.jpg           # Primary (displayed)
└── __versions/
    ├── IMG_0001.jpg       # Previous version (by mod time)
    └── IMG_0001_v1.jpg    # Explicit version

Users with can_see_versions permission see a version picker to navigate between versions.

Hidden Folders

Folders prefixed with __ are hidden from navigation but accessible for internal use:

photos/
├── vacation/          # Visible folder
└── __versions/        # Hidden (for version storage)

Inline Content Editing

Edit folder and image descriptions directly in the gallery UI.

Users with can_edit_content permission see edit buttons to modify:

  • Folder descriptions: Title and markdown description
  • Image descriptions: Title and caption

The editor supports:

  • Rich text mode with formatting toolbar
  • Raw markdown editing mode
  • Bold, italic, headings, lists, quotes, code, links

Changes are saved to the markdown sidecar files (_folder.md or image.jpg.md).

Enhanced Metadata Sources

Tenrankai reads metadata from multiple sources with priority:

1. Markdown Sidecar (Highest Priority)

Create IMG_001.jpg.md:

+++
title = "Sunset at Big Sur"
description = "Golden hour magic on the coast"
tags = ["sunset", "landscape", "california"]

# Astrophotography fields
telescope = "Celestron NexStar 8SE"
mount = "EQ6-R Pro"
filters = "Ha, OIII, SII"
total_exposure_hours = 12.5
ra = "05:34:31.94"
dec = "+22:00:52.2"
+++

Extended description with **markdown** formatting.

2. XMP Sidecar

Adobe Lightroom compatible. Create IMG_001.jpg.xmp with standard XMP metadata.

3. EXIF Data (Lowest Priority)

Embedded in image files. Automatically extracted for camera, lens, GPS, timestamps.

Zoom Features

Desktop: Click-to-Zoom Loupe

With can_use_zoom permission:

  • Click and hold to activate
  • 1.8x magnification using medium image
  • Custom cursor indicates availability

With can_use_tile_zoom permission:

  • Full resolution tile-based zoom
  • Requires [tiles] configuration in gallery TOML

Mobile: Pinch-to-Zoom

With can_use_zoom permission:

  • Native pinch gesture
  • Double-tap to quick zoom
  • Pan when zoomed
  • Fullscreen modal with zoom indicator
  • Automatic tile loading at high zoom levels

Configuration

In gallery TOML file:

[tiles]
tile_size = 1024

[pregenerate]
tiles = true  # Pre-generate tiles

In permissions.toml:

[roles.member.permissions]
can_use_zoom = true       # Basic zoom
can_use_tile_zoom = true  # Enhanced tile zoom

Cache Pre-Generation

Pre-generate cache on startup for instant loading (in gallery TOML file):

[pregenerate]
formats = { jpeg = true, webp = true, avif = false }
sizes = { thumbnail = true, gallery = true, medium = true, large = false }
tiles = false

Features:

  • Parallel processing: Uses all CPU cores
  • Memory-safe: Limits concurrent operations
  • Incremental: Only generates missing files
  • Graceful shutdown: Clean exit on Ctrl+C
  • Progress logging: Detailed server output

Image URL Indexing

Control how images are referenced in URLs:

# In gallery TOML file
image_indexing = "filename"  # or "sequence" or "unique_id"
ModeExampleUse Case
filename/gallery/image/IMG_001.jpgSEO, debugging
sequence/gallery/image/1Clean portfolios
unique_id/gallery/image/a3k2xPrivacy, clients

unique_id generates non-guessable 6-character IDs.

Hidden Folders

Hide folders from navigation while keeping them accessible:

+++
title = "Private Preview"
hidden = true
+++

Hidden folders:

  • Don’t appear in folder listings
  • Accessible via direct URL
  • Perfect for sharing with select people

Hide Technical Details

Remove camera/EXIF info per folder:

+++
title = "Client Portfolio"
hide_technical_details = true
+++

Hides:

  • Camera make/model
  • Lens information
  • Technical settings (ISO, aperture, shutter)
  • GPS coordinates

Image Preloading

Adjacent images are automatically preloaded:

  • Next and previous images load in background
  • Retina (@2x) versions included
  • Navigation feels instant

No configuration required.

Next Steps