Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ElthonJohan/comunitea/llms.txt

Use this file to discover all available pages before exploring further.

ComuniTEA’s data model is the backbone of every interaction in the app. At its center sits the Pictograma interface — a lightweight object that carries an emoji, a label, a category, and optional pointers to audio and image assets. Pictograms flow from the static board data in features/tablero/data/tablero.ts through the sentence-strip UI, the vocabulary module (VOCABULARY tree), the Zustand stores, and ultimately into Supabase’s sentence_log table when a child plays a constructed phrase. Understanding this model makes it possible to reason about any screen in the app.

Pictograma Interface

The Pictograma is the atomic unit of communication in ComuniTEA. Every item on the AAC board — foods, emotions, actions, people, requests — is represented as a Pictograma.
// features/tablero/data/tablero.ts

export interface Pictograma {
  id: string;
  emoji: string;
  label: string;
  categoria: string;
  esFavorito: boolean;
  /**
   * Clave en `getAudioAssets(perfil)` de `constants/AudioAssets.ts`.
   * Si no se define, se usa `id` al resolver el clip (p. ej. `manzana` → archivo manzana.mp3).
   */
  audioAssetKey?: string;
  /** Foto del niño u otro picto con imagen remota (personas / tablero). */
  imageUri?: string;
}
id
string
required
Unique identifier for the pictogram within the app. Used as the primary key for audio lookup (getAudioAssets) unless audioAssetKey overrides it, and as the value stored in sentence_log.pictogram_ids when a phrase is saved to Supabase.
emoji
string
required
Unicode emoji rendered as the pictogram’s visual representation on the board. Used as a fallback when no imageUri is present.
label
string
required
Human-readable display text shown beneath the pictogram on the board, and spoken by the TTS engine when the pictogram is tapped in isolation.
categoria
string
required
The category key this pictogram belongs to (e.g., 'frutas', 'emociones', 'personas'). Used to group pictograms in the board grid and to filter custom pictograms from Supabase via category_key.
esFavorito
boolean
required
Marks a pictogram as a favourite so it can be surfaced in a quick-access row. Defaults to false in the pic() helper.
audioAssetKey
string
Optional override for the key used to look up the pre-recorded MP3 file in getAudioAssets(voice). When omitted, the pictogram’s id is used as the key. This allows an id and its audio file name to differ — for example id: 'auto' maps to audio key 'carro', and id: 'fresa' maps to 'fresas'.
imageUri
string
Optional URI pointing to a remote or local image — used for custom photo pictograms (the “Mi mundo en fotos” feature) and for people pictograms that display a child’s actual photo. When set, this image is rendered in place of the emoji.

pic() Factory Helper

To avoid constructing Pictograma objects manually, the pic() helper takes positional arguments and omits optional keys when they are undefined or empty strings:
export function pic(
  id: string,
  emoji: string,
  label: string,
  categoria: string,
  esFavorito = false,
  audioAssetKey?: string,
  imageUri?: string,
): Pictograma {
  return {
    id,
    emoji,
    label,
    categoria,
    esFavorito,
    ...(audioAssetKey !== undefined ? { audioAssetKey } : {}),
    ...(imageUri !== undefined && imageUri.length > 0 ? { imageUri } : {}),
  };
}

getPictogramAudioKey()

When the audio player needs to resolve which MP3 to play for a given pictogram, it calls this function:
/** Clave para buscar el mp3 en `getAudioAssets(voice)` al reproducir un pictograma del tablero. */
export function getPictogramAudioKey(p: Pictograma): string {
  return p.audioAssetKey ?? p.id;
}
The result is passed into getAudioAssets(voiceProfile) from constants/AudioAssets.ts to retrieve the correct bundled audio asset for the active voice profile.

Subcategoria Interface

A Subcategoria groups related pictograms and maps them to a parent category. The full board is made up of ALL_SUBCATS, an array of Subcategoria objects covering seven default categories.
// features/tablero/data/tablero.ts

export interface Subcategoria {
  id: string;
  nombre: string;
  emoji: string;
  categoriaId: string;
  pictogramas: Pictograma[];
}
id
string
required
Unique identifier for the subcategory (e.g., 'frutas', 'emociones').
nombre
string
required
Display name shown on the subcategory selector tile (e.g., 'Frutas', 'Emociones').
emoji
string
required
Emoji used as the subcategory’s icon on the grid (e.g., '🍎', '😊').
categoriaId
string
required
Links the subcategory to its parent category. Currently mirrors id for the default board but is distinct to support future multi-level hierarchies.
pictogramas
Pictograma[]
required
The ordered list of pictograms displayed when this subcategory is selected on the board.

Default Subcategory Catalog (ALL_SUBCATS)

The static board includes seven default subcategories:
idnombreEmojiPictogram count
frutasFrutas🍎5
comidaComida🍽️5
juguetesJuguetes🧸4
verdurasVerduras🥕3
golosinasGolosinas🍬3
actividadesActividades🎮4
emocionesEmociones😊4

