Skip to main content

Database Schema Reference

Cheeko uses DigitalOcean Managed PostgreSQL with Prisma ORM. This page documents every model in the schema, grouped by domain.

Entity Relationship Overview

Users and Auth

  • sys_user — core user account
  • sys_user_token — session tokens
  • parent_profile — parent-facing profile and notification preferences
  • user_question_quota — monthly RFID question usage quota per user

Devices

  • ai_device — registered ESP32 devices
  • device_memories — per-device daily memory files
  • device_token_usage — daily LLM token and latency metrics per device

Agents and AI

  • ai_agent — user-created agent configurations
  • ai_agent_template — pre-built agent templates
  • ai_agent_chat_history — per-session chat turns
  • ai_model_provider — model provider registry
  • ai_model_config — individual model configurations
  • ai_tts_voice — TTS voice definitions

Content

  • ai_music — music tracks
  • ai_story — story audio content
  • ai_textbook — textbook entries
  • ai_textbook_chapter — chapters within a textbook
  • content_library — unified content catalogue
  • device_playlist — per-device content playlist
  • music_playlist — device-specific music ordering
  • story_playlist — device-specific story ordering

RFID

  • rfid_series — UID range-to-content mappings
  • rfid_pack — question pack groups
  • rfid_content_pack — content packs (prompts, audio)
  • rfid_question_pack — bundles of questions referenced by ID list
  • rfid_question — individual RFID-triggered questions
  • rfid_card_mapping — explicit UID-to-content assignments
  • rfid_content_pack — content packs with cached audio
  • content_item — individual items within a content pack
  • ai_rfid_tag — legacy RFID tag definitions
  • ai_rfid_scan_log — legacy scan event log
  • rfid_tags — simplified RFID tag registry
  • rfid_scan_log — simplified scan log

Kids

  • kid_profile — child profile linked to a parent user
  • kid_activity_log — per-child activity events
  • kid_learning_progress — per-child subject/topic progress

Analytics

  • analytics_game_sessions — game session summaries
  • analytics_game_attempts — individual question attempts within a session
  • analytics_media_playback — media play/pause/complete events
  • analytics_streaks — daily usage streak tracking
  • analytics_user_progress — aggregate per-device progress counters
  • game_session — legacy game session records

System

  • sys_params — key-value system configuration parameters
  • sys_dict_type — dictionary category definitions
  • sys_dict_data — dictionary entries
  • email_report_config — scheduled email report configuration
  • email_report_history — history of sent email reports
  • ai_ota — OTA firmware release records
  • openclaw_pair_tokens — short-lived pairing tokens for OpenClaw integration
  • memory_chunks — text chunks with pgvector embeddings for semantic retrieval

Model Details

sys_user

Purpose: Core user account. All other user-linked models reference this table.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
firebase_uidString (128)YesFirebase Auth UID (unique)
usernameString (100)YesUnique login username
passwordString (255)YesHashed password
emailString (255)YesUnique email address
phoneString (50)YesPhone number
nicknameString (100)YesDisplay name
avatarString (500)YesAvatar URL
genderIntYes0 = unset, 1 = male, 2 = female
statusIntYes1 = active, 0 = disabled
roleString (50)YesUser role (default: "user")
last_login_atDateTimeYesTimestamp of last login
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

sys_user_token

Purpose: Session tokens issued at login, used to authenticate API requests.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
user_idBigIntNoFK to sys_user
tokenString (500)NoToken value
expire_dateDateTimeNoToken expiry timestamp
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

parent_profile

Purpose: Extended profile for parent users, covering notification preferences and OpenClaw integration credentials.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
user_idBigIntYesUnique FK to sys_user
emailString (255)YesContact email
phone_numberString (50)YesContact phone
display_nameString (255)YesDisplay name
avatar_urlString (500)YesAvatar image URL
timezoneString (50)YesUser timezone
languageString (10)YesPreferred language (default: "en")
email_notificationsBooleanYesEmail notification opt-in (default: true)
push_notificationsBooleanYesPush notification opt-in (default: true)
weekly_reportBooleanYesWeekly report opt-in (default: true)
onboarding_completedBooleanYesWhether onboarding flow is done
terms_accepted_atDateTimeYesTimestamp when terms were accepted
terms_versionString (20)YesVersion of terms accepted
openclaw_urlStringYesOpenClaw server URL for this parent
openclaw_tokenStringYesOpenClaw auth token
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

