# FALO SME AI KM Platform - Project Technical Summary (AI-Optimized)

This document provides a structured, comprehensive technical summary of the SME Knowledge Management (KM) API platform. It is optimized for consumption by AI agents and coding assistants.

---

## 1. System Architecture Overview

The platform is built on a serverless stack powered by **Cloudflare (CF) developer platform**:
- **API Worker (Routing & Logic)**: Cloudflare Workers (using Hono framework for routing).
- **Relational Database**: Cloudflare D1 (SQLite-compatible) for metadata, audit logs, and document records.
- **Vector Database**: Cloudflare Vectorize for storing and performing similarity searches on document embeddings.
- **Blob Storage**: Cloudflare R2 for storing raw uploaded documents.
- **LLM & Embeddings**: Cloudflare Workers AI for running local embeddings (`@cf/baai/bge-m3`) and text generation models (Gemma, Llama, Qwen, Mistral, DeepSeek).

---

## 2. Database Schema (D1 SQL)

The system enforces multi-tenant segregation. All tables isolate data using a `tenant_id` column.

```sql
-- Tenants Table (Enterprise spaces)
CREATE TABLE tenants (
    id TEXT PRIMARY KEY,
    name TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- API Keys Table (Authorizing clients)
CREATE TABLE api_keys (
    id TEXT PRIMARY KEY,
    tenant_id TEXT NOT NULL,
    key_name TEXT NOT NULL,
    api_key_hash TEXT NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY(tenant_id) REFERENCES tenants(id)
);

-- Assistants Table (Configured RAG agents)
CREATE TABLE assistants (
    id TEXT NOT NULL,
    tenant_id TEXT NOT NULL,
    name TEXT NOT NULL,
    description TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY(tenant_id, id),
    FOREIGN KEY(tenant_id) REFERENCES tenants(id)
);

-- Documents Table (Uploaded source files)
CREATE TABLE documents (
    id TEXT PRIMARY KEY,
    tenant_id TEXT NOT NULL,
    assistant_id TEXT NOT NULL,
    name TEXT NOT NULL,
    file_path TEXT NOT NULL,
    file_size INTEGER NOT NULL,
    chunk_count INTEGER DEFAULT 0,
    status TEXT DEFAULT 'pending', -- 'pending', 'processing', 'completed', 'failed'
    error_message TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY(tenant_id, assistant_id) REFERENCES assistants(tenant_id, id)
);

-- Document Chunks Table (Segmented text blocks for Vector Search)
CREATE TABLE document_chunks (
    id TEXT PRIMARY KEY,
    tenant_id TEXT NOT NULL,
    document_id TEXT NOT NULL,
    content TEXT NOT NULL,
    vector_id TEXT NOT NULL,
    metadata TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY(document_id) REFERENCES documents(id)
);

-- Audit Logs Table (Administrative actions log)
CREATE TABLE audit_logs (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    tenant_id TEXT NOT NULL,
    action TEXT NOT NULL,
    details TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Usage Logs Table (API call and token metrics)
CREATE TABLE usage_logs (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    tenant_id TEXT NOT NULL,
    api_key_name TEXT NOT NULL,
    model_used TEXT NOT NULL,
    response_time_ms INTEGER NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```

---

## 3. Vector Database Configuration (Vectorize)

- **Vector Dimensions**: `1024` (matches output dimensions of `@cf/baai/bge-m3` embedding model).
- **Distance Metric**: `cosine` similarity.
- **Vector ID Format**: `chunk_{document_id}_{index}`.

---

## 4. Multi-Tenant Authorization Pattern

All HTTP request headers are intercepted by a Hono middleware:
1. Extract bearer token: `Authorization: Bearer <API_KEY>`.
2. Check D1 `api_keys` to match the key hash and fetch the corresponding `tenant_id`.
3. If valid, set context variables (`tenant_id`, `tenant_name`, `api_key_name`) for subsequent handlers.
4. If invalid, return `401 Unauthorized`.