Fixed Communication Rows

Two arrays are pinned to the board at all times and cannot be hidden. They cover the most frequent communicative functions for a child using AAC.

PERSONAS_ROW

Displays the child’s key people. Designed to be extended with custom imageUri entries from child_profiles.important_people.
export const PERSONAS_ROW: Pictograma[] = [
  pic('mama',  '👩',    'Mamá',  'personas'),
  pic('papa',  '👨',    'Papá',  'personas'),
  pic('profe', '👩‍🏫', 'Profe', 'personas'),
  pic('nico',  '👦',    'Nico',  'personas'),
];

PETICIONES_ROW

Provides the five core communicative functions — requesting, refusing, liking, expressing pain, and asking for help:
export const PETICIONES_ROW: Pictograma[] = [
  pic('quiero',    '🤲', 'Quiero',    'peticiones'),
  pic('no-quiero', '🚫', 'No quiero', 'peticiones'),
  pic('me-gusta',  '❤️', 'Me gusta',  'peticiones'),
  pic('me-duele',  '😣', 'Me duele',  'peticiones'),
  pic('ayuda',     '🙋', 'Ayuda',     'peticiones'),
];

Voice and Vocabulary Types

VoiceProfile

Defined in constants/AudioAssets.ts. Controls which set of bundled MP3 recordings is loaded when the app plays pictogram audio.
export type VoiceProfile = 'femenina' | 'masculina';
The active profile is persisted via useSettingsStore (see Stores). getAudioAssets(profile) returns a Record<string, any> mapping pictogram IDs to their corresponding audio assets for the selected voice.

VocabLevel

The vocabulary level gates which items appear in the vocabulary module. Each level is a superset in complexity, not just in size.
// Enforced by the `level` column constraint on public.profiles in Supabase
type VocabLevel = 'BASICO' | 'INTERMEDIO' | 'AVANZADO';
LevelDescription
BASICOCore words (YO, QUIERO, NO…), top-priority categories (emociones, comida, baño, jugar, dormir, ropa). Designed for children with minimal or no verbal language.
INTERMEDIOAdds números, colores, personas, lugares, higiene, mi día — extends vocabulary with two-word combinations.
AVANZADOAdds full conversational frames (yo quiero, me gusta, ¿podemos hablar?), escola agenda, verbos, and emergency phrases.

Vocabulary Module Types

The vocabulary feature uses a separate, richer type tree to support multi-level category navigation.
// features/vocabulario/data/Vocabulary.ts

export interface VocabularyItem {
  id: string;
  label: string;
  emoji: string;
  backgroundColor?: string;
  speechText?: string;
  items?: VocabularyItem[];
}
id
string
required
Stable identifier used for co-occurrence tracking and deep linking. Must match AUDIO_ASSETS keys when the item is a leaf node to be spoken.
label
string
required
Display text shown on the vocabulary chip (always uppercase in the static data).
emoji
string
required
Emoji rendered on the chip alongside the label.
backgroundColor
string
Optional hex color used to tint the chip background — applied to top-level categories to create a colour-coded grid.
speechText
string
Override for the text passed to the TTS engine. When absent, label is used. Useful for items like 'ME LLAMO...' where the spoken form differs from the visual label.
items
VocabularyItem[]
Child items. When present, tapping the item opens a sub-panel rather than adding the item to the sentence strip. Navigation supports a maximum depth of 2 levels.

Vocabulary Utility Functions

// Get all items for a given level (falls back to BASICO if unknown)
export const getVocabularyByLevel = (level: string): VocabularyItem[] =>
  VOCABULARY[level] || VOCABULARY.BASICO;

// Recursively find any item by id across the full tree
export const findItemById = (
  items: VocabularyItem[],
  targetId: string,
): VocabularyItem | undefined => { /* ... */ };

// Flatten a tree to leaf nodes only (no sub-categories)
export const flattenItems = (items: VocabularyItem[]): VocabularyItem[] =>
  { /* ... */ };
findItemById is used by the co-occurrence suggestion system (Phase 2) to look up items by ID anywhere in the vocabulary tree. flattenItems is used when presenting a subcategory’s contents as a flat grid, collapsing any intermediate sub-category nodes.

Route Types

All Expo Router routes are centralised in types/routes.ts to prevent typos and enable IDE auto-complete.
// types/routes.ts

export const ROUTES = {
  index:               '/',
  login:               '/login',
  voiceSelection:      '/voice-selection',
  onboarding:          '/onboarding',
  tutorial:            '/tutorial',
  tutorialBasic:       '/tutorial/basic',
  settings:            '/settings',
  categorias:          '/(tabs)/categorias',
  tablero:             '/(tabs)/tablero',
  ejerciciosTab:       '/(tabs)/ejercicios',
  perfil:              '/(tabs)/perfil',
  ejerciciosGrupo2:    '/ejercicios/grupo2',
  ejerciciosGrupo3:    '/ejercicios/grupo3',
  sentences:           '/sentences',
  report:              '/report',
  vocabularyManager:   '/vocabulary-manager',
  activityEditor:      '/activity-editor',
  activityRun:         '/activity-run',
  game:                '/game',
  teamManager:         '/team-manager',
} as const;