user_question_quota

Purpose: Tracks how many RFID-triggered questions a user has consumed in a given calendar month and how many extra questions have been purchased.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
user_idBigIntNoFK to sys_user
month_keyString (7)NoMonth identifier in YYYY-MM format
questions_usedIntNoQuestions consumed this month (default: 0)
extra_purchasedIntNoAdditional questions purchased (default: 0)
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

Unique constraint: (user_id, month_key).


ai_device

Purpose: Registered ESP32 Cheeko devices, linking a physical MAC address to a user, agent configuration, and child profile.

FieldTypeNullableDescription
idUUIDNoPrimary key
user_idBigIntYesFK to sys_user (owner)
mac_addressString (20)NoUnique device MAC address
last_connected_atDateTimeYesLast MQTT connection timestamp
auto_updateSmallIntYesOTA auto-update enabled (default: 1)
boardString (100)YesBoard hardware identifier
aliasString (255)YesHuman-friendly device name
agent_idUUIDYesActive agent configuration
kid_idBigIntYesAssociated child profile
modeString (50)YesInteraction mode (default: "conversation")
device_modeString (50)YesUpdate mode: "auto" or "manual"
app_versionString (50)YesInstalled firmware version
sortIntYesDisplay sort order
creatorBigIntYesUser ID who created the record
create_dateDateTimeYesRecord creation time
updaterBigIntYesUser ID of last updater
update_dateDateTimeYesRecord update time
openclaw_urlStringYesOpenClaw server URL for this device
openclaw_tokenStringYesOpenClaw auth token for this device

device_memories

Purpose: Stores per-device memory files (e.g., daily summaries, personality notes) keyed by MAC address, file type, and date. The content field holds the raw text of the memory file.

FieldTypeNullableDescription
idUUIDNoPrimary key
mac_idStringNoDevice MAC address
file_typeStringNoMemory file category (e.g., "daily", "personality")
file_dateDateTime (Date)YesDate the memory file applies to
contentStringNoText content of the memory (default: "")
updated_atDateTimeYesLast update timestamp

Unique constraint: (mac_id, file_type, file_date). Partial index on file_date where file_date IS NOT NULL.


device_token_usage

Purpose: Aggregates daily LLM token consumption and latency metrics per device. One row per (mac_address, usage_date).

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
mac_addressString (50)NoDevice MAC address
session_idString (100)YesLast contributing session ID
input_tokensIntYesTotal input tokens (default: 0)
output_tokensIntYesTotal output tokens (default: 0)
total_tokensIntYesSum of input + output (default: 0)
input_audio_tokensIntYesAudio-modality input tokens
input_text_tokensIntYesText-modality input tokens
input_cached_tokensIntYesTokens served from cache
output_audio_tokensIntYesAudio-modality output tokens
output_text_tokensIntYesText-modality output tokens
avg_ttft_secondsDecimal (10,3)YesAverage time-to-first-token in seconds
message_countIntYesTotal messages in the day
session_duration_secondsDecimal (10,3)YesTotal session duration
total_response_duration_secondsDecimal (10,3)YesTotal time spent generating responses
session_countIntYesNumber of sessions
usage_dateDateTime (Date)NoReporting date
created_atDateTimeYesRecord creation time
update_dateDateTimeYesRecord update time

Unique constraint: (mac_address, usage_date).


ai_agent

Purpose: A user-configured AI agent that defines which ASR, LLM, TTS, and other models to use, along with the system prompt and language settings.

FieldTypeNullableDescription
idUUIDNoPrimary key
user_idBigIntYesFK to sys_user (owner)
agent_codeString (100)YesShort identifier code
agent_nameString (200)NoDisplay name
asr_model_idUUIDYesFK to ai_model_config (ASR)
vad_model_idUUIDYesFK to ai_model_config (VAD)
llm_model_idUUIDYesFK to ai_model_config (LLM)
vllm_model_idUUIDYesFK to ai_model_config (vision LLM)
tts_model_idUUIDYesFK to ai_model_config (TTS)
tts_voice_idUUIDYesFK to ai_tts_voice
mem_model_idUUIDYesFK to ai_model_config (memory)
intent_model_idUUIDYesFK to ai_model_config (intent)
chat_history_confIntYesChat history window size (default: 0)
system_promptStringYesBase system prompt text
summary_memoryStringYesPersisted summary memory string
lang_codeString (10)YesBCP-47 language code (default: "en")
languageString (50)YesLanguage name (default: "English")
sortIntYesDisplay sort order
statusIntYes1 = active, 0 = disabled
creatorBigIntYesCreating user ID
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

