Specialized database operations for Chuukese language data including dictionary management, phrase collections, translation pairs, and linguistic metadata...
All persistence is Azure Cosmos DB with MongoDB API via pymongo. There is no SQLAlchemy, no SQLite, no relational layer. Three Python classes wrap it; nothing instantiates MongoClient directly.
| File | Class / role |
|---|---|
src/database/db_factory.py |
Connection helpers (get_cosmos_client, get_database_client, get_database_config) |
src/database/dictionary_db.py |
DictionaryDB — entries, words, phrases, paragraphs, pages |
src/database/user_db.py |
UserDB — users, role/permissions, sessions, page-tracking |
src/database/publication_manager.py |
PublicationManager — publication metadata + uploads/ filesystem |
db_factory.get_cosmos_client() tries, in order:
COSMOS_MONGO_CONNECTION_STRING — direct MongoDB connection string. Preferred in production. (Older docs reference COSMOS_DB_CONNECTION_STRING; that name is not read.)USE_MANAGED_IDENTITY=true + COSMOS_ACCOUNT_NAME are set (db_factory.py).COSMOS_DB_URI + COSMOS_DB_KEY — builds the connection string locally with URL-encoded key.mongodb://localhost:27017/ as fallback.Environment variables actually consulted:
| Var | Used by |
|---|---|
COSMOS_MONGO_CONNECTION_STRING |
preferred path |
USE_MANAGED_IDENTITY (true/false) |
managed-identity gate |
COSMOS_ACCOUNT_NAME (default chuuk-dictionary-cosmos) |
both managed identity + URI build |
COSMOS_DB_URI, COSMOS_DB_KEY |
key-based auth |
retryWrites=False and appName=@<account>@ are required by Cosmos's MongoDB API and are baked into the generated connection string.
From get_database_config():
{
"database_name": "chuuk_dictionary",
"container_name": "dictionary_entries", # → DictionaryDB.dictionary_collection
"pages_container": "dictionary_pages", # → pages_collection
"words_container": "words", # → words_collection
"phrases_container": "phrases", # → phrases_collection
"paragraphs_container": "paragraphs", # → paragraphs_collection
"users_container": "users", # → UserDB.users_collection
}
The methods that actually exist (see dictionary_db.py):
search_word(word: str) -> dict | Nonesearch_words(query: str, limit: int = 50) -> list[dict]add_word(word: str, translation: str, **meta) -> strsearch_phrases(query: str, limit: int = 50) -> list[dict]add_phrase(chuukese: str, english: str, **meta) -> strdict_db.dictionary_collection.find(...)) for ad-hoc queries.There is no search_entries, bulk_insert_entries, get_all_entries, etc. Older skill docs invented those.
UserDB handles auth-adjacent state:
get_user(email), upsert_user(email, role)start_session(email) — issues a session_id, invalidates prior active session for that emailis_session_valid(email, session_id) — single-active-session enforcementtrack_page(email, page) — appends to pages_accessed, updates last_activity_at (user_db.py)email, role, session_id, session_start_at, last_activity_at, pages_accessed, accepted_terms_atPublicationManager coordinates DB metadata + the filesystem under uploads/:
create_publication(title, author, ...) — writes Cosmos doc + creates uploads/<id>/ diradd_page(pub_id, file) — saves file, adds page metadataget_publication(pub_id), list_publications()from src.database.dictionary_db import DictionaryDB
from src.database.user_db import UserDB
dict_db = DictionaryDB() # Singleton-ish — instantiate once per worker
user_db = UserDB()
# Search (escape user input!)
results = dict_db.search_words(user_query, limit=50)
# Direct collection query when method doesn't fit
import re
pattern = re.escape(user_input)
rows = dict_db.dictionary_collection.find(
{"chuukese_word": {"$regex": pattern, "$options": "i"}},
limit=50,
)
# Insert with audit fields
from datetime import datetime, timezone
dict_db.dictionary_collection.insert_one({
"chuukese_word": word,
"english_translation": meaning,
"grammar_type": pos,
"confidence_score": 0.9,
"edited_by": user_email,
"created_at": datetime.now(timezone.utc),
})
pymongo version is pinned in requirements.txt for Cosmos wire-protocol compatibility — don't bump unilaterally.retryWrites=False is mandatory (already in connection string).chuukese_word / english_translation queries.$regex flags silently — case-insensitive search via $options: "i" is fine; lookahead/lookbehind are not.DictionaryDB() is instantiated twice. Don't add per-instance caches and expect them to be coherent across requests.get_database_config() AND the DictionaryDB.__init__ block so _collection attributes stay consistent.get_database_config() does not rename the underlying Cosmos container — you must run an Azure-side migration.