Struktury Danych — Użytkownicy
Dziecko (Child)
json
{
"id": "child_001",
"display_name": "Kosmonauta_7842",
"birth_year": 2019,
"birth_month": 3,
"birth_day": 15,
"language": "pl",
"age_groups": ["4-8"],
"avatar": {
"body": "avatar_body_01",
"hair": "hair_ponytail",
"hair_color": "#8B4513",
"skin_color": "#FFDBB4",
"eye_color": "#4A90D9",
"outfit": {
"top": "shirt_princess",
"bottom": "skirt_pink",
"shoes": "sneakers_white"
},
"accessories": ["glasses_round", "backpack_star"]
},
"level": 12,
"xp": 1450,
"xp_to_next_level": 2000,
"badges": ["badge_first_quiz", "badge_traveler", "badge_streak_7"],
"completed_tasks": ["task_001", "task_002", "task_031"],
"parent_ids": ["parent_001"],
"school_ids": ["school_001"],
"joined_planets": ["world_open_english"],
"assigned_planets": ["world_custom_001"],
"stats": {
"total_tasks_completed": 47,
"total_xp_earned": 1450,
"countries_visited": ["world_poland", "world_spain"],
"current_streak_days": 5,
"longest_streak_days": 12,
"time_spent_minutes": 840
},
"settings": {
"daily_limit_minutes": 60,
"break_interval_minutes": 20,
"rankings_enabled": true
},
"created_at": "2025-09-01T10:00:00Z"
}| Pole | Typ | Opis |
|---|---|---|
id | string | Unikalny identyfikator |
display_name | string | display_name jest losowo generowane przy rejestracji (np. 'Kosmonauta_7842'), dziecko może zmienić w profilu |
birth_year | number | Rok urodzenia (podawany przy rejestracji) → grupa wiekowa |
birth_month | number? | Miesiąc urodzenia (opcjonalny — uzupełniany w profilu) |
birth_day | number? | Dzień urodzenia (opcjonalny — uzupełniany w profilu) |
language | string | Język wybrany przy rejestracji (np. "pl") → domyślny kraj |
age_groups | string[] | Grupy wiekowe — może być wiele jednocześnie (np. ["4-8", "8-13"]) |
avatar | object | Konfiguracja awatara (patrz Awatar) |
level | number | Aktualny poziom |
xp | number | Aktualne XP |
xp_to_next_level | number | XP potrzebne do następnego poziomu |
badges | string[] | Lista ID zdobytych odznak |
completed_tasks | string[] | Lista ID ukończonych zadań |
parent_ids | string[] | Lista ID powiązanych rodziców |
school_ids | string[] | Lista ID przypisanych szkół/organizacji |
joined_planets | string[] | Planety otwarte, do których dziecko dołączyło |
assigned_planets | string[] | Planety zamknięte przypisane przez rodzica/szkołę |
stats | object | Statystyki (patrz Statystyki) |
settings | object | Ustawienia zarządzane przez rodzica |
created_at | string | Data rejestracji (ISO 8601) |
Rodzic (Parent)
json
{
"id": "parent_001",
"email": "mama@example.com",
"children_ids": ["child_001", "child_002"],
"has_app": true,
"auth_method": "app",
"created_worlds": ["world_custom_parent_001"],
"created_at": "2025-08-20T14:00:00Z"
}| Pole | Typ | Opis |
|---|---|---|
id | string | Unikalny identyfikator |
email | string | Email (logowanie przez kod jednorazowy) |
children_ids | string[] | Lista ID powiązanych dzieci |
has_app | boolean | Czy rodzic ma konto w app (false = tylko email) |
auth_method | string | "app" (kod z app) lub "email" (kod emailowy) |
created_worlds | string[] | Lista ID planet stworzonych w manager-content |
created_at | string | Data rejestracji (ISO 8601) |
Rodzic bez app (tylko email)
json
{
"id": "parent_002",
"email": "tata@example.com",
"children_ids": ["child_003"],
"has_app": false,
"auth_method": "email",
"created_worlds": [],
"created_at": "2025-10-15T09:00:00Z"
}Dorosły (Adult)
json
{
"id": "adult_001",
"email": "jan@example.com",
"display_name": "Explorer_1337",
"language": "pl",
"age_groups": ["14+"],
"avatar": {
"body": "avatar_body_03",
"hair": "hair_short",
"hair_color": "#2C1810",
"skin_color": "#D4A574",
"eye_color": "#654321",
"outfit": {
"top": "hoodie_blue",
"bottom": "jeans_dark",
"shoes": "boots_brown"
},
"accessories": []
},
"level": 5,
"xp": 680,
"xp_to_next_level": 1000,
"badges": ["badge_first_quiz", "badge_driving_signs"],
"completed_tasks": ["task_driving_001", "task_driving_002"],
"joined_planets": ["world_open_python"],
"assigned_planets": ["world_uni_cs_101"],
"stats": {
"total_tasks_completed": 15,
"total_xp_earned": 680,
"countries_visited": ["world_poland"],
"current_streak_days": 2,
"longest_streak_days": 8,
"time_spent_minutes": 320
},
"created_at": "2026-01-10T18:00:00Z"
}| Pole | Typ | Opis |
|---|---|---|
id | string | Unikalny identyfikator |
email | string | Email (logowanie przez kod jednorazowy) |
display_name | string | display_name jest losowo generowane przy rejestracji (np. 'Kosmonauta_7842'), dziecko może zmienić w profilu |
language | string | Język |
age_groups | string[] | Grupy wiekowe (np. ["14+"]) |
avatar | object | Konfiguracja awatara |
level | number | Aktualny poziom |
xp | number | Aktualne XP |
xp_to_next_level | number | XP do następnego poziomu |
badges | string[] | Lista ID zdobytych odznak |
completed_tasks | string[] | Lista ID ukończonych zadań |
joined_planets | string[] | Planety otwarte |
assigned_planets | string[] | Planety zamknięte |
stats | object | Statystyki |
created_at | string | Data rejestracji (ISO 8601) |
Szkoła / Organizacja (School)
json
{
"id": "school_001",
"name": "Szkoła Podstawowa nr 7 w Krakowie",
"type": "school",
"email": "sp7@krakow.pl",
"admin_ids": ["parent_010", "parent_011"],
"teacher_ids": ["parent_012", "parent_013", "parent_014"],
"student_ids": ["child_001", "child_005", "child_006", "child_007"],
"created_worlds": ["world_custom_001", "world_custom_002"],
"created_at": "2025-09-01T08:00:00Z"
}| Pole | Typ | Opis |
|---|---|---|
id | string | Unikalny identyfikator |
name | string | Nazwa szkoły/organizacji |
type | string | "school", "organization", "club" |
email | string | Email kontaktowy |
admin_ids | string[] | ID administratorów (rodzice/nauczyciele z rolą admin) |
teacher_ids | string[] | ID nauczycieli (mogą tworzyć content) |
student_ids | string[] | ID przypisanych uczniów/dzieci |
created_worlds | string[] | ID stworzonych planet |
created_at | string | Data utworzenia (ISO 8601) |
Awatar
Struktura awatara dziecka/dorosłego. Wszystkie elementy personalizacji w jednym obiekcie.
json
{
"body": "avatar_body_01",
"hair": "hair_ponytail",
"hair_color": "#8B4513",
"skin_color": "#FFDBB4",
"eye_color": "#4A90D9",
"outfit": {
"top": "shirt_princess",
"bottom": "skirt_pink",
"shoes": "sneakers_white"
},
"accessories": ["glasses_round", "backpack_star"]
}| Pole | Typ | Opis |
|---|---|---|
body | string | ID typu postaci |
hair | string | ID fryzury |
hair_color | string | Kolor włosów (hex) |
skin_color | string | Kolor skóry (hex) |
eye_color | string | Kolor oczu (hex) |
outfit | object | Ubrania: top, bottom, shoes |
accessories | string[] | Lista ID akcesoriów (okulary, plecak, zwierzątko...) |
Element personalizacji (do listy dostępnych)
json
{
"id": "shirt_princess",
"category": "top",
"name": "Koszulka z księżniczką",
"thumbnail": "avatar/tops/princess.png",
"unlock_type": "default",
"unlock_value": null
}json
{
"id": "hat_pirate",
"category": "accessory",
"name": "Czapka pirata",
"thumbnail": "avatar/accessories/pirate_hat.png",
"unlock_type": "badge",
"unlock_value": "badge_traveler"
}json
{
"id": "shoes_gold",
"category": "shoes",
"name": "Złote buty",
"thumbnail": "avatar/shoes/gold.png",
"unlock_type": "level",
"unlock_value": 20
}| Pole | Typ | Opis |
|---|---|---|
id | string | Unikalny identyfikator elementu |
category | string | "body", "hair", "top", "bottom", "shoes", "accessory" |
name | string | Nazwa wyświetlana |
thumbnail | string | Obrazek podglądu |
unlock_type | string | "default" (od razu), "level", "badge", "task" |
unlock_value | any? | Wartość odblokowania: numer poziomu, ID odznaki lub ID zadania |
Odznaka (Badge)
json
{
"id": "badge_first_quiz",
"name": "Pierwszy quiz!",
"description": "Ukończ swój pierwszy quiz",
"icon": "badges/first_quiz.png",
"category": "milestone",
"condition": {
"type": "task_count",
"task_type": "quiz",
"count": 1
}
}json
{
"id": "badge_traveler",
"name": "Podróżnik",
"description": "Odwiedź 5 różnych krajów",
"icon": "badges/traveler.png",
"category": "exploration",
"condition": {
"type": "countries_visited",
"count": 5
}
}json
{
"id": "badge_streak_7",
"name": "Seria 7 dni",
"description": "Ucz się przez 7 dni z rzędu",
"icon": "badges/streak_7.png",
"category": "streak",
"condition": {
"type": "streak_days",
"count": 7
}
}json
{
"id": "badge_cinema_5",
"name": "Kinoman",
"description": "Obejrzyj 5 filmów edukacyjnych",
"icon": "badges/cinema_5.png",
"category": "content",
"condition": {
"type": "task_count",
"task_type": "video",
"count": 5
}
}json
{
"id": "badge_driving_signs",
"name": "Znaki drogowe",
"description": "Ukończ quiz ze znaków drogowych na 80%+",
"icon": "badges/driving_signs.png",
"category": "achievement",
"condition": {
"type": "specific_task",
"task_id": "task_driving_001",
"min_score": 0.8
}
}json
{
"id": "badge_puzzle_master",
"name": "Mistrz puzzli",
"description": "Ułóż 10 puzzli",
"icon": "badges/puzzle_master.png",
"category": "content",
"condition": {
"type": "game_count",
"game_type": "puzzle",
"count": 10
}
}| Pole | Typ | Opis |
|---|---|---|
id | string | Unikalny identyfikator |
name | string | Nazwa odznaki |
description | string | Opis jak ją zdobyć |
icon | string | Ścieżka do ikony |
category | string | "milestone", "exploration", "streak", "content", "achievement" |
condition | object | Warunek odblokowania (patrz niżej) |
Warunki odznak (condition)
| Typ warunku | Pola | Opis |
|---|---|---|
task_count | task_type, count | Ukończ N zadań danego typu |
game_count | game_type, count | Ukończ N gier danego typu |
countries_visited | count | Odwiedź N krajów |
streak_days | count | Utrzymaj serię N dni |
specific_task | task_id, min_score? | Ukończ konkretne zadanie (opcjonalnie z min. wynikiem) |
xp_total | amount | Zdobądź łącznie N XP |
level_reached | level | Osiągnij poziom N |
Poziom (Level)
json
{
"level": 1,
"xp_required": 0,
"xp_to_next": 100,
"title": "Początkujący",
"rewards": []
}json
{
"level": 5,
"xp_required": 500,
"xp_to_next": 1000,
"title": "Odkrywca",
"rewards": [
{ "type": "avatar_item", "item_id": "hat_explorer" }
]
}json
{
"level": 10,
"xp_required": 1200,
"xp_to_next": 2000,
"title": "Podróżnik",
"rewards": [
{ "type": "avatar_item", "item_id": "backpack_gold" },
{ "type": "badge", "badge_id": "badge_level_10" }
]
}json
{
"level": 20,
"xp_required": 5000,
"xp_to_next": 8000,
"title": "Ekspert",
"rewards": [
{ "type": "avatar_item", "item_id": "shoes_gold" },
{ "type": "avatar_item", "item_id": "cape_star" }
]
}| Pole | Typ | Opis |
|---|---|---|
level | number | Numer poziomu |
xp_required | number | Wymagane XP aby osiągnąć ten poziom |
xp_to_next | number | XP potrzebne do następnego poziomu |
title | string | Nazwa poziomu (wyświetlana w profilu) |
rewards | array | Nagrody za osiągnięcie poziomu |
Nagrody za poziom
| Typ nagrody | Pole | Opis |
|---|---|---|
avatar_item | item_id | Odblokowanie elementu personalizacji |
badge | badge_id | Odblokowanie odznaki |
Todo (zadanie todo)
Zadanie realne od rodzica
json
{
"id": "todo_001",
"child_id": "child_001",
"added_by": "parent_001",
"source": "parent",
"title": "Posprzątaj pokój",
"description": "Posprzątaj pokój przed obiadem",
"type": "real",
"deadline": "2026-03-08T18:00:00Z",
"status": "pending",
"xp_reward": 15,
"linked_task_id": null,
"requires_parent_confirmation": true,
"completed_at": null,
"confirmed_at": null,
"created_at": "2026-03-08T08:00:00Z"
}Zadanie in-game od rodzica
json
{
"id": "todo_002",
"child_id": "child_001",
"added_by": "parent_001",
"source": "parent",
"title": "Zrób quiz z tabliczki mnożenia",
"description": null,
"type": "in_game",
"deadline": "2026-03-10T20:00:00Z",
"status": "pending",
"xp_reward": 25,
"linked_task_id": "task_001",
"requires_parent_confirmation": false,
"completed_at": null,
"confirmed_at": null,
"created_at": "2026-03-08T08:00:00Z"
}Zadanie realne dodane przez dziecko
json
{
"id": "todo_003",
"child_id": "child_001",
"added_by": "child_001",
"source": "child",
"title": "Nauczyć się na sprawdzian z przyrody",
"description": "Rozdział 5 — Rośliny",
"type": "real",
"deadline": "2026-03-12T08:00:00Z",
"status": "pending",
"xp_reward": 0,
"linked_task_id": null,
"requires_parent_confirmation": false,
"completed_at": null,
"confirmed_at": null,
"created_at": "2026-03-08T15:00:00Z"
}Zadanie in-game dodane przez dziecko
json
{
"id": "todo_004",
"child_id": "child_001",
"added_by": "child_001",
"source": "child",
"title": "Zdobądź 500 XP w tym tygodniu",
"description": null,
"type": "in_game",
"deadline": "2026-03-14T23:59:00Z",
"status": "pending",
"xp_reward": 0,
"linked_task_id": null,
"requires_parent_confirmation": false,
"completed_at": null,
"confirmed_at": null,
"created_at": "2026-03-08T15:30:00Z"
}Zadanie ukończone
json
{
"id": "todo_005",
"child_id": "child_001",
"added_by": "parent_001",
"source": "parent",
"title": "Obejrzyj film o dinozaurach",
"description": null,
"type": "in_game",
"deadline": "2026-03-08T20:00:00Z",
"status": "completed",
"xp_reward": 10,
"linked_task_id": "task_002",
"requires_parent_confirmation": false,
"completed_at": "2026-03-07T16:30:00Z",
"confirmed_at": "2026-03-07T16:30:00Z",
"created_at": "2026-03-06T08:00:00Z"
}Zadanie realne — oczekujące na zatwierdzenie rodzica
json
{
"id": "todo_006",
"child_id": "child_001",
"added_by": "parent_001",
"source": "parent",
"title": "Wyprowadź psa",
"description": "Spacer minimum 15 minut",
"type": "real",
"deadline": "2026-03-08T19:00:00Z",
"status": "pending_confirmation",
"xp_reward": 20,
"linked_task_id": null,
"requires_parent_confirmation": true,
"completed_at": "2026-03-08T17:15:00Z",
"confirmed_at": null,
"created_at": "2026-03-08T08:00:00Z"
}| Pole | Typ | Opis |
|---|---|---|
id | string | Unikalny identyfikator |
child_id | string | ID dziecka |
added_by | string | ID osoby dodającej (rodzic lub dziecko) |
source | string | "child" (dodane przez dziecko — self-confirm, auto-complete) lub "parent" (dodane przez rodzica — wymaga zatwierdzenia rodzica) |
title | string | Tytuł zadania |
description | string? | Opis (opcjonalny) |
type | string | "real" lub "in_game" |
deadline | string? | Deadline (ISO 8601, opcjonalny) |
status | string | "pending", "pending_confirmation", "completed" |
xp_reward | number | XP za ukończenie (0 = brak nagrody) |
linked_task_id | string? | ID zadania in-game (tylko type: "in_game") |
requires_parent_confirmation | boolean | Czy wymaga zatwierdzenia rodzica |
completed_at | string? | Data ukończenia przez dziecko |
confirmed_at | string? | Data zatwierdzenia (przez rodzica lub auto) |
created_at | string | Data utworzenia |
Statusy todo
| Status | Opis |
|---|---|
pending | Oczekujące — nie rozpoczęte |
pending_confirmation | Dziecko oznaczyło jako zrobione — czeka na zatwierdzenie rodzica (tylko dla todo dodanych przez rodzica, source: "parent") |
completed | Ukończone — automatycznie dla todo dziecka (source: "child"), po zatwierdzeniu rodzica dla todo rodzica (source: "parent") |
Statystyki dziecka
json
{
"total_tasks_completed": 47,
"total_xp_earned": 1450,
"countries_visited": ["world_poland", "world_spain"],
"current_streak_days": 5,
"longest_streak_days": 12,
"time_spent_minutes": 840,
"tasks_by_type": {
"quiz": 25,
"video": 10,
"audio": 5,
"game": 5,
"creative": 2
},
"tasks_by_age_group": {
"4-8": 40,
"8-13": 7
}
}| Pole | Typ | Opis |
|---|---|---|
total_tasks_completed | number | Łączna liczba ukończonych zadań |
total_xp_earned | number | Łącznie zdobyte XP |
countries_visited | string[] | Lista ID odwiedzonych krajów |
current_streak_days | number | Aktualna seria dni |
longest_streak_days | number | Najdłuższa seria |
time_spent_minutes | number | Łączny czas w app (minuty) |
tasks_by_type | object | Ukończone zadania per typ |
tasks_by_age_group | object | Ukończone zadania per grupa wiekowa |