ai_agent_chat_history

Purpose: Individual chat turns (user or assistant) recorded during a LiveKit session.

FieldTypeNullableDescription
idUUIDNoPrimary key
mac_addressString (20)YesDevice that generated the turn
agent_idUUIDYesFK to ai_agent
session_idString (100)NoLiveKit session identifier
chat_typeIntNoMessage role (e.g., 1 = user, 2 = assistant)
contentStringYesMessage text
audio_idString (100)YesAssociated audio file ID
created_atDateTimeYesTimestamp of the turn

ai_music

Purpose: Catalog entry for a music track available for playback on devices.

FieldTypeNullableDescription
idUUIDNoPrimary key
titleString (300)NoTrack title
artistString (200)YesArtist name
albumString (200)YesAlbum name
categoryString (100)YesGenre or category
languageString (50)YesTrack language
durationIntYesDuration in seconds
file_urlString (500)YesAudio file URL
cover_urlString (500)YesCover art URL
lyricsStringYesLyrics text
sortIntYesDisplay sort order
statusIntYes1 = active
creatorBigIntYesCreating user ID
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

ai_story

Purpose: Catalog entry for an audio story available for playback on devices.

FieldTypeNullableDescription
idUUIDNoPrimary key
titleString (300)NoStory title
authorString (200)YesAuthor name
categoryString (100)YesStory category
languageString (50)YesStory language
age_groupString (50)YesTarget age group
durationIntYesDuration in seconds
contentStringYesStory text content
audio_urlString (500)YesAudio file URL
cover_urlString (500)YesCover image URL
sortIntYesDisplay sort order
statusIntYes1 = active
creatorBigIntYesCreating user ID
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

ai_textbook

Purpose: A textbook entry that groups chapters for curriculum-aligned learning.

FieldTypeNullableDescription
idUUIDNoPrimary key
titleString (300)NoTextbook title
subjectString (100)YesSubject area
gradeString (50)YesGrade level
languageString (50)YesLanguage
publisherString (200)YesPublisher name
cover_urlString (500)YesCover image URL
descriptionStringYesTextbook description
sortIntYesDisplay sort order
statusIntYes1 = active
creatorBigIntYesCreating user ID
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

content_library

Purpose: Unified content catalogue entry that can represent music, stories, or other media types.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
content_typeString (50)NoType: "music", "story", etc.
titleString (500)NoContent title
descriptionStringYesDescription text
urlString (1000)YesMedia URL
thumbnail_urlString (500)YesThumbnail image URL
duration_secondsIntYesDuration in seconds
categoryString (100)YesCategory label
tagsJsonYesArray of tag strings
age_minIntYesMinimum recommended age
age_maxIntYesMaximum recommended age
languageString (50)YesContent language (default: "en")
metadataJsonYesArbitrary extra metadata
statusIntYes1 = active
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

device_playlist

Purpose: Associates content library items with a device as a playlist entry.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
device_idBigIntYesDevice identifier (legacy integer)
mac_addressString (50)YesDevice MAC address
content_idBigIntYesFK to content_library
playlist_typeString (50)YesPlaylist category (default: "music")
positionIntYesOrdering position
created_atDateTimeYesRecord creation time

rfid_series

Purpose: Maps a contiguous range of RFID UIDs (start_uid to end_uid) to a content pack, question, or question pack. This allows a batch of physical RFID cards to be configured without individual UID entries.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
series_nameString (255)NoHuman-readable series name
start_uidString (100)NoFirst UID in the range
end_uidString (100)NoLast UID in the range
content_pack_idBigIntYesFK to rfid_pack (question group)
question_idBigIntYesFK to rfid_question
content_ref_idBigIntYesFK to rfid_content_pack (audio/prompt content)
question_pack_idBigIntYesFK to rfid_question_pack
priorityIntYesResolution priority when ranges overlap (default: 0)
notesString (500)YesInternal notes
statusIntYes1 = active
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

