Created database initialization script following the core stack pattern.
The script automatically creates required databases on first initialization:
- openwebui: Open WebUI application database
- litellm: LiteLLM proxy database for API key management and tracking
Changes:
- Created ai/postgres/init/01-init-databases.sh
- Mounted init directory in ai_postgres service
- Added automatic privilege grants to AI_DB_USER
Note: Init script only runs on first database creation when volume is empty.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
LiteLLM now uses the ai_postgres database instance with a dedicated
'litellm' database for API key management, usage tracking, and rate limiting.
Changes:
- Set DATABASE_URL to postgresql://ai:password@ai_postgres:5432/litellm
- Added depends_on ai_postgres to ensure DB starts first
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removed authentication middleware to simplify access. LiteLLM now relies
solely on Bearer token authentication via LITELLM_MASTER_KEY.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Re-enabled LITELLM_MASTER_KEY for proper API key authentication.
LiteLLM supports master key without database for simple auth scenarios.
- LiteLLM validates Bearer token against master key
- Open WebUI uses same key for internal communication
- External access requires both HTTP Basic Auth + API key
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removed LITELLM_MASTER_KEY as it requires a database for virtual key
management. Security is already provided by HTTP Basic Auth on the
public Traefik endpoint. Internal Open WebUI communication doesn't
need additional API key auth.
Security layers:
- Public access: HTTP Basic Auth via Traefik
- Internal LiteLLM: Network isolation (no auth needed)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added AI_LITELLM_API_KEY environment variable to .env
- Configured LiteLLM MASTER_KEY for authentication
- Updated Open WebUI to use secure API key from environment
- Generated secure 64-character hex key: sk-77b42236...
This replaces the insecure hardcoded sk-1234 key with proper
secret management via environment variables.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Healthcheck was failing because curl is not installed in the LiteLLM
container, causing Traefik to mark it as unhealthy and not route traffic.
Disabled healthcheck as Traefik doesn't require it for routing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
LiteLLM was binding to localhost by default, making it unreachable
from Traefik reverse proxy. Added --host 0.0.0.0 parameter to allow
connections from the Docker network.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added Traefik configuration to make LiteLLM accessible at llm.ai.pivoine.art
for use with @openai/codex CLI tool.
Changes:
- Added AI_LITELLM_TRAEFIK_HOST to arty.yml (llm.ai.pivoine.art)
- Updated ai/compose.yaml litellm service with full Traefik labels
- HTTP to HTTPS redirect
- SSL termination via Let's Encrypt
- Compression and security headers
This allows external tools like Codex to use Claude models via
OpenAI-compatible API endpoint.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Removed miniPaint image editor service from the kit stack:
- Deleted paint service definition from kit/compose.yaml
- Removed Dockerfile for paint build
- Removed KIT_PAINT_TRAEFIK_HOST from arty.yml
- Stopped and removed kit_paint container
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Paint service uses a custom Dockerfile build from GitHub, so it shouldn't
be auto-updated by Watchtower. Set watchtower.enable=false explicitly.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Watchtower was failing with "Unknown notification type 'mattermost'" because
'mattermost' is not a valid WATCHTOWER_NOTIFICATIONS value. When using
Shoutrrr URLs (WATCHTOWER_NOTIFICATION_URL), the notification type should
be set to 'shoutrrr' or left empty, as the service type is inferred from
the URL format (mattermost://...).
Changed WATCHTOWER_NOTIFICATIONS from 'mattermost' to 'shoutrrr' to fix
the fatal error that was occurring every minute.
The mattermost:// Shoutrrr URL in WATCHTOWER_NOTIFICATION_URL is correct
and will work once the notification type is fixed.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Netdata v2.7 doesn't natively support Mattermost notifications, but
Mattermost supports Slack-compatible webhooks. Changed configuration to
use SEND_SLACK with SLACK_WEBHOOK_URL pointing to the Mattermost webhook.
Configuration changes:
- Changed SEND_MATTERMOST="YES" to SEND_SLACK="YES"
- Changed MATTERMOST_WEBHOOK_URL to SLACK_WEBHOOK_URL
- Updated role_recipients_mattermost to role_recipients_slack
- Webhook URL still uses ${MATTERMOST_WEBHOOK_URL} env var from .env
Tested with: alarm-notify.sh test
Result: All three alarm types (WARNING, CRITICAL, CLEAR) show "OK"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Remove all theme customization code:
- Removed theme directory (custom.css, custom.js, favicon.svg)
- Removed app.html.heex template override
- Removed Dockerfile for custom build
- Reverted compose.yaml to only mount custom.exs for SMTP config
Keeping only SMTP configuration in custom.exs.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Mount app.html.heex template with custom theme links:
- Custom CSS at /assets/custom.css via Routes.static_path()
- Custom favicon at /images/favicon-custom.svg
Phoenix will use the external template file instead of compiled version.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
static_paths only includes: assets, fonts, images, js
The css directory is NOT served by Phoenix.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The Plug was causing AsciinemaWeb.Endpoint to fail on startup.
Reverting to just SMTP configuration while we find a proper way
to inject custom theme.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Mount custom CSS, favicon, and JS into static directories
- Create custom.js to inject theme CSS and favicon via JavaScript
- Add CustomThemeInjector Plug in custom.exs to inject script tag
- Custom theme features:
- Pivoine rose primary color (#CE275B)
- Gray tone backgrounds
- Custom SVG favicon with rose gradient
- Bootstrap 4 component overrides
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added explicit overrides for body, main, and pre elements to prevent
default light gray (#f7f7f7) backgrounds from showing through.
- Body and main: metal-bg-base (dark)
- Pre/code blocks: metal-bg-elevated (slightly lighter)
- Main container: metal-bg-surface with proper spacing
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Refined the metal gray palette for better consistency and polish:
- Renamed variables to semantic names (base, elevated, surface, interactive, input)
- Reduced color range from 10%-30% to 16%-28% for smoother transitions
- Adjusted saturation to 10-12% for more cohesive palette
- Softened shadows and reduced motion for subtle elegance
- Added distinct heading area background for better hierarchy
- Improved button states with smoother hover transitions
- Refined border weights (1px default, 2px for accents)
- Updated all components to use new semantic variable names
Color hierarchy:
- metal-bg-base (16%): Body, terminal, code blocks
- metal-bg-elevated (19%): Header, footer, control bars, headings
- metal-bg-surface (22%): Cards, tables
- metal-bg-interactive (25%): Buttons, pagination
- metal-bg-input (28%): Form inputs
- metal-border (32%): Subtle borders
- metal-border-strong (40%): Accent borders
Rose accents preserved for all interactive elements.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Updated color palette to use multiple metal gray shades for visual hierarchy
- Kept original Pivoine rose accent colors for borders, links, and highlights
- Background variations:
- Darkest (10%): Body, terminal player, code blocks
- Darker (15%): Header/navbar, table headers
- Dark (18%): Footer, control bars
- Base (22%): Filter buttons, pagination
- Light (26%): Cards, tables, recording items
- Lighter (30%): Form inputs
- Border (35%): Borders and separators
- All rose accents preserved for visual pop on dark metal backgrounds
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>