Spaces:
Build error
Configuration Management
The PDF-TEI-Editor uses JSON configuration files to manage application settings. Configuration can be managed via the command-line interface.
For programmatic use, see Configuration Processing Architecture.
Configuration Files
data/db/config.json- Runtime configuration (user-specific, gitignored)config/config.json- Default configuration (version-controlled)
Configuration Processing Architecture
Backend Processing
Configuration values are processed through a high-level API that abstracts storage details.
fastapi_app/lib/utils/config_utils.py
Provides a Config class and module-level configuration instance:
High-Level API (recommended):
from fastapi_app.lib.utils.config_utils import get_config
# Get config instance (lazy initialization)
config = get_config()
# Get configuration values
value = config.get('session.timeout', default=3600)
# Set configuration values (with validation)
success, message = config.set('session.timeout', 7200)
# Delete configuration keys
success, message = config.delete('old.key')
# Load complete configuration
config_data = config.load()
The get_config() function returns a module-level config instance preconfigured with settings.db_dir, so you don't need to pass directory paths.
Alternative - Custom Config Instance:
For testing or custom db_dir:
from fastapi_app.lib.utils.config_utils import Config
from pathlib import Path
custom_config = Config(Path('/custom/db/dir'))
value = custom_config.get('key')
Configuration Features:
- Type validation: If
<key>.typeexists, validates value matches required JSON type - Values constraints: If
<key>.valuesexists, validates value is in allowed values - Auto-typing: New keys automatically get a
.typeconstraint based on value's JSON type - Thread-safe: Uses cross-platform file locking (fcntl on Unix, msvcrt on Windows)
- Dot notation: Supports keys like
session.timeoutandsession.cookie.name
Using Configuration in Backend Routes
Configuration is accessed via get_config():
from fastapi import APIRouter
from fastapi_app.lib.utils.config_utils import get_config
router = APIRouter()
@router.get("/my-endpoint")
async def my_endpoint():
# Get config instance
config = get_config()
# Get configuration values
timeout = config.get('session.timeout', default=3600)
mode = config.get('application.mode', default='production')
return {
"timeout": timeout,
"mode": mode
}
For Settings Properties:
Access environment variables and static settings via the Settings object:
from fastapi_app.config import get_settings
settings = get_settings()
host = settings.HOST
port = settings.PORT
data_root = settings.data_root # Path property
db_dir = settings.db_dir # Path property
Settings Properties:
- Environment variables:
HOST,PORT,DATA_ROOT,WEBDAV_ENABLED,LOG_LEVEL, etc. - Path properties:
data_root,db_dir,upload_dir,config_dir - Dynamic properties:
session_timeout(checks environment, then config.json, then default) - The Settings class is cached via
@lru_cache, soget_settings()returns the same instance
Setting Config Values:
from fastapi_app.lib.utils.config_utils import get_config
from fastapi import HTTPException
@router.post("/custom-config")
async def set_custom(key: str, value: str):
# Get config instance
config = get_config()
# Write custom config value (validates constraints)
success, message = config.set(key, value)
if not success:
raise HTTPException(status_code=400, detail=message)
return {"result": message}
fastapi_app/api/config.py
REST API endpoints for configuration access:
GET /api/v1/config/list: Returns complete configuration objectGET /api/v1/config/get/{key}: Returns specific configuration value by keyPOST /api/v1/config/set: Sets a configuration value (requires authentication)- Request body:
{"key": "config.key", "value": <json_value>} - Validates user authentication via session
- Calls
set_config_value()which performs validation - Logs the configuration change with username
- Request body:
Frontend Integration
app/src/plugins/config.js
The config plugin provides client-side access to configuration:
API Methods:
get(key, defaultValue, updateFirst=false): Retrieves a configuration value. IfupdateFirstis true, fetches fresh data from server before returning.set(key, value): Sets a configuration value on the server. Validates the key exists before attempting to set.load(): Fetches configuration data from server and updates local cache.toMap(): Returns configuration as a Map object.
Usage Pattern:
import { api as config } from './plugins/config.js'; // Get a value (uses cached data) const mode = await config.get('application.mode'); // Get with fresh data from server const interval = await config.get('heartbeat.interval', 30, true); // Set a value (updates server) await config.set('application.mode', 'production'); // Reload configuration cache await config.load();Internal State:
- Maintains a local
configMapobject cached from server - Automatically loads config on first
get()call if not already loaded - Uses
client.getConfigData()to fetch from/api/v1/config/list - Uses
client.setConfigValue(key, value)to update via/api/v1/config/set
- Maintains a local
Configuration Flow
Initial Load:
- Frontend calls
config.get()for the first time - Plugin fetches complete config via
GET /api/v1/config/list - Backend calls
config.load()to readdata/db/config.json - Data is cached in
configMapobject
- Frontend calls
Reading Values:
- Frontend calls
config.get(key)using cached data - Or
config.get(key, default, true)to force server refresh - Backend uses
config.get(key, default)for server-side reads
- Frontend calls
Writing Values:
- Frontend calls
config.set(key, value) - Validates key exists in cached config (throws error if not)
- Sends
POST /api/v1/config/setwith JSON body - Backend validates authentication and session
- Backend calls
config.set(key, value)which:- Acquires file lock on
config.json - Loads current config
- Validates value constraints and type
- Writes updated config
- Releases file lock
- Acquires file lock on
- Frontend calls
CLI Usage:
- CLI calls Python functions from
bin/manage.py - Uses low-level
config_utils.pyfunctions directly - No authentication required for CLI access
- CLI calls Python functions from