rfid_pack

Purpose: Groups rfid_series entries under a named pack, representing a physical card pack product.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
pack_nameString (255)NoDisplay name
pack_codeString (100)YesShort code identifier
descriptionStringYesPack description
age_minIntYesMinimum recommended age
age_maxIntYesMaximum recommended age
languageString (50)YesPack language (default: "en")
activeBooleanYesWhether the pack is active
statusIntYes1 = active
creatorBigIntYesCreating user ID
create_dateDateTimeYesRecord creation time
updaterBigIntYesLast updater user ID
update_dateDateTimeYesRecord update time
created_atDateTimeYesAlias creation timestamp
updated_atDateTimeYesAlias update timestamp

rfid_content_pack

Purpose: A content pack linked to RFID cards, holding a collection of audio or prompt content items (e.g., a nursery rhyme pack). Includes caching metadata for pre-generated audio.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
pack_codeString (100)NoUnique pack code
nameString (255)NoDisplay name
descriptionStringYesPack description
content_typeString (50)YesType: "prompt", "audio", etc. (default: "prompt")
content_mdStringYesMarkdown source content
total_itemsIntYesCount of content_item children
languageString (10)YesContent language (default: "en")
cached_audio_urlsStringYesSerialized list of pre-cached audio URLs
versionString (50)YesPack version string
statusString (50)YesPack lifecycle status
age_rangeString (50)YesTarget age range label
thumbnail_urlString (500)YesThumbnail image URL
content_hashString (255)YesHash for detecting content changes
activeBooleanYesWhether the pack is active
creatorBigIntYesCreating user ID
create_dateDateTimeYesRecord creation time
updaterBigIntYesLast updater user ID
update_dateDateTimeYesRecord update time

rfid_question_pack

Purpose: A named bundle of rfid_question IDs, allowing a single RFID card to trigger a rotating set of questions.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
pack_codeString (100)NoPack code identifier
nameString (255)NoDisplay name
descriptionStringYesPack description
question_idsJsonYesOrdered array of rfid_question IDs
languageString (10)YesLanguage code (default: "en")
categoryString (100)YesCategory label
versionIntYesRevision number
statusString (50)YesLifecycle status
activeBooleanYesWhether the pack is active
creatorBigIntYesCreating user ID
create_dateDateTimeYesRecord creation time
updaterBigIntYesLast updater user ID
update_dateDateTimeYesRecord update time

rfid_question

Purpose: An individual question triggered when an RFID card is scanned. Contains the prompt text sent to the LLM and optional pre-cached audio.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
codeString (100)NoUnique question code
titleString (255)NoShort title
prompt_textStringYesFull prompt text sent to the LLM
system_prompt_overrideStringYesOptional system prompt override for this question
allow_cachingBooleanYesWhether audio response may be cached (default: true)
cached_audio_urlString (500)YesURL to pre-generated audio response
languageString (10)YesLanguage code (default: "en")
categoryString (100)YesQuestion category
difficultyIntYesDifficulty level 1-5 (default: 1)
activeBooleanYesWhether the question is active
creatorBigIntYesCreating user ID
create_dateDateTimeYesRecord creation time
updaterBigIntYesLast updater user ID
update_dateDateTimeYesRecord update time

content_item

Purpose: An individual audio or text item belonging to an rfid_content_pack, ordered by item_number.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
content_pack_idBigIntYesFK to rfid_content_pack
item_numberIntNoOrdering position within the pack
titleString (255)YesItem title
descriptionStringYesItem description
audio_urlString (500)YesAudio file URL
audio_size_bytesBigIntYesAudio file size in bytes
audio_duration_msBigIntYesAudio duration in milliseconds
images_jsonJsonYesArray of image URLs/metadata
image_urlString (500)YesPrimary image URL
lyrics_textStringYesLyrics or subtitle text
content_textStringYesFull text content
activeBooleanYesWhether the item is active
creatorBigIntYesCreating user ID
create_dateDateTimeYesRecord creation time
updaterBigIntYesLast updater user ID
update_dateDateTimeYesRecord update time