export type RouteKey = keyof typeof ROUTES;
export type AppRoute = (typeof ROUTES)[RouteKey];

Dynamic Route Helpers

For routes with URL segments, typed helper functions build Href values:
// Ejercicios Grupo 2
export function hrefG2Nivel(n: number): Href
export function hrefG2Ejercicio(nivel: number, ej: number): Href

// Ejercicios Grupo 3
export function hrefG3Nivel(n: number): Href
export function hrefG3Ejercicio(nivel: number, ej: number): Href

// Actividades guiadas
export function hrefActivityRun(id: string): Href
  // → { pathname: '/activity-run', params: { id } }

// Tablero tab root
export function hrefCategorias(): Href
  // → '/(tabs)/categorias'
Always import route constants from types/routes.ts rather than writing string literals. This prevents silent breakage when a route is renamed and keeps all navigation paths auditable in one place.

AsyncStorage Keys (STORAGE_KEYS)

All persistent client-side state uses the keys defined in lib/storage/keys.ts. These are the canonical strings passed to AsyncStorage.getItem / AsyncStorage.setItem across the app and its Zustand persist middleware adapters.
// lib/storage/keys.ts

export const STORAGE_KEYS = {
  VOICE_PREFERENCE:         'user_voice_preference',
  PARENTAL_PIN:             'parental_pin',
  ELEVEN_CREDITS:           'eleven_credits',
  SHOW_KEYBOARD:            'show_keyboard',
  IMAGE_OVERRIDES:          'image_overrides',
  ONBOARDING_COMPLETED:     'onboarding_completed',
  PICTOGRAM_CACHE_META:     'pictogram_cache_meta',
  OFFLINE_QUEUE:            'offline_event_queue',
  DISABLED_PICTOGRAMS:      'disabled_pictograms',
  ACTIVE_ENVIRONMENT:       'active_environment',
  CONSENT_ACCEPTED:         'consent_accepted_at',
  PREFERRED_ACTIVITIES:     'preferred_activities',
  IMPORTANT_PEOPLE:         'important_people',
  TUTORIAL_COMPLETED:       'comunitea_tutorial_completed',
  TUTORIAL_BASIC_COMPLETED: 'comunitea_tutorial_basic_completed',
  EJERCICIOS_G3:            'comunitea_ejercicios_g3',
  EJERCICIOS_G3_COMPLETADOS:'ejercicios_g3_completados',
  EJERCICIOS_G2:            'comunitea_ejercicios_g2',
} as const;

export type StorageKey = (typeof STORAGE_KEYS)[keyof typeof STORAGE_KEYS];
KeyRaw stringPurpose
VOICE_PREFERENCEuser_voice_preferenceActive VoiceProfile — read by settingsStore
PARENTAL_PINparental_pin4-digit PIN protecting parental settings
ELEVEN_CREDITSeleven_creditsRemaining ElevenLabs TTS credits
SHOW_KEYBOARDshow_keyboardWhether the free-text keyboard is shown
IMAGE_OVERRIDESimage_overridesMap of pictogram id → custom local image URI
ONBOARDING_COMPLETEDonboarding_completedGuards the onboarding flow
PICTOGRAM_CACHE_METApictogram_cache_metaMetadata for the offline pictogram image cache
OFFLINE_QUEUEoffline_event_queueEvents queued for Supabase upload when offline
DISABLED_PICTOGRAMSdisabled_pictogramsPictogram IDs hidden by the parent
ACTIVE_ENVIRONMENTactive_environmentCurrent environment context (casa / escuela…)
CONSENT_ACCEPTEDconsent_accepted_atISO timestamp of privacy consent acceptance
PREFERRED_ACTIVITIESpreferred_activitiesChild’s preferred activity IDs
IMPORTANT_PEOPLEimportant_peopleJSON array of people pictogram configs
TUTORIAL_COMPLETEDcomunitea_tutorial_completedMain tutorial completion flag
TUTORIAL_BASIC_COMPLETEDcomunitea_tutorial_basic_completedBasic tutorial completion flag
EJERCICIOS_G3comunitea_ejercicios_g3Serialised EjercicioG3State
EJERCICIOS_G3_COMPLETADOSejercicios_g3_completados'true' when the full G3 path is complete
EJERCICIOS_G2comunitea_ejercicios_g2Serialised EjerciciosG2State
The Zustand persist adapters for g2ProgressStore and g3ProgressStore write a plain EjerciciosG2State / EjercicioG3State JSON object directly to the key — not the Zustand { state, version } envelope. The adapters handle the translation on read. Do not write to these keys manually without matching that structure.

Build docs developers (and LLMs) love