---

## 5. API Endpoints Specification

### 5.1 System Model Catalog
- **Route**: `GET /v1/models`
- **Headers**: `Authorization: Bearer <API_KEY>`
- **Description**: Returns supported local (Workers AI) and proxy-able external (Gemini, OpenAI, Claude) models.

### 5.2 Assistants Management
- **Route**: `GET /v1/assistants`
- **Route**: `POST /v1/assistants`
  - **Request JSON**: `{ "id": "hr-bot", "name": "HR Assistant", "description": "Answers HR policy questions" }`

### 5.3 Document Upload & Vectorization
- **Route**: `POST /v1/assistants/{id}/documents`
- **Headers**: `Content-Type: multipart/form-data`
- **Body**: File binary payload keyed as `file`.
- **Pipeline logic**:
  1. Save file to R2 bucket.
  2. Parse content (PDF, DOCX, XLSX, TXT, CSV).
  3. Perform text splitting into chunks of ~500 characters with 100 character overlap.
  4. Generate embeddings using `@cf/baai/bge-m3`.
  5. Insert embeddings into Vectorize index with metadata.
  6. Save chunk and document metadata to D1.

### 5.4 RAG Search & Chat Inference
- **Route**: `POST /v1/chat`
- **Headers**:
  - `Authorization: Bearer <API_KEY>`
  - `x-gemini-api-key`: Google API Key (optional)
  - `x-openai-api-key`: OpenAI API Key (optional)
  - `x-claude-api-key`: Anthropic API Key (optional)
- **Request JSON**:
  ```json
  {
    "assistant_id": "sme-km-demo",
    "question": "什麼是 FALO SME KM 平台？",
    "model": "@cf/google/gemma-4-26b-a4b-it"
  }
  ```
- **RAG Pipeline execution**:
  1. Generate query embedding from the `question`.
  2. Query Vectorize matching records where `tenant_id == active_tenant` (filters logic built into metadata metadata query).
  3. If Vectorize fails/cold-starts, fall back to D1 text SQL matching (`LIKE %keyword%`).
  4. Assemble system prompt:
     ```
     你是一個專業的企業知識助理。請根據以下官方參考資料回答使用者的問題。如果參考資料中找不到答案，請回答：「抱歉，在我的知識庫中找不到相關答案。」
     
     參考資料：
     [1] <Source Chunk 1>
     [2] <Source Chunk 2>
     ```
  5. Route inference to local Worker AI (using `env.AI.run`) or proxy to external model using provided key headers.
  6. Return dual output:
     - `answer`: Generative LLM reply (with `<think>` tags for reasoning models like DeepSeek-R1).
     - `db_standard_answer`: Direct matching record content from database.

---

## 6. Supported Models List

### Local Models (Cloudflare Workers AI - Pre-configured)
- `@cf/google/gemma-4-26b-a4b-it` (Gemma 4 26B)
- `@cf/meta/llama-3.1-8b-instruct-fp8` (Llama 3.1 8B)
- `@cf/meta/llama-3.2-3b-instruct` (Llama 3.2 3B)
- `@cf/meta/llama-3.3-70b-instruct-fp8-fast` (Llama 3.3 70B Fast)
- `@cf/meta/llama-3.1-70b-instruct` (Llama 3.1 70B Standard)
- `@cf/qwen/qwen3-30b-a3b-fp8` (Qwen 3 30B)
- `@cf/mistralai/mistral-small-3.1-24b-instruct` (Mistral Small 3.1 24B)
- `@cf/deepseek-ai/deepseek-r1-distill-qwen-32b` (DeepSeek R1 Qwen 32B)

### External Models (Proxy Gateway - Dynamic on API Key Input)
- `gemini-2.0-flash`
- `gemini-2.0-flash-lite`
- `gpt-4o-mini`
- `claude-3-5-sonnet`