kid_profile

Purpose: Child profile linked to a parent user, storing age, grade, interests, and language preferences used to personalise agent behaviour.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
user_idBigIntYesFK to sys_user (parent)
nameString (100)NoChild's full name
nicknameString (100)YesPreferred nickname
avatar_urlString (500)YesAvatar image URL
birth_dateDateTime (Date)YesDate of birth
genderString (20)YesGender
gradeString (50)YesSchool grade
schoolString (200)YesSchool name
interestsString[]NoArray of interest tags
languageString (10)YesPreferred language (default: "en")
timezoneString (50)YesTimezone string
preferencesJsonYesArbitrary preference JSON
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

sys_params

Purpose: Key-value store for system-wide configuration parameters accessible at runtime.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
param_codeString (100)NoUnique parameter key
param_valueStringYesParameter value
value_typeString (50)YesData type hint: "string", "int", "bool" (default: "string")
param_typeIntYes1 = system, 2 = custom
remarkString (500)YesDescription of the parameter
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

sys_dict_type

Purpose: Dictionary category (e.g., "gender", "status") that groups related sys_dict_data entries.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
dict_typeString (100)NoUnique type code
dict_nameString (255)NoDisplay name
remarkString (500)YesDescription
sortIntYesDisplay sort order
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

sys_dict_data

Purpose: Individual dictionary entries providing label-value pairs within a sys_dict_type category.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
dict_type_idBigIntYesFK to sys_dict_type
dict_typeString (100)YesDenormalised type code
dict_labelString (255)NoHuman-readable label
dict_valueString (255)NoStored value
remarkString (500)YesDescription
sortIntYesDisplay sort order
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

email_report_config

Purpose: Singleton-style configuration record for scheduled admin email reports, specifying recipients, schedule, and which sections to include.

FieldTypeNullableDescription
idUUIDNoPrimary key
enabledBooleanNoWhether scheduled reports are enabled (default: false)
schedule_hourIntNoHour of day to send reports (default: 8)
schedule_timezoneString (50)NoTimezone for the schedule (default: "Asia/Kolkata")
recipientsJsonNoArray of recipient email addresses
sectionsJsonNoObject flags for which report sections to include
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

email_report_history

Purpose: Audit log of each email report dispatch attempt, including delivery status and report payload.

FieldTypeNullableDescription
idUUIDNoPrimary key
report_dateDateTime (Date)NoDate the report covers
recipientsString[]NoArray of addresses the report was sent to
statusString (50)NoDelivery status (e.g., "sent", "failed")
error_messageStringYesError detail if status is "failed"
report_dataJsonYesFull report payload snapshot
sent_atDateTimeYesDispatch timestamp

openclaw_pair_tokens

Purpose: Short-lived pairing tokens that allow a device or parent app to authenticate with an OpenClaw instance. Tokens expire and are marked as paired once claimed.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
user_idBigIntNoFK to sys_user (token owner)
tokenString (20)NoUnique short pairing token
openclaw_urlStringYesOpenClaw server URL to pair with
pairedBooleanNoWhether the token has been claimed (default: false)
expires_atDateTimeNoToken expiry timestamp
created_atDateTimeYesRecord creation time
updated_atDateTimeYesRecord update time

memory_chunks

Purpose: Vector search index. Text chunks extracted from device memory files are stored here with pgvector embeddings, enabling semantic similarity search for memory retrieval during AI conversations.

FieldTypeNullableDescription
idBigInt (autoincrement)NoPrimary key
mac_idStringNoDevice MAC address (links to device_memories)
textStringNoRaw text chunk
file_pathStringYesSource file path the chunk was extracted from
start_lineIntYesStarting line number in source file (default: 0)
end_lineIntYesEnding line number in source file (default: 0)
embeddingUnsupported("vector")Yespgvector embedding for semantic search
categoryStringYesChunk category (default: "general")
created_atDateTimeYesRecord creation time
content_hashStringNoHash of text content for deduplication

Unique constraint: (mac_id, content_hash). The embedding column uses the pgvector extension (vector type) and is indexed with an HNSW or IVFFlat index (idx_memory_chunks_embedding) for approximate nearest-neighbour search.