This guide explains how to integrate DocEX into your platform by programmatically constructing the configuration, initializing DocEX, bootstrapping the system tenant, and validating the setup.
When integrating DocEX into your platform, you typically need to:
- Construct Configuration: Build
config.yamlfrom your platform's consolidated system settings - Initialize DocEX: Set up DocEX with the configuration
- Bootstrap System Tenant: Initialize the system tenant (required for multi-tenancy)
- Validate Setup: Confirm DocEX is properly configured and ready for use
- Provision Business Tenants: Create tenants for your platform's customers/organizations
- Use DocEX: Create baskets, add documents, and manage document operations
The is_properly_setup() method is a critical validation function that confirms DocEX is set up correctly and ready for operations. Use get_setup_errors() to get detailed error messages if validation fails.
Platform System Settings
↓
Construct config.yaml
↓
DocEX.setup(config)
↓
BootstrapTenantManager.initialize()
↓
DocEX.is_properly_setup() / DocEX.get_setup_errors()
↓
TenantProvisioner.create() (for business tenants)
↓
DocEX(user_context=UserContext(user_id, tenant_id))
↓
docex.create_basket() → basket.add() → basket.list_documents()
↓
✅ DocEX Ready for Use
Build the DocEX configuration dictionary from your platform's system settings. The configuration should match the structure expected by DocEX.
from pathlib import Path
from docex.config.docex_config import DocEXConfig
def build_docex_config_from_platform(platform_settings):
"""
Construct DocEX configuration from platform system settings.
Args:
platform_settings: Dictionary containing platform configuration
Returns:
Dictionary with DocEX configuration structure
"""
# Extract database settings from platform
db_type = platform_settings.get('database_type', 'sqlite') # 'sqlite' or 'postgresql'
config = {
'database': {
'type': db_type,
},
'storage': {
'type': platform_settings.get('storage_type', 'filesystem'),
},
'logging': {
'level': platform_settings.get('log_level', 'INFO'),
'file': platform_settings.get('log_file', 'docex.log'),
},
}
# Add database-specific configuration
if db_type == 'sqlite':
db_path = platform_settings.get('sqlite_path', 'docex.db')
config['database']['sqlite'] = {
'path': db_path,
}
elif db_type == 'postgresql':
config['database']['postgres'] = {
'host': platform_settings.get('db_host', 'localhost'),
'port': platform_settings.get('db_port', 5432),
'database': platform_settings.get('db_name', 'docex'),
'user': platform_settings.get('db_user', 'postgres'),
'password': platform_settings.get('db_password', ''),
}
# Add storage-specific configuration
storage_type = config['storage']['type']
if storage_type == 'filesystem':
storage_path = platform_settings.get('storage_path', 'storage/docex')
config['storage']['filesystem'] = {
'path': storage_path,
}
elif storage_type == 's3':
config['storage']['s3'] = {
'bucket': platform_settings.get('s3_bucket'),
'region': platform_settings.get('s3_region', 'us-east-1'),
'path_namespace': platform_settings.get('s3_path_namespace', ''),
'prefix': platform_settings.get('s3_prefix', 'production'),
'access_key': platform_settings.get('aws_access_key'),
'secret_key': platform_settings.get('aws_secret_key'),
}
# Note: S3 path structure uses three parts:
# Part A (config_prefix): {tenant_id}/{path_namespace}/{prefix}/ - set automatically
# Part B (basket_path): {basket_name}_{last_4_of_basket_id}/ - set when basket is created
# Part C (document_path): {document_name}_{last_6_of_document_id}.{ext} - stored in document.path
# Full path = Part A + Part B + Part C
# Add multi-tenancy configuration if enabled
if platform_settings.get('multi_tenancy_enabled', False):
config['multi_tenancy'] = {
'enabled': True,
'isolation_strategy': 'schema' if db_type == 'postgresql' else 'database',
'bootstrap_tenant': {
'id': '_docex_system_',
'display_name': 'DocEX System',
'schema': 'docex_system',
'database_path': 'storage/_docex_system_/docex.db' if db_type == 'sqlite' else None,
},
}
return configUse DocEX.setup() to initialize DocEX with your constructed configuration. This saves the configuration to ~/.docex/config.yaml and prepares DocEX for use.
from docex import DocEX
def initialize_docex(platform_settings):
"""
Initialize DocEX from platform settings.
Args:
platform_settings: Dictionary containing platform configuration
Returns:
True if initialization successful, False otherwise
"""
try:
# Build configuration from platform settings
config = build_docex_config_from_platform(platform_settings)
# Initialize DocEX with configuration
DocEX.setup(**config)
print("✅ DocEX configuration initialized")
return True
except Exception as e:
print(f"❌ Failed to initialize DocEX: {e}")
return FalseIf multi-tenancy is enabled, you must initialize the bootstrap/system tenant. This tenant manages the tenant registry and system metadata.
from docex.provisioning.bootstrap import BootstrapTenantManager
def bootstrap_system_tenant(created_by: str = "platform"):
"""
Bootstrap the system tenant for DocEX.
Args:
created_by: User ID who is initializing the system
Returns:
True if bootstrap successful, False otherwise
"""
try:
bootstrap_manager = BootstrapTenantManager()
# Check if already initialized
if bootstrap_manager.is_initialized():
print("✅ Bootstrap tenant already initialized")
return True
# Initialize bootstrap tenant
bootstrap_manager.initialize(created_by=created_by)
print("✅ Bootstrap tenant initialized")
return True
except Exception as e:
print(f"❌ Failed to bootstrap system tenant: {e}")
return FalseUse DocEX.is_initialized() or DocEX.is_properly_setup() to validate that DocEX is correctly configured and ready for use.
Checks if DocEX configuration is loaded and valid:
def validate_docex_initialization():
"""
Validate that DocEX is initialized.
Returns:
True if initialized, False otherwise
"""
if DocEX.is_initialized():
print("✅ DocEX is initialized")
return True
else:
print("❌ DocEX is not initialized")
return FalsePerforms comprehensive validation including:
- Configuration file exists and is valid
- Database is accessible
- Required tables exist
- Bootstrap tenant exists (if multi-tenancy enabled)
def validate_docex_setup():
"""
Validate that DocEX is properly set up and ready for use.
Returns:
True if properly set up, False otherwise
"""
if DocEX.is_properly_setup():
print("✅ DocEX is properly set up and ready for use")
return True
else:
# Get detailed error messages
errors = DocEX.get_setup_errors()
print("❌ DocEX is not properly set up")
for error in errors:
print(f" - {error}")
return FalseReturns a list of detailed error messages if setup validation fails:
def get_setup_errors():
"""
Get detailed setup error messages.
Returns:
List of error messages (empty if setup is valid)
"""
errors = DocEX.get_setup_errors()
if errors:
print("Setup errors found:")
for error in errors:
print(f" - {error}")
else:
print("✅ No setup errors")
return errorsHere's a basic integration example that covers initialization and validation:
from docex import DocEX
from docex.provisioning.bootstrap import BootstrapTenantManager
def integrate_docex_into_platform(platform_settings):
"""
Basic integration flow: configure, initialize, bootstrap, and validate DocEX.
Args:
platform_settings: Dictionary containing platform configuration
Returns:
Tuple of (success: bool, message: str)
"""
try:
# Step 1: Build configuration from platform settings
print("Step 1: Building DocEX configuration from platform settings...")
config = build_docex_config_from_platform(platform_settings)
# Step 2: Initialize DocEX
print("Step 2: Initializing DocEX...")
DocEX.setup(**config)
print("✅ DocEX configuration initialized")
# Step 3: Bootstrap system tenant (if multi-tenancy enabled)
multi_tenancy_enabled = platform_settings.get('multi_tenancy_enabled', False)
if multi_tenancy_enabled:
print("Step 3: Bootstrapping system tenant...")
bootstrap_manager = BootstrapTenantManager()
if not bootstrap_manager.is_initialized():
bootstrap_manager.initialize(created_by=platform_settings.get('admin_user', 'platform'))
print("✅ Bootstrap tenant initialized")
else:
print("✅ Bootstrap tenant already initialized")
# Step 4: Validate setup
print("Step 4: Validating DocEX setup...")
if not DocEX.is_initialized():
return False, "DocEX configuration not initialized"
if not DocEX.is_properly_setup():
errors = DocEX.get_setup_errors()
return False, f"DocEX is not properly set up: {', '.join(errors)}"
print("✅ DocEX is properly initialized and ready for use")
return True, "DocEX integration successful"
except Exception as e:
error_msg = f"Failed to integrate DocEX: {str(e)}"
print(f"❌ {error_msg}")
return False, error_msgIf your platform generates a config.yaml file, you can load it directly:
import yaml
from pathlib import Path
from docex import DocEX
from docex.config.docex_config import DocEXConfig
def initialize_docex_from_config_file(config_file_path: Path):
"""
Initialize DocEX from a configuration file.
Args:
config_file_path: Path to config.yaml file
Returns:
True if successful, False otherwise
"""
try:
# Load configuration from file
with open(config_file_path, 'r') as f:
config_dict = yaml.safe_load(f)
# Initialize DocEX
DocEX.setup(**config_dict)
# Bootstrap system tenant if multi-tenancy enabled
config = DocEXConfig()
multi_tenancy_config = config.get('multi_tenancy', {})
if multi_tenancy_config.get('enabled', False):
bootstrap_manager = BootstrapTenantManager()
if not bootstrap_manager.is_initialized():
bootstrap_manager.initialize(created_by='platform')
# Validate
if DocEX.is_properly_setup():
print("✅ DocEX initialized from config file")
return True
else:
print("❌ DocEX setup validation failed")
return False
except Exception as e:
print(f"❌ Failed to initialize from config file: {e}")
return FalseWhen constructing config.yaml, ensure it follows this structure:
database:
type: postgresql # or 'sqlite'
postgres:
host: localhost
port: 5432
database: docex
user: postgres
password: password
sqlite:
path: docex.db
storage:
type: s3 # or 'filesystem'
filesystem:
path: storage/docex
s3:
bucket: my-bucket
region: us-east-1
path_namespace: production
prefix: prod
multi_tenancy:
enabled: true
isolation_strategy: schema # or 'database'
bootstrap_tenant:
id: _docex_system_
display_name: DocEX System
schema: docex_system
database_path: null # Only for SQLite
logging:
level: INFO
file: docex.log| Method | Checks | Use Case |
|---|---|---|
DocEX.is_initialized() |
Configuration file exists and is valid | Quick check if config is loaded |
DocEX.is_properly_setup() |
Config + Database + Tables + Bootstrap tenant | Comprehensive validation before operations |
DocEX.get_setup_errors() |
Returns list of detailed error messages | Get specific issues when setup fails |
BootstrapTenantManager.is_initialized() |
Bootstrap tenant exists in registry | Check if system tenant is ready |
TenantProvisioner.tenant_exists(tenant_id) |
Check if a tenant is already provisioned | Verify tenant before provisioning |
Recommendation: Use DocEX.is_properly_setup() for platform integration validation. If it returns False, call DocEX.get_setup_errors() to get detailed error messages.
Always wrap initialization in try-except blocks and handle common errors:
def safe_docex_initialization(platform_settings):
"""Safely initialize DocEX with error handling."""
try:
# Build and apply configuration
config = build_docex_config_from_platform(platform_settings)
DocEX.setup(**config)
# Bootstrap if needed
if config.get('multi_tenancy', {}).get('enabled', False):
bootstrap_manager = BootstrapTenantManager()
if not bootstrap_manager.is_initialized():
bootstrap_manager.initialize()
# Validate
if not DocEX.is_properly_setup():
raise RuntimeError("DocEX setup validation failed")
return True
except FileNotFoundError as e:
print(f"Configuration file error: {e}")
return False
except ConnectionError as e:
print(f"Database connection error: {e}")
return False
except ValueError as e:
print(f"Configuration validation error: {e}")
return False
except Exception as e:
print(f"Unexpected error: {e}")
return False- Always Validate: Use
DocEX.is_properly_setup()after initialization to ensure everything is ready. UseDocEX.get_setup_errors()to get detailed error messages if validation fails. - Idempotent Operations:
- Check
BootstrapTenantManager.is_initialized()before callinginitialize()to avoid errors - Check
TenantProvisioner.tenant_exists(tenant_id)before provisioning tenants
- Check
- UserContext Requirements: When multi-tenancy is enabled, always provide
UserContextwithuser_id(required) andtenant_id(required for multi-tenant operations) - Error Handling: Wrap initialization in try-except blocks and provide meaningful error messages. Handle
TenantExistsErrorandInvalidTenantIdErrorwhen provisioning tenants. - Configuration Validation: Validate platform settings before constructing DocEX configuration
- Logging: Enable appropriate logging levels to track initialization progress
- Storage Permissions: Ensure storage directories/filesystem paths have proper write permissions
- Database Credentials: Securely manage database credentials (use environment variables or secrets management)
- S3 Path Structure: Understand the three-part S3 path structure (Part A: config, Part B: basket, Part C: document) for debugging and path verification
- Document Path Storage: Documents store full paths in
document.pathfor simplicity. For S3: full path = Part A + Part B + Part C. For filesystem: full relative path = Part B + Part C. - Basket Storage Config: Baskets store path components separately in
storage_config['s3']:config_prefix: Part A (config-based prefix)basket_path: Part B (basket-specific path)prefix: Combined A + B (for backward compatibility)
Error: Configuration file not found at ~/.docex/config.yaml
Solution: Ensure DocEX.setup() is called before using DocEX, or manually create the config file.
Error: Database connectivity check failed
Solution: Verify database credentials, network connectivity, and that the database server is running.
Error: Multi-tenancy enabled but bootstrap tenant not initialized
Solution: Call BootstrapTenantManager().initialize() after DocEX.setup().
Error: Missing required tables: ['docbasket', 'document', ...]
Solution: Ensure database schema is created. DocEX should create tables automatically, but verify database permissions.
After bootstrapping the system tenant, you can provision business tenants for your platform's customers or organizations.
from docex.provisioning.tenant_provisioner import TenantProvisioner
from docex.provisioning.tenant_provisioner import TenantExistsError, InvalidTenantIdError
def provision_business_tenant(tenant_id: str, display_name: str, created_by: str):
"""
Provision a new business tenant.
Args:
tenant_id: Unique identifier for the tenant (1-30 chars, letters/numbers/underscores only)
display_name: Human-readable name for the tenant
created_by: User ID who is creating the tenant
Returns:
TenantRegistry instance for the newly created tenant
"""
try:
provisioner = TenantProvisioner()
# Check if tenant already exists
if provisioner.tenant_exists(tenant_id):
print(f"⚠️ Tenant '{tenant_id}' already exists")
return None
# Provision the tenant
tenant_registry = provisioner.create(
tenant_id=tenant_id,
display_name=display_name,
created_by=created_by
# isolation_strategy is auto-detected based on database type
)
print(f"✅ Tenant '{tenant_id}' provisioned successfully")
return tenant_registry
except InvalidTenantIdError as e:
print(f"❌ Invalid tenant ID: {e}")
return None
except TenantExistsError as e:
print(f"❌ {e}")
return None
except Exception as e:
print(f"❌ Failed to provision tenant: {e}")
return NoneThe TenantProvisioner.create() method performs the following steps:
- Validates tenant ID: Ensures it's not reserved and follows naming rules
- Checks for existing tenant: Prevents duplicate provisioning
- Creates isolation boundary:
- PostgreSQL: Creates a schema (e.g.,
tenant_acme_corp) - SQLite: Creates a separate database file
- PostgreSQL: Creates a schema (e.g.,
- Initializes schema: Creates all required tables in the tenant's schema/database
- Creates performance indexes: Optimizes queries for the tenant
- Validates schema: Verifies all tables and indexes are created correctly
- Registers tenant: Adds tenant to the tenant registry
def provision_platform_tenants(tenant_list):
"""
Provision multiple tenants for your platform.
Args:
tenant_list: List of dicts with 'tenant_id', 'display_name', 'created_by'
"""
provisioner = TenantProvisioner()
results = []
for tenant_info in tenant_list:
tenant_id = tenant_info['tenant_id']
display_name = tenant_info['display_name']
created_by = tenant_info.get('created_by', 'platform')
try:
if provisioner.tenant_exists(tenant_id):
print(f"⚠️ Tenant '{tenant_id}' already exists, skipping...")
results.append({'tenant_id': tenant_id, 'status': 'exists'})
continue
tenant_registry = provisioner.create(
tenant_id=tenant_id,
display_name=display_name,
created_by=created_by
)
results.append({'tenant_id': tenant_id, 'status': 'created', 'registry': tenant_registry})
print(f"✅ Provisioned tenant: {tenant_id}")
except Exception as e:
results.append({'tenant_id': tenant_id, 'status': 'error', 'error': str(e)})
print(f"❌ Failed to provision tenant '{tenant_id}': {e}")
return results
# Example usage
tenants = [
{'tenant_id': 'acme_corp', 'display_name': 'Acme Corporation', 'created_by': 'admin'},
{'tenant_id': 'contoso', 'display_name': 'Contoso Ltd', 'created_by': 'admin'},
{'tenant_id': 'fabrikam', 'display_name': 'Fabrikam Inc', 'created_by': 'admin'},
]
results = provision_platform_tenants(tenants)After provisioning tenants, you can use DocEX with tenant-specific operations.
Important: When multi-tenancy is enabled, you must provide a UserContext with user_id and tenant_id:
from docex import DocEX
from docex.context import UserContext
def create_docex_for_tenant(tenant_id: str, user_id: str):
"""
Create a DocEX instance for a specific tenant.
Args:
tenant_id: Tenant identifier
user_id: User identifier (required)
Returns:
DocEX instance configured for the tenant
"""
# UserContext requires user_id (mandatory)
# tenant_id is optional but required for multi-tenant setups
user_context = UserContext(
user_id=user_id, # Required
tenant_id=tenant_id # Required for multi-tenant
)
docex = DocEX(user_context=user_context)
return docexBaskets can be created with different storage types (S3 or filesystem):
def create_baskets_for_tenant(docex: DocEX):
"""
Create baskets for a tenant with different storage configurations.
"""
# Create a filesystem basket (default)
fs_basket = docex.create_basket(
name="invoices_pending",
description="Pending invoices awaiting processing"
)
print(f"✅ Created filesystem basket: {fs_basket.id}")
# Create an S3 basket
s3_storage_config = {
'type': 's3',
's3': {
'bucket': 'my-documents-bucket',
'region': 'us-east-1',
'path_namespace': 'production',
'prefix': 'prod',
'access_key': 'AKIA...',
'secret_key': '...'
}
}
s3_basket = docex.create_basket(
name="invoices_processed",
description="Processed invoices archive",
storage_config=s3_storage_config
)
print(f"✅ Created S3 basket: {s3_basket.id}")
# Verify basket storage configuration
print(f"Filesystem basket storage type: {fs_basket.storage_config.get('type')}")
print(f"S3 basket storage type: {s3_basket.storage_config.get('type')}")
# For S3 baskets, check path structure components
if s3_basket.storage_config.get('type') == 's3':
s3_config = s3_basket.storage_config.get('s3', {})
print(f"S3 Config Prefix (Part A): {s3_config.get('config_prefix')}")
print(f"S3 Basket Path (Part B): {s3_config.get('basket_path')}")
print(f"S3 Full Prefix (A+B): {s3_config.get('prefix')}")
return fs_basket, s3_basketDocuments are added using the basket.add() method:
from pathlib import Path
def add_documents_to_basket(basket, file_paths: list):
"""
Add multiple documents to a basket.
Args:
basket: DocBasket instance
file_paths: List of file paths to add
"""
documents = []
for file_path in file_paths:
# Add document with optional metadata
doc = basket.add(
file_path=str(file_path),
document_type='file',
metadata={
'source': 'platform_upload',
'uploaded_by': 'user123',
'category': 'invoice'
}
)
documents.append(doc)
print(f"✅ Added document: {doc.id} ({doc.name})")
# Document path contains full storage path
# For S3: Full path = Part A + Part B + Part C
# For filesystem: Full relative path = Part B + Part C
print(f" Storage path: {doc.path}")
return documentsdef retrieve_documents_from_basket(basket):
"""
Retrieve documents from a basket using various methods.
"""
# List all documents
all_docs = basket.list_documents()
print(f"📋 Total documents: {len(all_docs)}")
# Get document by ID
if all_docs:
doc = basket.get_document(all_docs[0].id)
print(f"✅ Retrieved document by ID: {doc.id}")
# Get document content
# For text files
if doc.content_type and 'text' in doc.content_type:
content = doc.get_content(mode='text')
print(f" Content length: {len(content)} characters")
# For binary files
else:
content = doc.get_content(mode='bytes')
print(f" Content length: {len(content)} bytes")
# Find documents by metadata
invoice_docs = basket.find_documents_by_metadata({'category': 'invoice'})
print(f"📋 Found {len(invoice_docs)} invoice documents")
# Count documents
doc_count = basket.count_documents()
print(f"📊 Document count: {doc_count}")
return all_docsWhen using S3 storage, DocEX uses a three-part path structure:
- Part A (Config Prefix):
{tenant_id}/{path_namespace}/{prefix}/- Stored in:
basket.storage_config['s3']['config_prefix']
- Stored in:
- Part B (Basket Path):
{basket_friendly_name}_{last_4_of_basket_id}/- Stored in:
basket.storage_config['s3']['basket_path']
- Stored in:
- Part C (Document Path):
{document_friendly_name}_{last_6_of_document_id}.{ext}- Stored in:
document.path(full path = A + B + C)
- Stored in:
Example S3 Path:
s3://my-bucket/acme_corp/finance_dept/production/invoice_raw_2c03/invoice_001_585d29.pdf
- Part A:
acme_corp/finance_dept/production/ - Part B:
invoice_raw_2c03/ - Part C:
invoice_001_585d29.pdf
See S3_PATH_STRUCTURE.md for detailed documentation.
Here's a complete example that ties everything together:
from docex import DocEX
from docex.provisioning.bootstrap import BootstrapTenantManager
from docex.provisioning.tenant_provisioner import TenantProvisioner
from docex.context import UserContext
from pathlib import Path
def complete_platform_integration(platform_settings):
"""
Complete integration flow: configure, initialize, bootstrap, provision, and use DocEX.
"""
try:
# Step 1: Build configuration
print("Step 1: Building DocEX configuration...")
config = build_docex_config_from_platform(platform_settings)
# Step 2: Initialize DocEX
print("Step 2: Initializing DocEX...")
DocEX.setup(**config)
print("✅ DocEX configuration initialized")
# Step 3: Bootstrap system tenant
multi_tenancy_enabled = platform_settings.get('multi_tenancy_enabled', False)
if multi_tenancy_enabled:
print("Step 3: Bootstrapping system tenant...")
bootstrap_manager = BootstrapTenantManager()
if not bootstrap_manager.is_initialized():
bootstrap_manager.initialize(created_by=platform_settings.get('admin_user', 'platform'))
print("✅ Bootstrap tenant initialized")
# Step 4: Validate setup
print("Step 4: Validating DocEX setup...")
if not DocEX.is_properly_setup():
return False, "DocEX is not properly set up"
print("✅ DocEX is properly set up")
# Step 5: Provision business tenant
if multi_tenancy_enabled:
print("Step 5: Provisioning business tenant...")
provisioner = TenantProvisioner()
tenant_id = platform_settings.get('default_tenant_id', 'acme_corp')
if not provisioner.tenant_exists(tenant_id):
provisioner.create(
tenant_id=tenant_id,
display_name=platform_settings.get('default_tenant_name', 'Acme Corporation'),
created_by=platform_settings.get('admin_user', 'platform')
)
print(f"✅ Tenant '{tenant_id}' provisioned")
else:
print(f"✅ Tenant '{tenant_id}' already exists")
# Step 6: Use DocEX with tenant
print("Step 6: Using DocEX with tenant...")
user_context = UserContext(
user_id=platform_settings.get('admin_user', 'platform'),
tenant_id=tenant_id if multi_tenancy_enabled else None
)
docex = DocEX(user_context=user_context)
# Create a basket
basket = docex.create_basket(
name="test_basket",
description="Test basket for integration"
)
print(f"✅ Created basket: {basket.id}")
# Add a test document
test_file = Path('/tmp/test_document.txt')
test_file.write_text('Test document content')
doc = basket.add(str(test_file), metadata={'test': True})
print(f"✅ Added document: {doc.id}")
# Verify document retrieval
retrieved_doc = basket.get_document(doc.id)
if retrieved_doc:
print(f"✅ Retrieved document: {retrieved_doc.id}")
print(f" Document path: {retrieved_doc.path}")
# Cleanup
test_file.unlink()
basket.delete()
print("✅ Complete integration successful")
return True, "Integration successful"
except Exception as e:
error_msg = f"Failed to integrate DocEX: {str(e)}"
print(f"❌ {error_msg}")
return False, error_msgAfter successful initialization and tenant provisioning:
- Provision Tenants: Use
TenantProvisioner.create()to create business tenants - Create DocEX Instance: Initialize
DocEX(user_context=UserContext(user_id='...', tenant_id='...')) - Create Baskets: Use
docex.create_basket()to create document baskets (S3 or filesystem) - Add Documents: Use
basket.add(file_path, metadata={...})to add documents - Retrieve Documents: Use
basket.get_document(id),basket.list_documents(), orbasket.find_documents_by_metadata() - Get Document Content: Use
document.get_content(mode='text'|'bytes'|'json')
See MULTI_TENANCY_GUIDE.md for more details on tenant management. See S3_PATH_STRUCTURE.md for details on S3 path structure.