# Binexia > Developer documentation for Binexia — Universal Business Intelligence OS This document contains the full content of all documentation pages for AI consumption. --- ## Binexia Developer Documentation **URL:** https://docs.binexia.dev/docs **Description:** Universal Business Intelligence OS — developer documentation for building, deploying, and operating Binexia. Binexia is a vertical SaaS platform that provides five universal intelligence capabilities to businesses across domains: | Capability | What it does | |---|---| | **Knowledge RAG** | Upload documents, ask questions, get grounded answers | | **Text-to-SQL** | Ask questions in plain language, get charts and tables | | **Behavioral Scoring** | Automated churn risk and upsell opportunity detection | | **Document Extraction** | Structured field synthesis from uploaded documents | | **Proactive Agents** | Scheduled anomaly detection, forecasting, and alerting | The same platform serves different verticals (travel, manufacturing, legal, veterinary, logistics) by changing only the semantic model configuration. The code is identical — only the data and business terms change. ## Architecture at a Glance ``` Browser └─► Nuxt 3 Frontend (port 6080) └─► Laravel 12 API (port 6081) ├─► PostgreSQL 16 (5 schemas per tenant) ├─► Redis 7 (cache, queue, sessions) ├─► Agno FastAPI (port 8001) ─► LLM providers ├─► Dify (knowledge pipeline) ├─► MinIO (document storage) └─► Metabase (embedded BI dashboards) ``` ## Start Here --- ## Agno API **URL:** https://docs.binexia.dev/docs/api-reference/agno-api **Description:** FastAPI agent runtime endpoints — the intelligence layer. The Agno FastAPI service runs the agent runtime. Laravel calls these endpoints internally over Docker network DNS. All requests require `X-Agno-Key: {AGNO_API_KEY}` header. **Base URL (internal):** `http://ubios_agno:8001` (ip-test) or `http://agno-api:8001` (production) ## Agent Queries ### POST /query Primary endpoint for user-initiated questions. OrchestratorAgent classifies intent and routes to specialist. **Request:** | Field | Type | Required | Notes | |---|---|---|---| | `question` | string | yes | Natural language question | | `user_id` | UUID | yes | For session logging | | `session_context` | object | no | Previous messages for multi-turn | | `response_format` | string | no | `text`, `table`, `chart`, `auto` (default: `auto`) | **Response:** | Field | Type | Notes | |---|---|---| | `answer` | string | Natural language answer | | `agent_used` | string | Which specialist handled it | | `source` | string | `redis_cache`, `saved_query`, `generated`, `rag` | | `data` | object | Structured data (table/chart) | | `sql_used` | string | SQL executed (AnalyticsAgent only) | | `citations` | array | Source references (KnowledgeAgent only) | | `confidence` | float | 0–1 | | `suggested_questions` | array | 3 follow-up questions | | `session_id` | UUID | For multi-turn conversation | | `duration_ms` | integer | | ### POST /context Context panel data when user clicks a dashboard element. Target: under 1.5 seconds. **Request:** | Field | Type | Required | Notes | |---|---|---|---| | `click_type` | string | yes | `entity`, `metric`, `alert` | | `entity_type` | string | conditional | Required for `entity` clicks | | `entity_id` | UUID | conditional | Required for `entity` clicks | | `metric_name` | string | conditional | Required for `metric` clicks | | `period` | string | conditional | Time period for metric clicks | | `agent_output_id` | UUID | conditional | Required for `alert` clicks | **Response:** | Field | Type | Notes | |---|---|---| | `title` | string | Context panel headline | | `explanation` | string | 2–4 sentence explanation | | `key_signals` | array | `{label, value, trend}` objects | | `recommended_action` | string | What to do (optional) | | `suggested_questions` | array | 3 drill-down questions | | `confidence` | float | | ## Document Extraction ### POST /extract Trigger document extraction. Returns immediately — poll status with `job_id`. **Request:** | Field | Type | Required | Notes | |---|---|---|---| | `document_id` | UUID | yes | FK to `tenant_data.documents` | | `storage_path` | string | yes | MinIO/S3 path | | `mime_type` | string | yes | | | `document_type` | string | yes | `invoice`, `contract`, `delivery_note`, etc. | | `force_ocr` | boolean | no | Skip Docling, use Mistral OCR | | `force_table` | boolean | no | Route to PaddleOCR for table-heavy documents | **Response:** `{ job_id, estimated_seconds }` ### GET /extract/status/:job_id **Response:** | Field | Type | Notes | |---|---|---| | `status` | string | `queued`, `parsing`, `extracting`, `validating`, `completed`, `failed`, `review_required` | | `progress` | integer | 0–100 | | `fields_extracted` | integer | | | `fields_flagged` | integer | Low-confidence fields | | `error` | string | On failure only | ## Behavioral Scoring ### POST /score Trigger scoring for one or more entities. **Request:** | Field | Type | Required | Notes | |---|---|---|---| | `entity_type` | string | yes | e.g. `customer` | | `entity_ids` | array | no | Empty = score all | | `goal_id` | UUID | no | Empty = all active goals | | `force_refresh` | boolean | no | Ignore Redis cache | **Response:** `{ job_id, entities_queued }` ## Web Crawling ### POST /crawl Scrape, crawl, or map a URL via self-hosted Firecrawl. Requires `--profile web` Docker profile. **Request:** | Field | Type | Required | Notes | |---|---|---|---| | `url` | string | yes | URL to crawl | | `mode` | string | no | `scrape` (default), `crawl`, `map` | | `limit` | integer | no | Max pages for crawl mode (default: 10) | | `max_depth` | integer | no | Crawl depth (default: 2) | **Response:** | Field | Type | Notes | |---|---|---| | `url` | string | The requested URL | | `mode` | string | Which mode was used | | `pages` | array | `[{url, markdown, title}]` for scrape/crawl, `[{url}]` for map | | `total_pages` | integer | Number of pages returned | | `duration_ms` | integer | | **Modes:** - `scrape` — Single page, returns markdown + metadata - `crawl` — Multi-page, follows links up to `limit` and `max_depth` - `map` — URL discovery only, no content fetched ## Widget Rendering ### POST /widget/render Render widget data. Cache/template hits return in under 100ms. No LLM call for any standard widget. **Request:** | Field | Type | Required | Notes | |---|---|---|---| | `widget_type` | string | yes | `kpi_card`, `metric_chart`, `top_n_table`, `call_list`, `alert_feed`, `raw_query`, `report` | | `config` | object | yes | Widget-specific configuration | | `role` | string | no | `admin`, `manager`, `viewer` | **Response:** `{ widget_type, data, source, duration_ms }` `source` values: `template` (pre-computed), `cache` (Redis), `generated` (LLM, admin testing only), `pre_computed` (from agent_outputs). ### GET /widget/suggest Suggest widget configurations based on the semantic model. Admin-only. **Response:** `{ suggestions: [{ widget_type, config, preview_description }] }` ## Templates ### POST /templates/render Render a saved query template with parameters. ### POST /templates/suggest Suggest templates based on the semantic model. ### POST /templates/chat Chat about template modifications. ### POST /templates/evaluate Evaluate a template against test data. ### POST /templates/summarize Summarize template results. ## System ### GET /health **Response:** | Field | Type | Notes | |---|---|---| | `status` | string | `ok`, `degraded`, `unavailable` | | `database` | string | `ok`, `error` | | `redis` | string | `ok`, `error` | | `llm_providers` | object | `provider_name: 'ok' or 'error'` per provider | | `version` | string | Agno version | | `uptime_seconds` | integer | | ### POST /schema/refresh Re-sync `schema_context` from live database DDL. **Response:** `{ tables_synced, columns_synced, duration_ms }` ### GET /traces/:trace_id Retrieve a query trace for debugging. ### POST /config/reload Reload configuration from database. ### GET /metrics Prometheus-format metrics for monitoring. ## Error Format All errors return HTTP 4xx/5xx with: ```json { "error": "string description", "error_code": "AGENT_TIMEOUT | SCHEMA_NOT_FOUND | LLM_FAILURE | VALIDATION_FAILED", "retry_possible": true, "details": {} } ``` --- ## Environment Variables **URL:** https://docs.binexia.dev/docs/api-reference/environment-variables **Description:** Every environment variable for every service, grouped by service. All configuration is through environment variables. No secrets in code. Required variables have no default and will cause startup failure. Optional variables have working defaults. ## Laravel Application ### Core | Variable | Required | Default | Notes | |---|---|---|---| | `APP_NAME` | yes | — | Display name | | `APP_ENV` | yes | — | `local` or `production` | | `APP_KEY` | yes | — | Generate with `php artisan key:generate` | | `APP_URL` | yes | — | `http://{HOST_IP}:6081` (ip-test) | | `APP_DEBUG` | no | `false` | `true` in local only | | `FRONTEND_URL` | yes | — | `http://{HOST_IP}:6080` | | `TENANT_SLUG` | yes | — | `ubios` — prefixes schema names | ### Database | Variable | Required | Default | Notes | |---|---|---|---| | `DB_CONNECTION` | no | `pgsql` | | | `DB_HOST` | yes | — | `ubios_postgres` | | `DB_PORT` | no | `5432` | | | `DB_DATABASE` | yes | — | `ubios` | | `DB_USERNAME` | yes | — | `postgres` (ip-test), `ubios_app` (production) | | `DB_PASSWORD` | yes | — | | ### Redis | Variable | Required | Default | Notes | |---|---|---|---| | `REDIS_CLIENT` | no | `phpredis` | | | `REDIS_HOST` | yes | — | `ubios_redis` | | `REDIS_PORT` | no | `6379` | | | `CACHE_STORE` | no | `redis` | | | `SESSION_DRIVER` | no | `redis` | | | `QUEUE_CONNECTION` | no | `redis` | | ### Agno Integration | Variable | Required | Default | Notes | |---|---|---|---| | `AGNO_API_URL` | yes | — | `http://ubios_agno:8001` | | `AGNO_API_KEY` | yes | — | Shared secret. `dev-key` in ip-test | | `AGNO_TIMEOUT_SECONDS` | no | `60` | Sync agent response timeout | | `AGNO_ASYNC_TIMEOUT_SECONDS` | no | `300` | Async/scheduled timeout | ### Mail | Variable | Required | Default | Notes | |---|---|---|---| | `MAIL_MAILER` | no | `smtp` | `ses` in production | | `MAIL_HOST` | no | `ubios_mailpit` | | | `MAIL_PORT` | no | `1025` | | | `MAIL_FROM_ADDRESS` | no | `noreply@ubios.dev` | | ### Security | Variable | Required | Default | Notes | |---|---|---|---| | `ENCRYPTION_KEY` | no | `dev_encryption_key_...` | **Generate unique for production** | | `BLIND_INDEX_KEY` | no | `dev_blind_index_key_...` | **Generate unique for production** | | `RLS_ENABLED` | no | `true` | Row-level security toggle | | `SANCTUM_STATEFUL_DOMAINS` | yes | — | `{HOST_IP},{HOST_IP}:6080,localhost` | ### MinIO / Storage | Variable | Required | Default | Notes | |---|---|---|---| | `MINIO_ENDPOINT` | yes | — | `http://ubios-minio:9000` | | `MINIO_ACCESS_KEY` | yes | — | `ubios-minio` | | `MINIO_SECRET_KEY` | yes | — | `ubios-minio_secret` | | `MINIO_BUCKET` | yes | — | `ubios-documents` | | `MINIO_USE_PATH_STYLE` | no | `true` | Required for MinIO | ### Feature Flags | Variable | Default | What it controls | |---|---|---| | `FEATURE_PROACTIVE_AGENTS` | `true` | Scheduled agents | | `FEATURE_DOCUMENT_EXTRACTION` | `true` | Document extraction pipeline | | `FEATURE_METABASE_EMBED` | `true` | BI dashboard embedding | | `FEATURE_QUERY_CACHE` | `true` | Redis query caching | ### Rate Limiting | Variable | Default | Endpoint | |---|---|---| | `UBIOS_RATE_LIMIT_CHAT` | `50` | Agent queries | | `UBIOS_RATE_LIMIT_SUGGEST` | `100` | Widget suggestions | | `UBIOS_RATE_LIMIT_REPORT` | `5` | Report generation | | `UBIOS_RATE_LIMIT_UPLOAD` | `10` | Document upload | ## Agno FastAPI | Variable | Required | Default | Notes | |---|---|---|---| | `AGNO_API_KEY` | yes | — | Must match Laravel's | | `TENANT_SLUG` | yes | — | Must match Laravel's | | `DB_HOST` | yes | — | `ubios_postgres` | | `DB_PORT` | no | `5432` | | | `DB_DATABASE` | yes | — | `ubios` | | `DB_READONLY_USERNAME` | yes | — | `postgres` (ip-test), `ubios_reader` (production) | | `DB_READONLY_PASSWORD` | yes | — | | | `DB_APP_USERNAME` | yes | — | `postgres` (ip-test), `ubios_app` (production) | | `DB_APP_PASSWORD` | yes | — | | | `REDIS_HOST` | yes | — | `ubios_redis` | | `LOG_LEVEL` | no | `INFO` | `debug` for development | | `DOCLING_SERVICE_URL` | no | — | `http://host.docker.internal:8010` | | `PADDLEOCR_SERVICE_URL` | no | — | `http://host.docker.internal:8015` | | `FIRECRAWL_SERVICE_URL` | no | — | `http://host.docker.internal:8030` | ### LLM Provider Keys All optional — at least one needed for AI features: | Variable | Provider | |---|---| | `OPENAI_API_KEY` | OpenAI | | `ANTHROPIC_API_KEY` | Anthropic | | `OPENROUTER_API_KEY` | OpenRouter (100+ models) | | `GLM_API_KEY` | GLM (Zhipu AI) | | `DEEPSEEK_API_KEY` | DeepSeek | | `GOOGLE_API_KEY` | Google Gemini | | `MISTRAL_API_KEY` | Mistral | | `GROQ_API_KEY` | Groq | | `AZURE_API_KEY` | Azure OpenAI | | `COHERE_API_KEY` | Cohere | | `PERPLEXITY_API_KEY` | Perplexity | | `TOGETHER_API_KEY` | Together AI | | `FIREWORKS_API_KEY` | Fireworks AI | | `CUSTOM_LLM_API_KEY` | Custom OpenAI-compatible endpoint | ### Embeddings | Variable | Default | Notes | |---|---|---| | `EMBEDDING_PROVIDER` | `openai` | `openai` or `local` | | `EMBEDDING_MODEL` | `text-embedding-3-small` | | | `EMBEDDING_DIMENSIONS` | `1536` | Must match pgvector columns | ## Dify | Variable | Required | Notes | |---|---|---| | `SECRET_KEY` | yes | Dify's own secret | | `DB_HOST` | yes | `ubios_postgres` | | `DB_DATABASE` | yes | `ubios_dify` (separate database) | | `DB_USERNAME` / `DB_PASSWORD` | yes | Dify's own DB user | | `REDIS_HOST` | yes | `ubios_redis` | | `REDIS_DB` | no | `5` (separate index) | | `STORAGE_TYPE` | yes | `s3` | | `S3_ENDPOINT` | yes | `http://ubios-minio:9000` | | `S3_BUCKET_NAME` | yes | `ubios-dify` | | `S3_ACCESS_KEY` / `S3_SECRET_KEY` | yes | MinIO credentials | ## Metabase | Variable | Notes | |---|---| | `MB_DB_CONNECTION_URI` | `postgresql://postgres:331331331@ubios_postgres:5432/ubios_metabase` | ## Nuxt Frontend | Variable | Default | Notes | |---|---|---| | `NUXT_PUBLIC_API_BASE` | `/api` | Proxied to Laravel | | `NUXT_PUBLIC_API_VERSION` | `v1` | | | `NUXT_PUBLIC_SITE_URL` | — | `http://{HOST_IP}:6080` | | `NUXT_API_PROXY_TARGET` | — | `http://ubios_api:8000` | | `NUXT_SSR_API_BASE` | — | `http://ubios_api:8000/api` | | `PORT` | `5080` | Internal port | | `NODE_ENV` | `development` | | | `NUXT_PUBLIC_THEME` | `fimula-base` | Theme package | | `NUXT_PUBLIC_THEME_PRESET` | `teal` | Color preset | | `NUXT_PUBLIC_DEFAULT_THEME_MODE` | `light` | `light` or `dark` | --- ## Laravel API **URL:** https://docs.binexia.dev/docs/api-reference/laravel-api **Description:** REST API endpoints served by the Laravel 12 backend. The Laravel API serves as the gateway between the Nuxt frontend and the backend services (Agno, Dify, PostgreSQL). All endpoints require Sanctum session authentication unless noted. ## Authentication | Method | Path | Auth | Purpose | |---|---|---|---| | POST | `/api/v1/auth/login` | No | Email/password login | | POST | `/api/v1/auth/logout` | Yes | End session | | POST | `/api/v1/auth/forgot-password` | No | Password reset email | | POST | `/api/v1/auth/reset-password` | No | Reset with token | ## Agent Queries | Method | Path | Auth | Purpose | |---|---|---|---| | POST | `/api/v1/agent/query` | Yes | Submit natural language question → proxies to Agno `POST /query` | | POST | `/api/v1/agent/context` | Yes | Dashboard element click → proxies to Agno `POST /context` | | POST | `/api/v1/agent/extract` | Admin | Trigger document extraction → proxies to Agno `POST /extract` | | GET | `/api/v1/agent/extract/status/{id}` | Admin | Poll extraction status → proxies to Agno `GET /extract/status/{id}` | ## Semantic Model (Admin) | Method | Path | Purpose | |---|---|---| | GET | `/api/v1/semantic/entities` | List entities | | POST | `/api/v1/semantic/entities` | Create entity | | PUT | `/api/v1/semantic/entities/{id}` | Update entity | | DELETE | `/api/v1/semantic/entities/{id}` | Delete entity | | GET/POST/PUT/DELETE | `/api/v1/semantic/metrics/*` | Metric CRUD | | GET/POST/PUT/DELETE | `/api/v1/semantic/dimensions/*` | Dimension CRUD | | GET/POST/PUT/DELETE | `/api/v1/semantic/vocabulary/*` | Vocabulary CRUD | | POST | `/api/v1/semantic/schema/refresh` | Regenerate `schema_context` | ## Widgets & Dashboards | Method | Path | Purpose | |---|---|---| | GET | `/api/v1/dashboards` | List dashboards for current user's role | | POST | `/api/v1/dashboards` | Create dashboard (admin) | | PUT | `/api/v1/dashboards/{id}` | Update dashboard (admin) | | DELETE | `/api/v1/dashboards/{id}` | Delete dashboard (admin) | | GET/POST/PUT/DELETE | `/api/v1/widgets/*` | Widget CRUD (admin) | | POST | `/api/v1/widgets/render` | Render widget data → proxies to Agno `POST /widget/render` | | GET | `/api/v1/widgets/suggest` | Suggest widgets from semantic model (admin) | ## LLM Routing (Admin) | Method | Path | Purpose | |---|---|---| | GET | `/api/v1/admin/llm-routing` | List all routes | | PUT | `/api/v1/admin/llm-routing/{id}` | Update route (provider, model, etc.) | | POST | `/api/v1/admin/llm-routing/{id}/toggle` | Toggle route active/inactive | ## Knowledge | Method | Path | Purpose | |---|---|---| | GET | `/api/v1/knowledge/sources` | List knowledge sources | | POST | `/api/v1/knowledge/sources` | Create knowledge source | | POST | `/api/v1/knowledge/upload` | Upload document → MinIO → Dify indexing | | DELETE | `/api/v1/knowledge/sources/{id}` | Delete source | | POST | `/api/v1/knowledge/sync` | Trigger re-index of all sources | ## Goals & Notifications | Method | Path | Purpose | |---|---|---| | GET | `/api/v1/goals` | List active goals | | POST | `/api/v1/goals` | Create goal (admin) | | PUT | `/api/v1/goals/{id}` | Update goal (admin) | | GET | `/api/v1/notifications` | List current user's notifications | | PUT | `/api/v1/notifications/{id}/read` | Mark notification as read | ## Response Format All endpoints return JSON. Success responses use appropriate HTTP status codes (200, 201). Error responses: ```json { "message": "Human-readable error description", "errors": { "field": ["Validation message"] } } ``` Rate limiting applies per endpoint (configurable via `UBIOS_RATE_LIMIT_*` env vars). --- ## Database **URL:** https://docs.binexia.dev/docs/architecture/database **Description:** Five PostgreSQL schemas per tenant — what lives where and why. Binexia uses a **schema-per-tenant** model in a single PostgreSQL 16 instance with pgvector. Each tenant gets five schemas that separate concerns by lifecycle and access pattern. ## The Five Schemas ### `tenant_data` — Business Records Core domain tables specific to the vertical. For IntelliTravel: `customers`, `bookings`, `destinations`, `suppliers`, `contact_history`. Plus universal tables: | Table | Purpose | |---|---| | `entities` | Universal entity registry, kept in sync via `sync_entity()` trigger | | `events` | Event stream for behavioral analysis | | `documents` | Document metadata (files stored in MinIO) | | `tags` | Flexible tagging for any entity | ### `tenant_semantic` — Semantic Model The metadata layer that makes natural language queries work. This is the **source of truth** for all metric and dimension definitions. | Table | Purpose | |---|---| | `entities` | Maps domain tables to natural language names | | `metrics` | SQL expressions, units, format hints (e.g., `COUNT(*)`, `currency`) | | `dimensions` | Grouping/slicing columns (time, categorical) | | `vocabulary` | Business terms → SQL filters (e.g., "high-value customer" → `ltv_eur > 5000`) | | `schema_context` | Auto-generated LLM prompt assembled from all above tables | Changes to metrics flag dependent query templates for review. ### `tenant_config` — Configuration Platform settings, user preferences, and admin-editable configuration. | Table | Purpose | |---|---| | `platform_settings` | Key-value application settings | | `llm_routing` | Agent → provider + model + temperature mapping | | `dashboards` | Dashboard definitions with grid layout JSON | | `widgets` | Widget configs (type, metric, dimension, chart settings) | | `users` | User accounts (extends fimula-base auth) | | `api_keys` | API key management | ### `tenant_agent_state` — Agent Runtime Session state, outputs, and notification history. | Table | Purpose | |---|---| | `agent_sessions` | Conversation sessions with context | | `agent_outputs` | Agent results (scores, alerts, forecasts) with expiry | | `scheduled_jobs` | Cron definitions for scheduled agents | | `notifications` | In-app and email notification log | ### `tenant_knowledge` — Document Intelligence Managed by Dify. Stores chunked document embeddings. | Table | Purpose | |---|---| | `document_chunks` | Embeddings with pgvector (`embedding_model` + `embedding_dimensions` columns for versioning) | | `knowledge_sources` | Source document metadata and indexing status | ## Database Users Two users with different privilege levels: | User | Access | Used by | |---|---|---| | `ubios_reader` | Read-only, statement timeouts | AnalyticsAgent SQL execution, Agno queries | | `ubios_app` | Read-write | Behavioral scoring, extraction, state updates | ## Entity Sync Trigger The `sync_entity()` trigger function keeps the `tenant_data.entities` table in sync with domain tables. When a row is inserted/updated/deleted in a domain table (e.g., `customers`), the trigger automatically updates the universal entities registry. This ensures agents always have a current view of available data. ## Additional Databases Two extra databases share the PostgreSQL instance: - **`ubios_dify`** — Dify's internal state (datasets, documents, chunking progress) - **`ubios_metabase`** — Metabase's internal state (queries, dashboards, user preferences) --- ## Request Flow **URL:** https://docs.binexia.dev/docs/architecture/request-flow **Description:** Three real requests traced end-to-end through the Binexia stack. How data flows through the system for three common scenarios. ## 1. User asks a natural language question "What's our revenue this month compared to last month?" ``` Browser └─ POST /api/v1/agent/query { question: "..." } └─► Laravel API ├─ Auth check (Sanctum) ├─ Load semantic schema_context from tenant_semantic └─► POST http://ubios_agno:8001/query └─► Agno OrchestratorAgent ├─ Analyzes: structured data question └─► Routes to AnalyticsAgent ├─ Reads schema_context ├─ Generates SQL via litellm ├─ Executes SQL via ubios_reader └─ Returns { sql, data, chart_config } ◄── Agno response ├─ Cache result in Redis (5 min TTL) └─► JSON response to browser └─► Recharts renders chart ``` **Key points:** - The semantic model (`schema_context`) is the LLM prompt — not raw schema DDL - SQL executes via `ubios_reader` (read-only, with statement timeout) - Cached results skip the LLM entirely on repeat queries - Agno uses litellm Python library (in-process) — no HTTP hop to the proxy ``` Browser — click on "Revenue" KPI card └─ POST /api/v1/agent/context { entity: "booking", metric: "revenue", filters: [...] } └─► Laravel API └─► POST http://ubios_agno:8001/context └─► ContextAgent ├─ Fetches entity data from Redis (pre-cached by nightly agents) ├─ Generates natural language explanation (cached 5 min) └─ Returns { entity_data, explanation, related_metrics } ◄── Agno response └─► JSON response to browser └─► Context panel renders overlay ``` **Key points:** - Entity data is served from Redis cache (pre-populated by scheduled agents) - The click triggers a fresh API call — no browser-side caching - LLM explanations are cached server-side with 5-minute TTL ## 3. Scheduled agent runs ``` Laravel scheduler (runs inside queue container) └─ php artisan schedule:run └─► Dispatches BehavioralScoringAgent job └─► Queue worker picks up job └─► POST http://ubios_agno:8001/score └─► BehavioralScoringAgent ├─ Queries booking patterns from tenant_data ├─ Scores each customer for churn risk └─ Returns { scores: [...] } ◄── Agno response ├─ Writes scores to tenant_agent_state.agent_outputs └─► Creates notifications for high-risk customers ├─ In-app notification (agent_state.notifications) └─ Email via Mailpit (critical alerts only) ``` **Key points:** - Scheduled agents run in the `queue` container, not the `api` container - Agent outputs expire after 30 days (`expires_at` column) - Only critical-severity outputs trigger email notifications --- ## Services **URL:** https://docs.binexia.dev/docs/architecture/services **Description:** The 15 Docker services that make up the Binexia stack. Binexia runs as a single Docker Compose stack with 15 core services + 3 optional profile-gated services. All inter-service communication uses Docker network DNS — the browser only reaches the Nuxt frontend. ## Service Map ``` Browser (:6080) └─► Nuxt 3 Frontend │ Proxies /api/* to Laravel │ └─► Laravel 12 API (:6081) ├─► PostgreSQL 16 (:5432) — 5 schemas + pgvector ├─► Redis 7 (:6379) — cache, queues, sessions ├─► Agno FastAPI (:8001) ─► LLM providers (via litellm library) ├─► LiteLLM Proxy (:4000) ─► unified LLM gateway │ └─► OpenAI/Compatible, Anthropic, Google Gemini, Mistral, OpenRouter, Cohere ├─► Dify API (:5001) + Worker ─► LiteLLM Proxy ─► LLM providers ├─► MinIO (:9000) — document storage ├─► Mailpit (:1025) — SMTP testing ├─► Metabase (:3000) — BI dashboards ├─► Uptime Kuma (:3001) — service monitoring ├─► Dozzle (:8080) — log viewer │ ├─► [profile: documents] │ ├─► Docling (:8010) — PDF/document parsing │ └─► PaddleOCR (:8015) — table-aware OCR parsing │ └─► [profile: web] └─► Firecrawl (:8030) — web crawler (scrape/crawl/map) ``` ## Services | Service | Container | Port | Purpose | |---|---|---|---| | `postgres` | `ubios_postgres` | 5432 | PostgreSQL 16 with pgvector. Single instance, 5 tenant schemas + Dify + Metabase databases. | | `redis` | `ubios_redis` | 6379 | Cache store, session driver, queue backend, rate limiter. | | `minio` | `ubios-minio` | 9000 / 9001 | S3-compatible document storage. Console on port 9001. | | `mailpit` | `ubios_mailpit` | 1025 / 8025 | SMTP testing sink. Web UI on port 8025. | | `api` | `ubios_api` | 6081→8000 | Laravel 12 API. Serves REST endpoints for frontend and Agno callbacks. | | `queue` | `ubios_queue` | — | Laravel queue worker (`php artisan queue:listen`). Runs document extraction, scheduled agent tasks, and async jobs separately from the API. | | `app` | `ubios_app` | 6080→5080 | Nuxt 3 frontend. Proxies `/api/*` to Laravel internally. | | `agno` | `ubios_agno` | 8001 | FastAPI agent runtime. Runs all 8 agent types via litellm library (in-process). | | `litellm` | `ubios_litellm` | 4000 | Unified LLM gateway proxy. Exposes OpenAI-compatible API for Dify and other services. Routes to all providers. | | `dify-api` | `ubios_dify_api` | 5001 | Dify knowledge pipeline API. Routes LLM calls through litellm proxy. | | `dify-worker` | `ubios_dify_worker` | — | Dify Celery worker. Processes document ingestion jobs. | | `dify-web` | `ubios_dify_web` | 3080→3000 | Dify admin UI for managing knowledge bases. | | `metabase` | `ubios_metabase` | 3000 | Embedded BI dashboards. Uses its own PostgreSQL database. | | `uptime-kuma` | `ubios_uptime_kuma` | 3001 | Self-hosted service monitoring. Health checks for all containers, status pages, alerting. | | `dozzle` | `ubios_dozzle` | 8080 | Real-time log viewer for all Docker containers. Zero config. | ### Profile-Gated Services These services only start when their profile is explicitly enabled: | Service | Container | Port | Profile | Purpose | |---|---|---|---|---| | `docling` | `ubios_docling` | 8010 | `documents` | PDF/document parsing into Markdown. Handles PDFs with text layers. | | `paddleocr` | `ubios_paddleocr` | 8015 | `documents` | Table-aware OCR parsing. Excels at structured tables. Apache 2.0, ~2GB image. | | `firecrawl` | `ubios_firecrawl` | 8030 | `web` | Self-hosted web crawler. Scrape, crawl, and map URLs into Markdown. AGPL-3.0. | ```bash # Start document parsing services docker compose --profile documents up -d # Start web crawler docker compose --profile web up -d ``` ## Why Each Service Exists **LiteLLM Proxy** — Unified LLM gateway. Dify and other services send OpenAI-format requests to one endpoint, litellm routes to the correct provider. One set of API keys for the entire stack. **Dify** — Manages the document ingestion pipeline: upload → chunk → embed → store in pgvector. Routes LLM calls through litellm proxy. **Metabase** — Provides embedded BI dashboards accessed via signed iFrame with a postMessage bridge. Derives its metric definitions from the semantic model. **Uptime Kuma** — Monitors health of all services via HTTP, TCP, and Docker checks. Provides status pages and 90+ notification channels. **Dozzle** — Zero-config log viewer. Mounts Docker socket, shows real-time logs for every container in the stack. **Mailpit** — Replaces Amazon SES in development. Captures all outgoing email (password resets, alert notifications) for inspection. **Queue worker** — Separates long-running jobs (document extraction, scheduled agent runs) from the HTTP request cycle. Uses Redis as the queue backend. ## Dependencies ```bash postgres (healthy) → api, agno, dify-api, metabase api → queue, app minio (healthy) → dify-api, dify-worker litellm → dify-api, dify-worker dify-api → dify-worker, dify-web ``` PostgreSQL must be healthy before any application service starts. MinIO must be healthy before Dify starts. Dify depends on litellm proxy for LLM access. ## LLM Access Patterns | Service | How it accesses LLMs | Why | |---|---|---| | **Agno** | litellm Python library (in-process) | Hot path — many calls per session, lowest latency | | **Dify** | litellm proxy via HTTP (`:4000`) | Occasional calls during ingestion, unified config | | **Other services** | litellm proxy via HTTP | Any future service gets OpenAI-compatible access | --- ## Tenant Isolation **URL:** https://docs.binexia.dev/docs/architecture/tenant-isolation **Description:** How Binexia isolates tenant data — schema-per-tenant, RLS, and Docker isolation. Binexia uses three layers of isolation to ensure tenant data never leaks. ## 1. Schema-per-Tenant (Primary) Each tenant gets five PostgreSQL schemas (`tenant_data`, `tenant_semantic`, `tenant_config`, `tenant_agent_state`, `tenant_knowledge`). The `TENANT_SLUG` environment variable determines which schemas the application uses. Laravel's `BelongsToProvider` trait automatically scopes all queries to the current tenant's schemas. Models use `$table = 'tenant_slug.table_name'` syntax where the prefix is resolved at runtime from the environment. ## 2. PostgreSQL Row-Level Security (Optional) Opt-in RLS policies add a defense-in-depth layer. When `RLS_ENABLED=true`: - Policies restrict rows to the current tenant's slug - Even if a query escapes the application-level scoping, the database enforces isolation - Enabled in production, can be disabled for simpler local development ## 3. Docker Compose Isolation (Production) In production, each customer gets their own Docker Compose stack on a dedicated server. This means: - Separate PostgreSQL instances - Separate Redis instances - Separate Agno agent runtimes - No shared processes between customers ## Auth Scoping `SANCTUM_STATEFUL_DOMAINS` restricts which domains can make authenticated API requests. In ip-test mode: ``` SANTUM_STATEFUL_DOMAINS=192.168.1.50,192.168.1.50:6080,localhost,localhost:6080 ``` Only requests from these origins are accepted as stateful (cookie-based) API requests. --- ## Agents **URL:** https://docs.binexia.dev/docs/core-concepts/agents **Description:** The eight agent types that power Binexia's intelligence capabilities. Binexia has eight specialized agents, grouped by when they run. ## On-Demand Agents Triggered by user actions (asking a question, clicking a widget). ### OrchestratorAgent The router. Receives every user query and decides which specialist agent handles it: - **Structured data question** ("What's our revenue?") → AnalyticsAgent - **Unstructured knowledge question** ("What's our refund policy?") → KnowledgeAgent - **Dashboard context** (user clicked a data point) → ContextAgent Uses the semantic model's `schema_context` and vocabulary to classify the query. ### AnalyticsAgent Text-to-SQL specialist. Converts natural language questions into SQL queries: 1. Reads `schema_context` from the semantic model 2. Generates SQL via litellm using the configured provider 3. Executes SQL via `ubios_reader` (read-only, statement timeout) 4. Returns structured data + chart configuration Results are cached in Redis (5 min TTL). Repeat queries skip the LLM entirely. ### KnowledgeAgent RAG specialist. Answers questions from uploaded documents: 1. Embeds the question using the same model as document chunks 2. Searches `tenant_knowledge.document_chunks` with pgvector similarity 3. Passes top-k chunks as context to the LLM 4. Returns a grounded answer with source citations ### ContextAgent Context panel specialist. When a user clicks on any data element: 1. Fetches entity data from Redis (pre-cached by nightly agents) 2. Generates a natural language explanation of what the data means 3. Suggests related metrics and drill-down options Explanations are cached 5 min TTL. ## Scheduled Agents Triggered by cron schedules defined in `tenant_agent_state.scheduled_jobs`. ### BehavioralScoringAgent Scores customers on churn risk and upsell probability: - Analyzes booking frequency, recency, spend trends - Outputs risk scores (0–1) with recommended actions - Runs weekly (`0 6 * * 1`) - High-risk customers trigger notifications ### AnomalyDetectionAgent Detects statistical anomalies in key metrics: - Monitors cancellation rates, revenue, booking volume, supplier SLA - Uses standard deviation thresholds (flags at >2σ) - Runs daily (`0 8 * * *`) - Critical anomalies trigger immediate notifications ### ForecastAgent Generates revenue and booking forecasts: - Uses historical patterns and seasonal trends - Outputs projected values with confidence intervals - Runs monthly (`0 7 1 * *`) ### DocumentExtractionAgent Extracts structured fields from uploaded documents: - Works alongside Dify for the chunking/embedding pipeline - Synthesizes key fields (amounts, dates, parties) from document text - Triggered on document upload ## Agent Outputs All agent results are stored in `tenant_agent_state.agent_outputs`: | Field | Purpose | |---|---| | `output_type` | `behavioral_score`, `anomaly_alert`, `forecast`, etc. | | `agent_name` | Which agent produced this | | `title` | Short summary | | `body` | Full explanation | | `data` | JSON payload with structured results | | `recommended_action` | What the user should do | | `confidence` | 0–1 confidence score | | `severity` | `info`, `warning`, `critical` | | `is_read` | Whether the user has seen it | | `expires_at` | Auto-cleanup after 30 days | ## Agent Sessions Each conversation with an agent creates a session in `agent_sessions`. Sessions track context, message history, and token usage across multiple turns. --- ## Knowledge Pipeline **URL:** https://docs.binexia.dev/docs/core-concepts/knowledge-pipeline **Description:** How documents flow from upload to searchable embeddings. The knowledge pipeline converts uploaded documents into searchable embeddings that power RAG answers via the KnowledgeAgent. ## Pipeline Stages ``` Upload document (PDF, DOCX, etc.) └─► Store file in MinIO └─► Dify picks up the document ├─ Docling (local, text-based PDFs) → text chunks └─ Mistral OCR 3 (API, scanned PDFs) → text chunks └─► Embed chunks via configured embedding model └─► Store in tenant_knowledge.document_chunks (pgvector) ``` ## Components ### Dify Manages the entire pipeline: document intake, chunking strategy, embedding generation, and storage. Each knowledge source maps to a Dify dataset (`dify_dataset_id` in `knowledge_sources` table). Dify runs as three Docker services: - `dify-api` (port 5001) — API endpoint - `dify-worker` — Celery background job processor - `dify-web` (port 3080) — Admin UI for managing datasets ### Docling Local document parser for text-based PDFs and DOCX files. Runs as a service accessible at `DOCLING_SERVICE_URL` (typically `http://host.docker.internal:8010`). ### Mistral OCR 3 API-based OCR for scanned documents and images. Requires `MISTRAL_OCR_API_KEY`. Without it, only text-based documents work. ### pgvector Embeddings are stored in `tenant_knowledge.document_chunks` using PostgreSQL's pgvector extension. Each chunk includes: | Column | Purpose | |---|---| | `embedding` | Vector (dimensions depend on model) | | `embedding_model` | Model name used (for versioning) | | `embedding_dimensions` | Vector size (e.g., 1536 for OpenAI) | | `content` | Raw text content | | `metadata` | Source document, page number, chunk index | ## Embedding Model Versioning The `embedding_model` and `embedding_dimensions` columns track which model produced each embedding. Changing the embedding model requires batch re-embedding of all existing chunks — old embeddings are incompatible with the new model's vector space. ## KnowledgeAgent (RAG) When a user asks a knowledge question: 1. Question is embedded using the same model as document chunks 2. pgvector similarity search finds the top-k matching chunks 3. Chunks + question are passed to the LLM as context 4. LLM generates a grounded answer with source citations ## Knowledge Sources Each source tracks its status: | Status | Meaning | |---|---| | `ready` | All documents indexed and searchable | | `indexing` | Currently processing documents | | `error` | Indexing failed, needs attention | ## Databases Dify uses its own PostgreSQL database (`ubios_dify`) for internal state. Document chunks are stored in the tenant's `ubios_knowledge` schema. --- ## LLM Routing **URL:** https://docs.binexia.dev/docs/core-concepts/llm-routing **Description:** How Binexia routes each agent to the best LLM provider and model using litellm. Every LLM call in Binexia goes through **litellm** — a unified API client that supports 100+ providers with a single interface. The routing table in `tenant_config.llm_routing` maps each agent to a specific provider, model, and configuration. ## Two LLM Access Patterns Binexia uses litellm in two ways: | Pattern | Used by | How | Why | |---|---|---|---| | **Python library** (in-process) | Agno agents | `litellm.completion()` | Hot path — lowest latency, many calls per session | | **Proxy server** (HTTP) | Dify, other services | `POST http://ubios_litellm:4000/v1/chat/completions` | OpenAI-compatible endpoint, unified key management | Both use the same API keys from `.env`. Agno reads them directly; the proxy reads them from its `config.yaml`. ## How It Works (Agno Agents) ```sql SELECT * FROM ubios_config.llm_routing WHERE agent_name = 'AnalyticsAgent'; -- Result: -- agent_name: AnalyticsAgent -- provider: anthropic -- model: claude-sonnet-4-6 -- max_tokens: 4096 -- temperature: 0.1 -- api_key_env: ANTHROPIC_API_KEY -- api_base: NULL -- fallback_route_id: NULL -- is_active: true ``` When the AnalyticsAgent needs to generate SQL, the router: 1. Looks up the route for `AnalyticsAgent` 2. Reads the API key from the environment variable specified in `api_key_env` 3. Calls litellm with the provider prefix + model name 4. If the call fails and `fallback_route_id` is set, tries the fallback route ## Provider Compatibility Tiers Providers are grouped by **API protocol**, not individual brands. Most providers speak the OpenAI protocol — same API format, different endpoint. ### OpenAI or Compatible Providers that implement the OpenAI `/v1/chat/completions` API. litellm handles routing automatically. | Provider | `provider` value | Env var | litellm prefix | Notes | |---|---|---|---|---| | OpenAI | `openai` | `OPENAI_API_KEY` | `openai/` | Direct | | DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` | `deepseek/` | Native litellm handler | | Groq | `groq` | `GROQ_API_KEY` | `groq/` | Native litellm handler | | Together AI | `together` | `TOGETHER_API_KEY` | `together/` | Native litellm handler | | Fireworks AI | `fireworks` | `FIREWORKS_API_KEY` | `fireworks/` | Native litellm handler | | Perplexity | `perplexity` | `PERPLEXITY_API_KEY` | `perplexity/` | Native litellm handler | | Azure OpenAI | `azure` | `AZURE_API_KEY` | `azure/` | Native litellm handler, set `api_base` | | GLM (Zhipu AI) | `glm` | `GLM_API_KEY` | `openai/` | Set `api_base: https://open.bigmodel.cn/api/paas/v4` | | Any /v1 endpoint | `custom` | `CUSTOM_LLM_API_KEY` | `openai/` | Ollama, vLLM, LocalAI, etc. | ### Anthropic | Provider | `provider` value | Env var | litellm prefix | |---|---|---|---| | Anthropic | `anthropic` | `ANTHROPIC_API_KEY` | `anthropic/` | ### Google Gemini | Provider | `provider` value | Env var | litellm prefix | |---|---|---|---| | Google Gemini | `google` | `GOOGLE_API_KEY` | `gemini/` | ### Mistral | Provider | `provider` value | Env var | litellm prefix | |---|---|---|---| | Mistral | `mistral` | `MISTRAL_API_KEY` | `mistral/` | ### OpenRouter (Gateway) | Provider | `provider` value | Env var | litellm prefix | Notes | |---|---|---|---|---| | OpenRouter | `openrouter` | `OPENROUTER_API_KEY` | `openrouter/` | Access 100+ models with one key | ### Cohere | Provider | `provider` value | Env var | litellm prefix | |---|---|---|---| | Cohere | `cohere` | `COHERE_API_KEY` | `cohere/` | ## Custom Endpoints The `api_base` field lets you point any provider at a custom endpoint: ```sql -- GLM via OpenAI-compatible endpoint UPDATE ubios_config.llm_routing SET provider = 'glm', api_base = 'https://open.bigmodel.cn/api/paas/v4', api_key_env = 'GLM_API_KEY', model = 'glm-4-flash' WHERE agent_name = 'KnowledgeAgent'; -- Self-hosted vLLM UPDATE ubios_config.llm_routing SET provider = 'custom', api_base = 'http://localhost:8000/v1', api_key_env = 'CUSTOM_LLM_API_KEY', model = 'meta-llama/Llama-3-70B' WHERE agent_name = 'OrchestratorAgent'; ``` ## Multiple Keys Per Provider You can define multiple env vars for the same provider and assign them to different agents: ```bash # .env.testip.local GLM_API_KEY_1=key-for-cheap-models GLM_API_KEY_2=key-for-premium-models ``` ```sql -- Agent 1 uses key 1 UPDATE ubios_config.llm_routing SET api_key_env = 'GLM_API_KEY_1', model = 'glm-4.5-air' WHERE agent_name = 'OrchestratorAgent'; -- Agent 2 uses key 2 UPDATE ubios_config.llm_routing SET api_key_env = 'GLM_API_KEY_2', model = 'glm-5' WHERE agent_name = 'AnalyticsAgent'; ``` ## Fallback Routes Set `fallback_route_id` to an alternate route name. If the primary call fails, the router tries the fallback: ```sql INSERT INTO ubios_config.llm_routing (agent_name, provider, model, max_tokens, temperature, api_key_env, is_active) VALUES ('analytics-backup', 'openai', 'gpt-4o-mini', 4096, 0.1, 'OPENAI_API_KEY', true); UPDATE ubios_config.llm_routing SET fallback_route_id = 'analytics-backup' WHERE agent_name = 'AnalyticsAgent'; ``` ## The LLM Routing Editor (Admin UI) Settings → LLM Routing provides a visual editor where you can: - Change provider and model for each agent - Set custom API base URLs - Choose which env var holds the API key - Configure fallback routes - Toggle routes active/inactive Changes take effect immediately — no restart needed. ## Default Routes (IntelliTravel Demo) | Agent | Provider | Model | Why | |---|---|---|---| | OrchestratorAgent | openai | gpt-4o-mini | Fast routing, cheap | | AnalyticsAgent | anthropic | claude-sonnet-4-6 | Strong SQL generation | | KnowledgeAgent | openai | gpt-4o-mini | Fast RAG responses | | ContextAgent | openai | gpt-4o-mini | Fast context explanations | | BehavioralScoringAgent | anthropic | claude-sonnet-4-6 | Complex reasoning | | AnomalyDetectionAgent | anthropic | claude-sonnet-4-6 | Statistical analysis | | ForecastAgent | anthropic | claude-sonnet-4-6 | Time-series reasoning | | DocumentExtractionAgent | openai | gpt-4o-mini | Fast field extraction | --- ## Semantic Model **URL:** https://docs.binexia.dev/docs/core-concepts/semantic-model **Description:** The core abstraction that makes natural language queries work — entities, metrics, dimensions, and vocabulary. The semantic model is the **most important concept** in Binexia. It sits between the raw database schema and the LLM, translating business concepts into queryable SQL. Every natural language query goes through the semantic model. ## The Four Building Blocks ### Entities Map domain tables to natural language names that the LLM understands. | Field | Example | Purpose | |---|---|---| | `name` | `booking` | Machine name used in queries | | `display_name` | `Booking` | Human-readable name | | `table_name` | `bookings` | Actual PostgreSQL table | | `primary_key_column` | `id` | Primary key | | `display_column` | `id` | Default display value | | `active_filter_sql` | `status NOT IN ('cancelled')` | Excludes inactive rows from queries | | `description` | "A travel booking linking a customer to a destination" | LLM context | ### Metrics SQL expressions that compute values. Each metric knows its table, unit, and format. | Field | Example | Purpose | |---|---|---| | `name` | `revenue` | Machine name | | `sql_expression` | `SUM(CASE WHEN status IN ('confirmed','completed') THEN total_price_eur END)` | The actual SQL | | `base_table` | `bookings` | Which table to query | | `unit` | `currency` | number, currency, percentage | | `format_hint` | `,2 EUR` | Display formatting | | `is_additive` | `true` | Whether it can be summed across time periods | ### Dimensions How metrics get sliced and grouped. | Field | Example | Purpose | |---|---|---| | `name` | `booking_date` | Machine name | | `dimension_type` | `time` | `time` or `categorical` | | `table_name` | `bookings` | Source table | | `column_name` | `created_at` | Source column | | `description` | "Supports grouping by day, week, month, or year" | LLM context | Time dimensions support automatic roll-up (day → week → month → year). Categorical dimensions support filtering and grouping. ### Vocabulary Business terms mapped to SQL filters — the bridge between how people talk and how data is structured. ```sql -- "high-value customer" becomes: ltv_eur > 5000 AND id IN (SELECT customer_id FROM bookings GROUP BY customer_id HAVING COUNT(*) >= 2) -- "at-risk customer" becomes: id IN (SELECT customer_id FROM bookings GROUP BY customer_id HAVING COUNT(*) >= 2) AND id NOT IN (SELECT customer_id FROM bookings WHERE travel_date >= CURRENT_DATE - INTERVAL '14 months') ``` Each vocabulary entry includes example questions that should trigger it: | Term | Example questions | |---|---| | "high-value customer" | "Show me all high-value customers", "Which customers spend the most" | | "at-risk customer" | "List at-risk customers", "Who might churn soon" | | "seasonal customer" | "Which customers travel seasonally", "Show seasonal travelers" | ## schema_context The `schema_context` table holds an auto-generated LLM prompt assembled from all entities, metrics, dimensions, and vocabulary. This is what the AnalyticsAgent receives at query time — not raw DDL, but a curated description of the data model. When you edit the semantic model in the admin UI, the `schema_context` is regenerated. ## The Admin Semantic Model Editor Settings → Semantic Model in the admin UI provides a visual editor for all four building blocks. Changes take effect immediately for new queries. Existing cached results remain until their TTL expires. --- ## Widget Framework **URL:** https://docs.binexia.dev/docs/core-concepts/widget-framework **Description:** How dashboard widgets work — types, configuration, and the rendering pipeline. Widgets are the building blocks of Binexia dashboards. Each widget is a JSON configuration object that describes what data to show and how to display it. **Widget rendering is LLM-free for cached/template hits** — only the admin's Raw Query widget triggers live LLM generation. ## Widget Types ### `kpi_card` Single metric with optional comparison period. ```json { "widget_type": "kpi_card", "config": { "metric": "revenue", "period": "this_month", "comparison_period": "last_month", "icon": "pi pi-dollar", "color": "var(--p-green-500)" } } ``` Displays: current value, change from comparison period (%, arrow), icon, color. ### `metric_chart` Time-series or categorical chart. ```json { "widget_type": "metric_chart", "config": { "metric": "total_bookings", "dimension": "booking_date", "chart_type": "line", "period": "last_30_days", "color": "var(--p-primary-color)", "show_trend": true } } ``` Supports: `line`, `bar`, `area` chart types. Dimensions determine grouping (time for line, categorical for bar). ### `top_n_table` Ranked table of items by metric value. ```json { "widget_type": "top_n_table", "config": { "metric": "revenue", "dimension": "destination", "period": "this_month", "sort_by": "value", "sort_dir": "desc", "limit": 5, "show_rank": true, "show_percentage": true } } ``` ### `alert_feed` Scrollable list of recent agent alerts. ```json { "widget_type": "alert_feed", "config": { "max_items": 10, "severity_filter": ["warning", "critical"], "show_timestamp": true } } ``` ### `raw_query` Admin-only widget. Accepts a free-text natural language question and renders the result live via the LLM pipeline. This is the only widget type that triggers the full OrchestratorAgent → AnalyticsAgent flow. ## Dashboard Layout Dashboards use a grid layout stored as JSON: ```json { "layout": [ { "i": "w1", "x": 0, "y": 0, "w": 6, "h": 4 }, { "i": "w2", "x": 6, "y": 0, "w": 6, "h": 4 }, { "i": "w3", "x": 0, "y": 4, "w": 8, "h": 6 } ] } ``` 12-column grid. Each widget has a position (`x`, `y`) and size (`w`, `h`). ## Rendering Pipeline ``` Widget config JSON └─► Is it a cache/template hit? ├─ YES → Render directly from cached data (no LLM) └─ NO → Is it a raw_query? ├─ YES → OrchestratorAgent → AnalyticsAgent → SQL → chart └─ NO → Fetch metric data from semantic model → render ``` ## Metric Source of Truth All widget metrics reference `tenant_semantic.metrics` by name. When you change a metric definition in the semantic model, affected widgets update on next render. The system flags dependent widgets for admin review when metrics change. ## Admin Tools - **Widget Builder** — Create and configure widgets visually - **Dashboard Builder** — Arrange widgets on a grid, set role visibility - **Dashboard defaults** — Set one dashboard per role as the landing page --- ## Prerequisites **URL:** https://docs.binexia.dev/docs/getting-started/prerequisites **Description:** What you need before running Binexia. ## Required - **Linux machine** (Ubuntu/Debian) or **macOS** on the same network as your laptop - **Docker + Docker Compose v2** — [install guide](https://docs.docker.com/engine/install/) - **Git** - **GitHub personal access token** — needed to pull private fimula-base packages during build. Generate at https://github.com/settings/tokens (needs `repo:read` scope). Containers **will not build** without this. ## LLM Provider Keys (optional) The platform works in **mock mode** without any LLM keys — dashboard data is hardcoded, AI queries return demo responses. Add keys when you're ready for live AI features. | Key | Where to get | Cost | Default for | |---|---|---|---| | `OPENAI_API_KEY` | https://platform.openai.com/api-keys | ~$0.15/1M tokens | Orchestrator, Knowledge, Context, Document Extraction | | `ANTHROPIC_API_KEY` | https://console.anthropic.com/settings/keys | ~$3/1M tokens | Analytics, Behavioral Scoring, Anomaly Detection, Forecast | ### Additional providers | Key | Where to get | Notes | |---|---|---| | `OPENROUTER_API_KEY` | https://openrouter.ai/keys | Unified gateway — access 100+ models with one key | | `GLM_API_KEY` | https://open.bigmodel.cn | Zhipu AI. Also works as Anthropic-compatible via custom `api_base` | | `DEEPSEEK_API_KEY` | https://platform.deepseek.com | Cheap reasoning models | | `MISTRAL_API_KEY` | https://console.mistral.ai | European provider | | `GROQ_API_KEY` | https://console.groq.com | Fast inference (LPU hardware) | ### What works without LLM keys - Full frontend UI (dashboards, admin, knowledge library) - Login and authentication - Dashboard widgets with mock data - All CRUD operations (semantic model, widgets, goals) - Document upload and storage (MinIO) ### What requires LLM keys - AI query answers (text-to-SQL, RAG) - Document extraction (structured field synthesis) - Behavioral scoring explanations - Anomaly detection analysis - Revenue forecasting ## Hardware 12 Docker containers run simultaneously. Recommended minimum: - **RAM:** 8 GB (16 GB preferred) - **Disk:** 20 GB free (Docker images + data volumes) - **CPU:** 4 cores --- ## Quick Start **URL:** https://docs.binexia.dev/docs/getting-started/quick-start **Description:** Clone, configure, and run the full Binexia stack in 5 minutes. Get the full Binexia stack running on any machine. No domains, no Traefik — just IP and ports. ## Step 1: Clone and prepare ```bash git clone https://github.com/krecco/ubios.git cd ubios # Create your env file cp .env.testip .env.testip.local ``` Edit `.env.testip.local` — add your `GITHUB_TOKEN` (required for private fimula packages). LLM keys are optional. ## Step 2: Find your IP ```bash hostname -I | awk '{print $1}' # Example: 192.168.1.50 ``` ## Step 3: Start everything ```bash export HOST_IP=192.168.1.50 # your actual IP from Step 2 docker compose \ -f docker-compose.ip-test.yml \ --env-file .env.testip.local \ up -d --build ``` First build takes 5–10 minutes. Watch progress: ```bash docker compose -f docker-compose.ip-test.yml logs -f ``` Wait until you see Nuxt output `Listening on http://0.0.0.0:5080`. ## Step 4: Initialize the database ```bash # Create additional databases docker exec -it ubios_api bash -c ' PGPASSWORD=331331331 psql -U postgres -h ubios_postgres -c "CREATE DATABASE ubios_dify;" 2>/dev/null PGPASSWORD=331331331 psql -U postgres -h ubios_postgres -c "CREATE DATABASE ubios_metabase;" 2>/dev/null echo "Databases ready" ' # Generate Laravel APP_KEY docker exec -it ubios_api php artisan key:generate --force # Run migrations docker exec -it ubios_api php artisan migrate # Seed demo data (IntelliTravel vertical) docker exec -it ubios_api php artisan db:seed --class=UbiosDatabaseSeeder ``` ## Step 5: Open in browser From any machine on the same network: ``` http://192.168.1.50:6080 ``` Login: **admin@ubios.local** / **password** You should see the main dashboard with KPI cards (Total Bookings, Revenue), a daily bookings chart, and recent agent alerts. ## What's Running | Service | Port | Purpose | |---|---|---| | Frontend | `:6080` | Main app — login, dashboards, AI queries | | API | `:6081` | Laravel API (debugging) | | Agno | `:8001` | Agent runtime health check | | LiteLLM Proxy | `:4000` | Unified LLM gateway | | MinIO Console | `:9001` | Document storage browser | | Metabase | `:3000` | BI dashboards | | Mailpit | `:8025` | Email testing inbox | | Dify | `:3080` | Knowledge pipeline admin | | Uptime Kuma | `:3001` | Service monitoring | | Dozzle | `:8080` | Log viewer | ## Next Steps - Add LLM provider keys to enable AI features - Explore the semantic model in the admin UI - Read about the [architecture](/docs/architecture/services) --- ## Building Dashboards **URL:** https://docs.binexia.dev/docs/guides/building-dashboards **Description:** Create dashboards, add widgets, and configure layouts. Dashboards are collections of widgets arranged on a 12-column grid. This guide covers the admin workflow. ## Creating a Dashboard 1. Go to Settings → Dashboards → New Dashboard 2. Set name, description, and role visibility 3. Optionally set as default dashboard for specific roles **Role visibility** controls who sees the dashboard: - `admin, manager, viewer` — everyone - `admin` — admin only - `admin, manager` — admins and managers ## Adding Widgets Click "Add Widget" and choose: ### KPI Card Shows a single metric with period comparison. | Config field | What it does | |---|---| | `metric` | Which metric to display (from semantic model) | | `period` | Time period: `this_month`, `this_week`, `last_30_days` | | `comparison_period` | Previous period for % change: `last_month`, `last_week` | | `icon` | PrimeIcons class (e.g., `pi pi-dollar`) | | `color` | CSS variable or hex color | ### Chart Time-series or categorical visualization. | Config field | What it does | |---|---| | `metric` | What to measure | | `dimension` | How to slice (time or categorical) | | `chart_type` | `line`, `bar`, or `area` | | `period` | Time range | | `show_trend` | Show trend line overlay | ### Top N Table Ranked list by metric value. | Config field | What it does | |---|---| | `metric` | What to rank by | | `dimension` | What to list | | `limit` | How many items (e.g., 5 for top 5) | | `sort_dir` | `desc` (highest first) or `asc` | | `show_percentage` | Show % of total | ### Alert Feed Recent agent alerts. | Config field | What it does | |---|---| | `max_items` | How many alerts to show | | `severity_filter` | `["warning", "critical"]` | | `show_timestamp` | Display time ago | ## Layout Configuration Widgets are positioned on a 12-column grid: ``` ┌──────────────────────┬──────────────────────┐ │ KPI: Bookings │ KPI: Revenue │ │ (w:6, h:4) │ (w:6, h:4) │ ├──────────────────────────────┬───────────────┤ │ Chart: Daily Bookings │ Alert Feed │ │ (w:8, h:6) │ (w:4, h:6) │ └──────────────────────────────┴───────────────┘ ``` Position is stored as JSON: `{ "i": "w1", "x": 0, "y": 0, "w": 6, "h": 4 }` ## Setting a Default Dashboard Mark one dashboard per role as default. When a user with that role logs in, they see this dashboard first. Each role can have a different default. ## Metric Source of Truth All widget metrics reference `tenant_semantic.metrics` by name. If a metric is renamed or deleted, affected widgets show a configuration warning in the admin UI. --- ## Building a Semantic Model **URL:** https://docs.binexia.dev/docs/guides/building-semantic-model **Description:** Step-by-step guide to creating a semantic model for your vertical. The semantic model is what makes natural language queries work. This guide walks through building one, using IntelliTravel as a real example. ## Step 1: Define Entities Entities map your domain tables to natural language names. For each table that users might ask about: 1. Go to Settings → Semantic Model → Entities 2. Add the table with a clear name and description **IntelliTravel example:** | name | table_name | display_column | active_filter_sql | description | |---|---|---|---|---| | `customer` | `customers` | `name` | — | Travel agency customer with segment and lifetime value | | `booking` | `bookings` | `id` | `status NOT IN ('cancelled')` | Travel booking linking customer to destination | | `destination` | `destinations` | `name` | — | Available travel destination | | `supplier` | `suppliers` | `name` | `is_active = true` | Service supplier (hotel, transfer, activity) | | `contact_history` | `contact_history` | `id` | — | Customer interaction record | ## Step 2: Add Metrics For each number users might ask about: 1. Go to Settings → Semantic Model → Metrics 2. Define the SQL expression, unit, and format **Key fields:** - **`sql_expression`** — The actual SQL. Use `CASE WHEN` for conditional aggregation. - **`base_table`** — Which table this metric queries. - **`unit`** — `number`, `currency`, or `percentage`. - **`format_hint`** — How to display: `,0` for integers, `,2 EUR` for euros, `0.0%` for percentages. - **`is_additive`** — Can this metric be summed across time periods? Revenue: yes. Average booking value: no. **IntelliTravel example:** | name | sql_expression | unit | is_additive | |---|---|---|---| | `total_bookings` | `COUNT(*)` | number | true | | `revenue` | `SUM(CASE WHEN status IN ('confirmed','completed') THEN total_price_eur END)` | currency | true | | `avg_booking_value` | `SUM(...) / NULLIF(COUNT(...), 0)` | currency | false | | `cancellation_rate` | `COUNT(*) FILTER (WHERE status = 'cancelled') * 100.0 / NULLIF(COUNT(*), 0)` | percentage | false | ## Step 3: Add Dimensions Dimensions define how metrics get sliced: - **Time dimensions** — `booking_date`, `travel_date`. Enable day/week/month/year roll-up. - **Categorical dimensions** — `destination`, `booking_channel`, `customer_segment`, `supplier`. For each dimension, specify the table and column. The `description` field is LLM context — explain what the dimension means and what kind of grouping makes sense. ## Step 4: Define Vocabulary Vocabulary terms bridge business language to SQL. This is where domain expertise matters most. **Good vocabulary entries:** | Term | What it means | SQL filter | |---|---|---| | "high-value customer" | LTV > 5000 EUR + 2+ bookings | `ltv_eur > 5000 AND id IN (SELECT ... HAVING COUNT(*) >= 2)` | | "at-risk customer" | 2+ past bookings, none in 14 months | Complex subquery on booking recency | | "season" | High/Shoulder/Low demand period | `CASE WHEN EXTRACT(MONTH ...) IN (6,7,8) THEN 'High' ...` | Each entry includes **example questions** — the phrases that should trigger this term: - "high-value customer" → ["Show me all high-value customers", "Which customers spend the most"] ## Step 5: Test 1. Create a Raw Query widget on a test dashboard 2. Ask questions that use your vocabulary terms 3. Verify the generated SQL is correct 4. Check chart rendering **Common issues:** - **Wrong `base_table`** — Metric queries the wrong table - **Missing `active_filter_sql`** — Includes inactive/cancelled records - **Overly complex `sql_expression`** — Simplify; the LLM handles complexity - **Vocabulary too narrow** — Add more example questions per term ## What Happens Next When you save the semantic model: - `schema_context` is regenerated for the LLM - Existing cached queries remain until TTL expires - Metabase and widgets that reference changed metrics are flagged for review --- ## Cheap LLM for Dev/Test **URL:** https://docs.binexia.dev/docs/guides/cheap-llm-dev **Description:** Use free and budget LLMs during development to avoid burning expensive tokens. All LLM calls in Binexia go through litellm — swapping providers is a config change, not a code change. Providers are grouped by **API protocol** (not individual brands): most providers (DeepSeek, Groq, Together, Fireworks, Perplexity, GLM/Zhipu, Azure) speak the OpenAI protocol — same SDK, different endpoint. Use free tiers during development, switch to production models only for quality validation. ## Best Option: Google Gemini 2.0 Flash (Free) Completely free tier with generous limits. One API key covers all 8 agents. | Metric | Free Tier | |---|---| | Requests/min | 15 RPM | | Tokens/min | 1,000,000 TPM | | Requests/day | 1,500 RPD | | Cost | $0 | **Setup:** ```bash # .env.testip.local — add this one line GOOGLE_API_KEY=AIza... # https://aistudio.google.com/apikey ``` **litellm config** (`services/litellm/config.yaml`): ```yaml - model_name: gemini-2.0-flash litellm_params: model: gemini/gemini-2.0-flash api_key: os.environ/GOOGLE_API_KEY ``` **Update routing table:** ```sql UPDATE ubios_config.llm_routing SET provider = 'google', model = 'gemini-2.0-flash', api_key_env = 'GOOGLE_API_KEY'; ``` Or change per-agent in Settings → LLM Routing. ## Other Free/Budget Options ### Groq (Free Tier) LPU-accelerated inference — very fast. Llama models only. | Model | Free RPM | Free TPM | |---|---|---| | llama-3.3-70b-versatile | 30 | 12,000 | | llama-3.1-8b-instant | 30 | 6,000 | ```bash GROQ_API_KEY=gsk_... # https://console.groq.com ``` Good for Orchestrator and Context agents. Less capable for complex SQL generation. ### DeepSeek V3.2 (~$0.28/1M input) Extremely cheap, strong reasoning. Cache hits cost $0.028/1M. ```bash DEEPSEEK_API_KEY=sk-... # https://platform.deepseek.com ``` 10,000 test queries at ~1,500 tokens each ≈ **$0.004** (cache miss). ### Gemini 2.0 Flash-Lite (Free, Faster) Same free tier but higher RPM (30). Use for high-volume automated tests. ## Recommended Dev Routes | Agent | Dev Default | Cost | |---|---|---| | OrchestratorAgent | `gemini-2.0-flash` | Free | | AnalyticsAgent | `gemini-2.0-flash` | Free | | KnowledgeAgent | `gemini-2.0-flash` | Free | | ContextAgent | `gemini-2.0-flash-lite` | Free | | BehavioralScoringAgent | `gemini-2.0-flash` | Free | | AnomalyDetectionAgent | `gemini-2.0-flash` | Free | | ForecastAgent | `gemini-2.0-flash` | Free | | DocumentExtractionAgent | `gemini-2.0-flash` | Free | **All 8 agents on one free key.** ## When to Switch to Paid | Scenario | Switch to | Why | |---|---|---| | SQL accuracy validation | Anthropic Claude Sonnet | Production-grade text-to-SQL | | RAG quality benchmarking | OpenAI GPT-4o | Baseline comparison | | Load testing (>15 RPM) | DeepSeek V3.2 | Cheap, high rate limits | | CI/CD pipeline (>1.5K req/day) | DeepSeek V3.2 | Near-zero cost | ## Cost Comparison: 1,000 Queries per Agent | Provider | 8 agents × 1,000 queries | |---|---| | Google Gemini 2.0 Flash (free) | **$0.00** | | DeepSeek V3.2 | ~$0.03 | | OpenAI GPT-4o-mini | ~$1.84 | | Anthropic Claude Sonnet | ~$48.00 | ## Free Tier Gotchas - **Gemini 15 RPM** is shared across all agents — integration test suites can hit this. Add `time.sleep(4)` between agent calls if rate-limited - **Groq models change** occasionally — pin a specific version if tests depend on output format - **DeepSeek can be slow** during peak hours (China daytime) — use cache hits when possible --- ## Creating a Vertical **URL:** https://docs.binexia.dev/docs/guides/creating-vertical **Description:** How to configure Binexia for a new business domain. Binexia uses a **template pattern**: the same code serves every vertical. Only the semantic model configuration and seed data change. This guide covers what you need to create a new vertical. ## The Template Pattern ``` Same codebase (Laravel + Nuxt + Agno) └─ Different configuration per vertical: ├─ Semantic model (entities, metrics, dimensions, vocabulary) ├─ Seed data (demo records) ├─ Dashboard templates (widgets, layouts) ├─ Goals (scheduled agent configurations) └─ LLM routing defaults (provider/model per agent) ``` ## Checklist ### 1. Domain Tables (`tenant_data` schema) Create the business tables for your vertical. Examples: | IntelliTravel | Manufacturing | Legal | |---|---|---| | `customers` | `clients` | `clients` | | `bookings` | `orders` | `cases` | | `destinations` | `products` | `practice_areas` | | `suppliers` | `suppliers` | `attorneys` | | `contact_history` | `quality_reports` | `time_entries` | ### 2. Semantic Entities Map each domain table to a natural language entity with description and `active_filter_sql`. ### 3. Metrics Define the key performance indicators: | IntelliTravel | Manufacturing | Legal | |---|---|---| | Total Bookings | Total Orders | Total Cases | | Revenue | Revenue | Billable Hours | | Avg Booking Value | Avg Order Value | Avg Case Value | | Cancellation Rate | Defect Rate | Case Dismissal Rate | | Active Customers | Active Clients | Active Clients | | Repeat Booking Rate | Repeat Order Rate | Client Retention Rate | ### 4. Dimensions Time: booking date, travel date → order date, delivery date → case filed date, case closed date Categorical: destination, channel, segment → product line, region, priority → practice area, attorney, court ### 5. Vocabulary Domain-specific business terms. This is the most important part — it's where domain expertise gets encoded: | IntelliTravel | Manufacturing | Legal | |---|---|---| | "high-value customer" | "enterprise client" | "major client" | | "at-risk customer" | "churn-risk client" | "at-risk client" | | "seasonal booking" | "seasonal order" | "seasonal case volume" | | "supplier SLA breach" | "supplier quality issue" | "attorney response delay" | ### 6. Goals Configure scheduled agent goals: ```json { "name": "cancellation_rate_alert", "agent_type": "anomaly", "agent_schedule": "0 8 * * *", "alert_threshold": { "above": 20.0, "window_days": 7 } } ``` ### 7. Seed Data Create a seeder class (like `UbiosDemoSeeder`) that populates: - Users with roles - Semantic model tables (entities, metrics, dimensions, vocabulary) - Goals - Dashboard templates with widgets - Sample agent outputs for demo purposes - LLM routing defaults ### 8. Test 1. Run the seeder 2. Log in and verify dashboards render correctly 3. Test natural language queries against the semantic model 4. Verify vocabulary terms trigger correctly 5. Check scheduled agent configurations ## Example: Manufacturing Vertical **Entities:** client, order, product, supplier, quality_report **Key metrics:** Total Orders, Revenue, Avg Order Value, Defect Rate, Active Clients, Repeat Order Rate **Key dimensions:** order_date, delivery_date, product_line, region, supplier **Vocabulary:** "enterprise client" (order value greater than $50K), "defect" (quality_score below 80), "on-time delivery" (delivery_date on or before promised_date) **Goals:** Defect Rate Alert (anomaly, daily), Client Churn Risk (behavioral, weekly), Monthly Revenue Forecast (forecast, monthly) --- ## Deploying **URL:** https://docs.binexia.dev/docs/guides/deploying **Description:** Production deployment on Hetzner with Docker Compose. ## Server Setup (Hetzner) 1. Provision a server (recommended: CX32 or larger — 4 vCPU, 8 GB RAM) 2. Install Docker + Docker Compose 3. Clone the repository 4. Configure environment ## Production Environment Create a `.env.production` with production values: ```bash # Required GITHUB_TOKEN=ghp_... # Private package access HOST_IP=your-server-ip # LLM — at least one required for AI features OPENAI_API_KEY=sk-... ANTHROPIC_API_KEY=sk-ant-... # Security — generate unique keys ENCRYPTION_KEY=$(php -r "echo bin2hex(random_bytes(32));") BLIND_INDEX_KEY=$(php -r "echo bin2hex(random_bytes(32));") # Tenant TENANT_SLUG=your-tenant # App URLs APP_URL=https://api.yourdomain.com FRONTEND_URL=https://yourdomain.com ``` ## Start Production Stack ```bash docker compose -f docker-compose.yml --env-file .env.production up -d --build # Initialize docker exec -it ubios_api php artisan key:generate --force docker exec -it ubios_api php artisan migrate docker exec -it ubios_api php artisan db:seed --class=UbiosDatabaseSeeder ``` ## SSL / Reverse Proxy Use Nginx or Caddy as a reverse proxy in front of the Nuxt container: ```nginx server { listen 443 ssl; server_name yourdomain.com; ssl_certificate /etc/ssl/yourdomain.crt; ssl_certificate_key /etc/ssl/yourdomain.key; location / { proxy_pass http://127.0.0.1:6080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` ## Backups PostgreSQL data lives in a Docker volume. Back up regularly: ```bash # Create backup docker exec ubios_postgres pg_dump -U postgres ubios > backup_$(date +%Y%m%d).sql # Restore cat backup_20260410.sql | docker exec -i ubios_postgres psql -U postgres ubios ``` ## Monitoring - `docker ps` — check all containers are running - `docker compose logs -f` — live log tailing - Agno health: `curl http://localhost:8001/health` - PostgreSQL health: `docker inspect ubios_postgres --format='{{.State.Health.Status}}'` ## Scaling Notes Each customer gets their own Docker Compose stack. For multiple customers: - Use separate Hetzner servers (simplest, most isolated) - Or use Docker Compose profiles / separate compose files on a single high-spec server --- ## Setting Up Dify **URL:** https://docs.binexia.dev/docs/guides/setting-up-dify **Description:** Configure Dify knowledge pipeline with litellm proxy for unified LLM access. Dify manages the document ingestion pipeline: upload → chunk → embed → store in pgvector. It routes all LLM calls through the litellm proxy, so you use the same API keys as Agno agents. ## Prerequisites - Full stack running (`docker compose -f docker-compose.ip-test.yml up -d`) - At least one LLM key in `.env.testip.local` - `ubios_dify` database created (done in quick start) ## Step 1: Create Dify Admin Account Open `http://{IP}:3080` and create the admin account. Use a strong password — this is a service account. ## Step 2: Configure LLM Provider Dify connects to the litellm proxy as an OpenAI-compatible endpoint. 1. Go to **Settings → Model Providers** 2. Find **OpenAI-API-Compatible** (or **OpenAI** if using built-in provider) 3. Configure: | Field | Value | |---|---| | API Base URL | `http://ubios_litellm:4000/v1` | | API Key | Your `LITELLM_MASTER_KEY` value (from `.env.testip.local`) | 4. Add models. These names must match the `model_name` values in `services/litellm/config.yaml`: | Model Name | Type | Use Case | |---|---|---| | `gpt-4o-mini` | Text generation | Default chunking, keyword extraction | | `claude-sonnet` | Text generation | Complex document analysis | | `glm-4-flash` | Text generation | Budget-friendly processing | 5. Set `gpt-4o-mini` as the default system model: - **Settings → Model Providers → System Model Settings** - Default model: `gpt-4o-mini` ## Step 3: Configure Embedding Provider For embeddings, you can use the same litellm proxy or configure directly: 1. Go to **Settings → Model Providers** 2. Configure your embedding model (e.g., OpenAI `text-embedding-3-small`) 3. Set it as the system embedding model ## Step 4: Create a Knowledge Base 1. Go to **Knowledge → Create Knowledge Base** 2. Name it (e.g., "IntelliTravel Documents") 3. Select the embedding model configured in Step 3 4. Set chunking strategy: - **Automatic** (recommended for most cases) - Or **Custom** with chunk size 500–1000, overlap 50–100 ## Step 5: Test the Pipeline Upload a test document: 1. In the knowledge base, click **Add File** 2. Upload a PDF, DOCX, or TXT file 3. Wait for processing to complete (check status indicator) 4. Verify chunks were created by clicking the file Test retrieval from Agno: ```bash # Ask a question that should use the knowledge base curl -X POST http://$HOST_IP:8001/query \ -H "X-Agno-Key: dev-key" \ -H "Content-Type: application/json" \ -d '{"question": "What does our travel policy say about cancellation?", "user_id": "test"}' ``` ## Architecture ``` Dify API (:5001) ├─ Document chunking → LLM call → http://ubios_litellm:4000/v1 → any litellm-supported provider ├─ Embedding generation → OpenAI text-embedding-3-small └─ Vector storage → PostgreSQL pgvector (tenant_knowledge schema) Agno KnowledgeAgent └─ Queries pgvector embeddings directly (bypasses Dify at query time) ``` Key points: - Dify handles **ingestion only** (upload → chunk → embed → store) - Agno KnowledgeAgent queries **pgvector directly** at query time (no Dify in the hot path) - All LLM calls from Dify go through litellm proxy — same keys, same config ## Troubleshooting ### Dify can't connect to litellm ```bash # Check litellm is healthy curl http://$HOST_IP:4000/health # Check from inside Dify container docker exec -it ubios_dify_api curl http://ubios_litellm:4000/health ``` ### Model not found error The model name in Dify must exactly match a `model_name` in `services/litellm/config.yaml`. Check the config and restart litellm if you changed it. ### Embedding fails Ensure the embedding API key is configured. Check Dify logs: ```bash docker compose -f docker-compose.ip-test.yml logs -f dify-api ``` --- ## Setting Up LLM Providers **URL:** https://docs.binexia.dev/docs/guides/setting-up-llm-providers **Description:** Step-by-step guide for configuring LLM providers in Binexia. ## How LLM Keys Work All provider keys live in `.env.testip.local`. Two services read them: - **Agno** reads keys directly via litellm Python library (in-process, lowest latency) - **LiteLLM Proxy** reads keys from `services/litellm/config.yaml` and exposes an OpenAI-compatible API for Dify and other services Both use the same keys — no duplication. ## Quick Setup Edit `.env.testip.local` and add at least one provider key: ```bash # Cheapest option — works for all agents OPENAI_API_KEY=sk-... # Better reasoning — recommended for Analytics and Behavioral agents ANTHROPIC_API_KEY=sk-ant-... # LiteLLM proxy master key (for Dify access) LITELLM_MASTER_KEY=sk-litellm-your-secret ``` Then restart containers: ```bash docker compose -f docker-compose.ip-test.yml --env-file .env.testip.local up -d ``` No rebuild needed — env vars are read on container start. ## Verifying Setup ### Agno (direct) ```bash curl http://$HOST_IP:8001/health ``` ### LiteLLM Proxy ```bash curl http://$HOST_IP:4000/health ``` Test a completion through the proxy: ```bash curl http://$HOST_IP:4000/v1/chat/completions \ -H "Authorization: Bearer $LITELLM_MASTER_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "gpt-4o-mini", "messages": [{"role": "user", "content": "Hello"}], "max_tokens": 50}' ``` ## Verifying a Provider Works Test a simple query from the UI: log in, open a dashboard, and type a question in the Raw Query widget. If you get a chart, the LLM is working. ## LiteLLM Proxy Configuration The proxy config is at `services/litellm/config.yaml`. It maps friendly model names to provider-specific parameters: ```yaml model_list: - model_name: gpt-4o-mini litellm_params: model: openai/gpt-4o-mini api_key: os.environ/OPENAI_API_KEY - model_name: claude-sonnet litellm_params: model: anthropic/claude-sonnet-4-6 api_key: os.environ/ANTHROPIC_API_KEY - model_name: glm-4-flash litellm_params: model: openai/glm-4-flash api_key: os.environ/GLM_API_KEY api_base: https://open.bigmodel.cn/api/paas/v4 ``` To add a new model, add it to `config.yaml` and restart the litellm container: ```bash docker compose -f docker-compose.ip-test.yml restart litellm ``` ## Provider Details Providers are grouped by **API protocol**. Most providers speak the OpenAI API format — same SDK, different endpoint. litellm handles the routing automatically. ### OpenAI or Compatible These providers use the OpenAI `/v1/chat/completions` API protocol. litellm routes each to the correct endpoint. #### OpenAI (Recommended Default) ```bash OPENAI_API_KEY=sk-proj-... # https://platform.openai.com/api-keys ``` - **Cost:** ~$0.15/1M input tokens (GPT-4o-mini), ~$2.50/1M (GPT-4o) - **Good for:** Orchestrator, Knowledge, Context, Document Extraction - **Provider:** `openai` #### DeepSeek ```bash DEEPSEEK_API_KEY=sk-... # https://platform.deepseek.com ``` - **Cost:** Very cheap (~$0.14/1M tokens for DeepSeek-V3) - **Good for:** Budget-conscious deployments - **Provider:** `deepseek` #### Groq ```bash GROQ_API_KEY=gsk_... # https://console.groq.com ``` - **Very fast** inference via LPU hardware - **Good for:** Real-time responses, low latency - **Provider:** `groq` #### Together AI ```bash TOGETHER_API_KEY=... # https://api.together.ai ``` - **Open-source models at scale** — Llama, Mistral, FLUX - **Provider:** `together` #### Fireworks AI ```bash FIREWORKS_API_KEY=... # https://fireworks.ai ``` - **Fast open-source model** inference - **Provider:** `fireworks` #### Perplexity ```bash PERPLEXITY_API_KEY=pplx-... # https://perplexity.ai/settings/api ``` - **Sonar models** — search-augmented generation - **Provider:** `perplexity` #### GLM (Zhipu AI) ```bash GLM_API_KEY=your-glm-key # https://open.bigmodel.cn ``` Configure in the LLM Routing Editor: - **Provider:** `glm` - **Model:** `glm-4-flash` (or `glm-4-plus`, `glm-4-long`) - **API Base URL:** `https://open.bigmodel.cn/api/paas/v4` - **API Key Env Var:** `GLM_API_KEY` GLM uses an OpenAI-compatible API — the `glm` provider setting automatically routes through the `openai/` litellm prefix with the correct `api_base`. #### Azure OpenAI ```bash AZURE_API_KEY=... AZURE_API_BASE=https://your-resource.openai.azure.com AZURE_API_VERSION=2024-06-01 ``` - **Enterprise compliance** — regional deployment, data residency - **Provider:** `azure` - **Requires** `api_base` set to your Azure endpoint #### Custom (Any OpenAI-Compatible Endpoint) For self-hosted models (Ollama, vLLM, LocalAI, etc.): ```bash CUSTOM_LLM_API_KEY=optional-key ``` - **Provider:** `custom` - **Set `api_base`** to your endpoint (e.g., `http://localhost:11434/v1` for Ollama) ### Anthropic ```bash ANTHROPIC_API_KEY=sk-ant-api03-... # https://console.anthropic.com/settings/keys ``` - **Cost:** ~$3/1M input tokens (Claude Sonnet) - **Good for:** Analytics, Behavioral Scoring, Anomaly Detection, Forecast - **Stronger at:** Complex SQL generation, reasoning, analysis - **Provider:** `anthropic` ### Google Gemini ```bash GOOGLE_API_KEY=AI... # https://aistudio.google.com/apikey ``` - **Multimodal** — text, images, video - **Provider:** `google` - **Models:** `gemini-2.0-flash`, `gemini-2.5-pro` - **Free tier:** 15 RPM, 1M TPM — great for development (see [Cheap LLM for Dev](/docs/guides/cheap-llm-dev)) ### Mistral ```bash MISTRAL_API_KEY=... # https://console.mistral.ai ``` - **European provider** — data stays in EU - **Provider:** `mistral` ### OpenRouter (Gateway) ```bash OPENROUTER_API_KEY=sk-or-... # https://openrouter.ai/keys ``` - **Cost:** Varies by model (often cheaper than direct) - **Good for:** Accessing 100+ models with one key - **Model format:** `anthropic/claude-3.5-sonnet`, `meta-llama/llama-3-70b`, etc. - **Provider:** `openrouter` ### Cohere ```bash COHERE_API_KEY=... # https://dashboard.cohere.com ``` - **Enterprise NLP** — search, summarization, classification - **Provider:** `cohere` ## Mock Mode (No Keys) Without any LLM keys, Binexia runs in mock mode: - Dashboard widgets show hardcoded demo data - AI queries return canned demo responses - Document extraction skips LLM synthesis - Scheduled agents don't run Everything else works: login, CRUD, file upload, dashboard layout, semantic model editing. ## Cost Estimates Approximate cost per agent type with default models: | Agent | Model | Avg tokens/query | Est. cost/1000 queries | |---|---|---|---| | Orchestrator | GPT-4o-mini | ~500 | $0.08 | | Analytics | Claude Sonnet | ~2000 | $6.00 | | Knowledge | GPT-4o-mini | ~1500 | $0.23 | | Context | GPT-4o-mini | ~800 | $0.12 | | Behavioral | Claude Sonnet | ~3000 | $9.00 | | Anomaly | Claude Sonnet | ~2000 | $6.00 | | Forecast | Claude Sonnet | ~2500 | $7.50 | --- ## Test Data & Databases **URL:** https://docs.binexia.dev/docs/guides/test-data **Description:** Sample databases for testing all 5 UBIOS capabilities across every vertical. UBIOS needs production-quality test data to validate text-to-SQL, RAG retrieval, document extraction, behavioral scoring, and proactive agents. Each database below serves a specific vertical or capability. ## Primary: TPC-DS (Multi-Channel Retail) The gold standard for BI testing. 25 tables in star schema, 99 predefined queries. Maps to IntelliRetail, IntelliTravel, and IntelliSupply by relabeling. | Scale Factor | Rows | Size | Use For | |---|---|---|---| | SF 1 | ~7M | ~1 GB | Development | | SF 10 | ~70M | ~10 GB | Customer demos | | SF 100 | ~570M | ~100 GB | Performance testing | Setup: `CREATE EXTENSION tpcds; CALL tpcds.run(10, 4);` — one command in PostgreSQL. ## All Test Databases | Database | Domain | Rows | Tables | Best For | |---|---|---|---|---| | **TPC-DS** | Multi-channel retail | 7M–570M | 25 | Text-to-SQL, dashboards, anomalies | | **Synthea** | Healthcare (OMOP CDM) | Up to millions of patients | 70+ | IntelliClinic vertical | | **Stack Exchange** | Q&A communities | Up to 60M posts | 8 | RAG at scale, user analytics | | **Pagila** | DVD rental | ~45K | 15 | IntelliTravel prototyping | | **Northwind** | Food import | ~10K | 14 | IntelliSupply prototyping | | **Chinook** | Media sales | ~15K | 11 | IntelliMedia, simple joins | | **IMDB** | Movie metadata | ~10M titles | 7 | Streaming analytics | | **MovieLens** | User ratings | Up to 32M ratings | 3 | Recommendation, behavioral | | **Employee DB** | HR | ~3.9M | 6 | IntelliHR, time-series queries | ## Quick Setup: Development Baseline For a fully functional dev environment with meaningful data: ```bash # 1. TPC-DS (primary — most capabilities) docker exec -it ubios_api bash -c ' PGPASSWORD=331331331 psql -U postgres -h ubios_postgres -d ubios -c "CREATE EXTENSION IF NOT EXISTS tpcds;" PGPASSWORD=331331331 psql -U postgres -h ubios_postgres -d ubios -c "CALL tpcds.run(1, 4);" ' # 2. Chinook (quick media data) wget -q https://raw.githubusercontent.com/lerocha/chinook-database/master/ChinookDatabase/DataSources/Chinook_PostgreSql.sql -O /tmp/chinook.sql sed 's/CREATE TABLE /CREATE TABLE chinook./g; s/INSERT INTO /INSERT INTO chinook./g' /tmp/chinook.sql | \ docker exec -i ubios_api bash -c 'PGPASSWORD=331331331 psql -U postgres -h ubios_postgres -d ubios' # 3. Employee DB (large HR dataset) # See docs/testing/12-employee-setup.md for full instructions ``` ## By UBIOS Capability ### Text-to-SQL | Database | Why | Complexity | |---|---|---| | TPC-DS | Star schema, 99 benchmark queries | High | | Chinook | Simple joins, aggregations | Low | | Employee DB | Temporal queries, window functions | Medium | | IMDB | Text search + ratings joins | Medium | ### Knowledge RAG | Database | Why | Scale | |---|---|---| | Stack Exchange | Real Q&A content, structured tags | Up to 60M posts | | IMDB plot summaries | Unstructured text + structured metadata | ~10M titles | ### Document Extraction Use the document sets in `docs/testing/05-document-sets.md`: CORD invoices, SEC 10-K filings, GDPR text. ### Behavioral Scoring | Database | Why | |---|---| | TPC-DS (returns data) | Customer return patterns | | MovieLens | User rating behavior over time | | Employee DB | Salary progression, title changes | ### Proactive Agents | Database | Why | |---|---| | TPC-DS (seasonal data) | Holiday spikes, promotion effectiveness | | Stack Exchange | Reputation trends, answer quality drift | ## Recommended Test Data Plan ### Phase 1: Development (this week) 1. **TPC-DS SF 1** (~7M rows, 1GB) — primary test database 2. **Chinook** (~15K rows) — quick media join testing 3. **10 PDF invoices** — extraction pipeline test ### Phase 2: Customer Demo (before first demo) 4. **TPC-DS SF 10** (~70M rows, 10GB) — production-scale demo 5. **DocLayNet-small** (804 pages) — extraction showcase 6. **Synthetic events** — behavioral scoring demo ### Phase 3: Production Validation 7. **TPC-DS SF 100** (~570M rows) — full performance benchmark 8. **Synthea** — IntelliClinic vertical validation 9. **Stack Exchange** — large-scale RAG stress test --- Detailed setup instructions for each database are in `docs/testing/`: - `01-pagila-setup.md` — IntelliTravel prototyping - `02-northwind-setup.md` — IntelliSupply prototyping - `03-synthea-setup.md` — IntelliClinic (healthcare) - `04-tpc-ds-setup.md` — Primary production test DB - `07-stackexchange-setup.md` — Knowledge/community analytics - `10-chinook-setup.md` — IntelliMedia (music sales) - `11-netflix-movie-setup.md` — IntelliMedia (streaming) - `12-employee-setup.md` — IntelliHR (large dataset) --- ## Day to Day **URL:** https://docs.binexia.dev/docs/operations/day-to-day **Description:** Common commands for starting, stopping, and managing the Binexia stack. ## Always Set Your IP First ```bash export HOST_IP=192.168.1.50 # your actual LAN IP ``` ## Commands ### Start / Stop ```bash # Start all services docker compose -f docker-compose.ip-test.yml --env-file .env.testip.local up -d # Stop all services (keep data) docker compose -f docker-compose.ip-test.yml down # Rebuild after code changes docker compose -f docker-compose.ip-test.yml --env-file .env.testip.local up -d --build ``` ### Logs ```bash # All services docker compose -f docker-compose.ip-test.yml logs -f # Specific service docker compose -f docker-compose.ip-test.yml logs -f api # Laravel docker compose -f docker-compose.ip-test.yml logs -f app # Nuxt docker compose -f docker-compose.ip-test.yml logs -f agno # Agents docker compose -f docker-compose.ip-test.yml logs -f queue # Queue worker ``` ### Shell Access ```bash docker exec -it ubios_api bash # Laravel docker exec -it ubios_app sh # Nuxt docker exec -it ubios_agno bash # Agno Python docker exec -it ubios_postgres bash # PostgreSQL ``` ### Database ```bash # Fresh database (destroys all data) docker exec -it ubios_api php artisan migrate:fresh --seed --class=UbiosDatabaseSeeder # Run new migrations only docker exec -it ubios_api php artisan migrate # Re-seed (keeps schema, replaces data) docker exec -it ubios_api php artisan db:seed --class=UbiosDatabaseSeeder ``` ### Health Checks ```bash # Agno health curl http://$HOST_IP:8001/health # PostgreSQL health docker inspect ubios_postgres --format='{{.State.Health.Status}}' # Should show: healthy # Test database connection docker exec -it ubios_api bash -c ' PGPASSWORD=331331331 psql -U postgres -h ubios_postgres -d ubios -c "SELECT 1;" ' ``` ### Cleanup ```bash # Stop and delete all data volumes docker compose -f docker-compose.ip-test.yml down -v # Stop and delete data + built images docker compose -f docker-compose.ip-test.yml down -v --rmi local ``` --- ## IP Testing **URL:** https://docs.binexia.dev/docs/operations/ip-testing **Description:** Run the full Binexia stack using IP addresses — no DNS setup needed. IP testing runs the full stack on any machine accessible via LAN. No dnsmasq, no Traefik, no domains. ## When to Use - **IP testing:** Quick setup, testing from another machine on the network, demos - **Local dev (dnsmasq):** Daily development, hot reload, multiple services with named URLs ## Setup ### 1. Clone and configure ```bash git clone https://github.com/krecco/ubios.git cd ubios cp .env.testip .env.testip.local # Edit .env.testip.local — add GITHUB_TOKEN (required) and LLM keys (optional) nano .env.testip.local ``` ### 2. Find your IP ```bash hostname -I | awk '{print $1}' # Example: 192.168.1.50 ``` ### 3. Start ```bash export HOST_IP=192.168.1.50 docker compose \ -f docker-compose.ip-test.yml \ --env-file .env.testip.local \ up -d --build ``` First build: 5–10 minutes. Subsequent starts: ~30 seconds. ### 4. Initialize database ```bash # Create databases for Dify and Metabase docker exec -it ubios_api bash -c ' PGPASSWORD=331331331 psql -U postgres -h ubios_postgres -c "CREATE DATABASE ubios_dify;" 2>/dev/null PGPASSWORD=331331331 psql -U postgres -h ubios_postgres -c "CREATE DATABASE ubios_metabase;" 2>/dev/null echo "Databases ready" ' # Generate app key docker exec -it ubios_api php artisan key:generate --force # Run migrations docker exec -it ubios_api php artisan migrate # Seed demo data docker exec -it ubios_api php artisan db:seed --class=UbiosDatabaseSeeder ``` ### 5. Access From any machine on the same network: ``` http://192.168.1.50:6080 ``` Login: **admin@ubios.local** / **password** ## Service Access URLs | Service | URL | Purpose | |---|---|---| | Frontend | `http://{IP}:6080` | Main app | | API (direct) | `http://{IP}:6081` | Laravel API debugging | | Agno health | `http://{IP}:8001/health` | Agent runtime status | | MinIO console | `http://{IP}:9001` | Document storage | | Metabase | `http://{IP}:3000` | BI dashboards | | Mailpit | `http://{IP}:8025` | Email testing | | Dify UI | `http://{IP}:3080` | Knowledge pipeline | | LiteLLM Proxy | `http://{IP}:4000/health` | LLM gateway status | | Uptime Kuma | `http://{IP}:3001` | Service monitoring dashboard | | Dozzle | `http://{IP}:8080` | Real-time log viewer | ## Adding LLM Keys Later Edit `.env.testip.local` and restart — no rebuild needed: ```bash nano .env.testip.local # Add: OPENAI_API_KEY=sk-... docker compose -f docker-compose.ip-test.yml --env-file .env.testip.local up -d ``` --- ## Local Development **URL:** https://docs.binexia.dev/docs/operations/local-development **Description:** dnsmasq setup, hot reload, and service URLs for local development. Local development uses dnsmasq for wildcard DNS resolution and hot-reload for all services. ## DNS Setup (dnsmasq) ```bash # Install dnsmasq sudo apt install dnsmasq # Linux brew install dnsmasq # macOS # Configure wildcard for *.fimula.local echo "address=/fimula.local/127.0.0.1" | sudo tee /etc/dnsmasq.d/fimula.conf sudo systemctl restart dnsmasq ``` ### Service URLs | Service | URL | |---|---| | Frontend | `http://ubios.fimula.local` | | API | `http://api.ubios.fimula.local` | | Agno | `http://agno.fimula.local:8001` (internal) | | LiteLLM Proxy | `http://ubios.fimula.local:4000` | | Dify | `http://dify.fimula.local:5001` | | Metabase | `http://metabase.fimula.local:3000` | | MinIO | `http://minio.fimula.local:9001` | | Mailpit | `http://mail.fimula.local:8025` | | Uptime Kuma | `http://ubios.fimula.local:3001` | | Dozzle | `http://ubios.fimula.local:8080` | ## Hot Reload All three application services support hot reload: | Service | How it works | Trigger | |---|---|---| | **Nuxt** (app) | Vite HMR | File save in `app/` | | **Laravel** (api) | Octane auto-reloads | File save in `api/` | | **Agno** (agno) | Uvicorn `--reload` | File save in `services/agno/` | Changes appear within 1–2 seconds. No manual restart needed. ## Debugging Per Service ### Laravel ```bash # Tinker REPL docker exec -it ubios_api php artisan tinker # Tail logs docker compose -f docker-compose.dev.yml logs -f api # Check routes docker exec -it ubios_api php artisan route:list ``` ### Nuxt ```bash # Shell access docker exec -it ubios_app sh # Check build errors docker compose -f docker-compose.dev.yml logs -f app ``` ### Agno ```bash # Shell access docker exec -it ubios_agno bash # Health check curl http://ubios.fimula.local:8001/health # Test a query directly curl -X POST http://ubios.fimula.local:8001/query \ -H "X-Agno-Key: dev-key" \ -H "Content-Type: application/json" \ -d '{"question": "What is our revenue?", "user_id": "test"}' ``` ### PostgreSQL ```bash # Direct query docker exec -it ubios_api bash -c ' PGPASSWORD=331331331 psql -U postgres -h ubios_postgres -d ubios ' # Check schema \d ubios_semantic.entities \d ubios_config.llm_routing ``` --- ## Monitoring **URL:** https://docs.binexia.dev/docs/operations/monitoring **Description:** Container health checks, log aggregation, and system monitoring. ## Uptime Kuma (Service Monitoring) Uptime Kuma runs at `http://{IP}:3001`. It monitors all 15 containers via HTTP, TCP, and Docker health checks. **First-time setup:** 1. Open `http://{IP}:3001` — create an admin account 2. Add a new monitor for each service: - **Type:** HTTP for API services, Docker for containers - **Interval:** 60 seconds (recommended) - **Retention:** Keep defaults **Recommended monitors:** | Monitor | Type | Target | |---|---|---| | Laravel API | HTTP | `http://ubios_api:8000/api/v1/health` | | Agno | HTTP | `http://ubios_agno:8001/health` | | PostgreSQL | Docker | `ubios_postgres` | | Redis | TCP | `ubios_redis:6379` | | MinIO | HTTP | `http://ubios-minio:9000/minio/health/live` | | Metabase | HTTP | `http://ubios_metabase:3000/api/health` | | Dify | HTTP | `http://ubios_dify_api:5001/health` | | LiteLLM Proxy | HTTP | `http://ubios_litellm:4000/health` | ## Dozzle (Log Viewer) Dozzle runs at `http://{IP}:8080`. It shows real-time logs for all containers with zero configuration. **Features:** - View logs for any container by clicking its name - Search logs with regex or SQL - Split-screen to watch multiple containers - Filter by severity level ## Container Health Checks Check all containers are running: ```bash docker ps --format "table {{.Names}}\t{{.Status}}" ``` Expected: all 15 containers show `Up` with `(healthy)` for services that define health checks (postgres, minio). ### Individual Health Endpoints | Service | Command | Expected | |---|---|---| | Agno | `curl http://$HOST_IP:8001/health` | `{"status": "ok"}` | | LiteLLM Proxy | `curl http://$HOST_IP:4000/health` | `{"status": "ok"}` | | PostgreSQL | `docker inspect ubios_postgres --format='{{.State.Health.Status}}'` | `healthy` | | MinIO | `curl -sf http://$HOST_IP:9000/minio/health/live` | 200 OK | ## Redis Monitoring ```bash # Check Redis is responding docker exec -it ubios_redis redis-cli ping # Expected: PONG # Memory usage docker exec -it ubios_redis redis-cli info memory | grep used_memory_human # Connected clients docker exec -it ubios_redis redis-cli info clients | grep connected_clients # Cache hit rate docker exec -it ubios_redis redis-cli info stats | grep keyspace_hits ``` ## Queue Monitoring ```bash # Check queue worker is running docker compose -f docker-compose.ip-test.yml logs --tail=20 queue # Failed jobs docker exec -it ubios_api php artisan queue:failed # Retry a failed job docker exec -it ubios_api php artisan queue:retry {job_id} ``` ## Agent Activity ```bash # Recent agent outputs docker exec -it ubios_api bash -c ' PGPASSWORD=331331331 psql -U postgres -h ubios_postgres -d ubios -c \ "SELECT agent_name, output_type, severity, is_read, created_at FROM ubios_agent_state.agent_outputs ORDER BY created_at DESC LIMIT 10;" ' # Scheduled job status docker exec -it ubios_api bash -c ' PGPASSWORD=331331331 psql -U postgres -h ubios_postgres -d ubios -c \ "SELECT * FROM ubios_agent_state.scheduled_jobs WHERE is_active = true;" ' ``` ## Log Aggregation All services log to stdout/stderr (Docker logging driver). View them via Dozzle (`http://{IP}:8080`) or the CLI: ```bash # Follow all logs with timestamps docker compose -f docker-compose.ip-test.yml logs -f -t # Filter by severity (Agno) docker compose -f docker-compose.ip-test.yml logs -f agno 2>&1 | grep -i error # Laravel error log docker exec -it ubios_api tail -f storage/logs/laravel.log ``` ## Key Metrics to Watch | Metric | Warning | Critical | Where to check | |---|---|---|---| | PostgreSQL connections | > 80% pool | > 95% | `pg_stat_activity` | | Redis memory | > 80% maxmemory | > 95% | `redis-cli info memory` | | Queue depth | > 100 jobs | > 500 jobs | `queue:failed` + Redis list length | | Agno response time | > 5s P95 | > 10s P95 | `GET /health` + application logs | | Disk usage | > 80% | > 90% | `df -h` on host | ## Production Monitoring (Target) Phase 3 includes centralized monitoring via Prometheus + Grafana on a control plane server: - Container health status (all 12+ containers) - PostgreSQL connection pool saturation and query latency - Redis memory usage and eviction rate - Agent session count, LLM call count, average duration - Query cache hit rate - Scheduled job success/failure rate - Document extraction queue depth - Disk usage (Postgres data, MinIO objects) --- ## Troubleshooting **URL:** https://docs.binexia.dev/docs/operations/troubleshooting **Description:** Common issues and fixes for the Binexia stack. ## Connection Refused from Browser **Symptom:** Browser can't reach `http://{IP}:6080` ```bash # Check containers are running docker ps # Open firewall ports sudo ufw allow 6080/tcp sudo ufw allow 6081/tcp ``` If using a cloud server, also check the cloud provider's security group/firewall rules. ## Container Won't Start / Build Fails **Most common cause:** Missing `GITHUB_TOKEN` ```bash grep GITHUB_TOKEN .env.testip.local # Should show: GITHUB_TOKEN=ghp_... (not empty) ``` **Rebuild from scratch:** ```bash docker compose -f docker-compose.ip-test.yml down -v docker compose -f docker-compose.ip-test.yml --env-file .env.testip.local up -d --build ``` ## Database Errors **Symptom:** `SQLSTATE[08006]` or migration failures ```bash # Check postgres is healthy docker inspect ubios_postgres --format='{{.State.Health.Status}}' # Should show: healthy # If not healthy, check logs docker compose -f docker-compose.ip-test.yml logs postgres # Test connection docker exec -it ubios_api bash -c ' PGPASSWORD=331331331 psql -U postgres -h ubios_postgres -d ubios -c "SELECT 1;" ' # If connection works but migration fails, check schema exists docker exec -it ubios_api bash -c ' PGPASSWORD=331331331 psql -U postgres -h ubios_postgres -d ubios -c "\dn" ' ``` ## Port Already in Use **Symptom:** `bind: address already in use` ```bash # Find what's using the port sudo lsof -i :5432 # PostgreSQL sudo lsof -i :6080 # Nuxt sudo lsof -i :6379 # Redis sudo lsof -i :8001 # Agno # Kill the conflicting process or change the port in docker-compose ``` ## Agno Returns Errors **Symptom:** Agent queries fail or return LLM errors ```bash # Check Agno health (includes LLM provider status) curl http://$HOST_IP:8001/health # Check Agno logs docker compose -f docker-compose.ip-test.yml logs --tail=50 agno ``` Common Agno issues: - **`LLM_FAILURE`**: API key missing or invalid. Check the key for the provider in `.env.testip.local`. - **`SCHEMA_NOT_FOUND`**: Migrations haven't run. Run `docker exec -it ubios_api php artisan migrate`. - **`AGENT_TIMEOUT`**: LLM provider is slow or rate-limited. Try again or switch to a faster model. ## Queue Jobs Not Processing **Symptom:** Scheduled agents don't run, document extraction hangs ```bash # Check queue worker is running docker compose -f docker-compose.ip-test.yml logs --tail=20 queue # Check for failed jobs docker exec -it ubios_api php artisan queue:failed # Restart the queue worker docker compose -f docker-compose.ip-test.yml restart queue ``` ## Nuxt Shows Blank Page **Symptom:** Frontend loads but shows nothing ```bash # Check Nuxt is serving docker compose -f docker-compose.ip-test.yml logs --tail=20 app # Common issue: API proxy not connecting # Verify NUXT_API_PROXY_TARGET points to correct container docker exec -it ubios_app sh -c 'echo $NUXT_API_PROXY_TARGET' # Should show: http://ubios_api:8000 ``` ## MinIO / Document Upload Fails ```bash # Check MinIO is healthy curl -sf http://$HOST_IP:9000/minio/health/live # Check MinIO credentials docker exec -it ubios_api bash -c 'echo $MINIO_ACCESS_KEY' ``` ## Reset Everything ```bash # Nuclear option: stop, delete all data and images, start fresh docker compose -f docker-compose.ip-test.yml down -v --rmi local docker compose -f docker-compose.ip-test.yml --env-file .env.testip.local up -d --build # Then re-initialize docker exec -it ubios_api bash -c ' PGPASSWORD=331331331 psql -U postgres -h ubios_postgres -c "CREATE DATABASE ubios_dify;" 2>/dev/null PGPASSWORD=331331331 psql -U postgres -h ubios_postgres -c "CREATE DATABASE ubios_metabase;" 2>/dev/null ' docker exec -it ubios_api php artisan key:generate --force docker exec -it ubios_api php artisan migrate docker exec -it ubios_api php artisan db:seed --class=UbiosDatabaseSeeder ``` --- ## Links - [GitHub](https://github.com/krecco/ubios)