> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lala.ist/llms.txt
> Use this file to discover all available pages before exploring further.

# Journey

> Deneme results, topic performance, study-hours stats, and the streak.

The journey is the student's progress record. It holds deneme (mock exam) results, and it derives
everything else: rolling averages, trends, topic performance, study-hours stats, and the streak.

Three sources write into it. The client posts denemeler through this API. Lala records denemeler
that the student reports in chat. The planner supplies study time — a completed block is study
time, and the journey never stores a second copy.

## What a deneme is

One deneme is one scored paper. A TYT paper and an AYT paper from the same exam day are two
denemeler. Their nets are never summed.

A deneme carries per-subject results. Each result holds `dogru`, `yanlis`, `bos`, and a `net`.
The server computes the net from the counts:

* TYT and AYT: `net = dogru − yanlis / 4`
* LGS: `net = dogru − yanlis / 3`

A student often reports only the net ("matematik 16 net"). That is a first-class write: send
`net` and leave the counts out. When the counts are present, the server computes the net and
ignores a claimed one.

A deneme can also carry per-topic rows ("Paragraf: 8 doğru, 3 yanlış, 1 boş"). Topic rows are
optional. They feed the topic performance tables.

## Subjects

Subject keys are canonical and exam-prefixed: `tyt_matematik`, `ayt_tarih1`, `lgs_fen`. On write,
the API also accepts display names, aliases, and short codes — `Matematik`, `mat`, and `MAT` all
land on the same key. An unknown subject is a 400, never a silent new subject.

Each result in a response carries the key, a Turkish `label` ("Matematik"), and a `short` code
("MAT") for dense views.

On AYT, `tarih` and `coğrafya` resolve to the -1 papers (`ayt_tarih1`, `ayt_cografya1`). Name the
-2 papers as `tarih-2` or `coğrafya-2`.

## Record a deneme

`POST /api/denemeler` records one paper.

```bash theme={null}
curl -X POST "$BASE_URL/api/denemeler" \
  -H "Authorization: Bearer $LALA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "examType": "TYT",
    "name": "Bilgi Sarmal Türkiye Geneli",
    "takenDate": "2026-08-11",
    "subjects": [
      { "subject": "türkçe", "dogru": 26, "yanlis": 8, "bos": 6 },
      { "subject": "mat", "dogru": 18, "yanlis": 8, "bos": 14 },
      { "subject": "fizik", "net": 3 }
    ],
    "topics": [
      { "subject": "mat", "topic": "Türev", "dogru": 2, "yanlis": 6, "bos": 4 }
    ]
  }'
```

The response is the full deneme. Subjects come back in booklet order, with the computed nets and
the `totalNet` rollup.

`GET /api/denemeler` lists denemeler, newest first, with an opaque cursor. Pass `nextCursor` back
as `cursor` for the next older page. `examType` narrows to one paper type.

## Correct a deneme

`PATCH /api/denemeler/:id` is a partial update. Header fields overwrite. `subjects` and `topics`
upsert by their natural key:

```bash theme={null}
curl -X PATCH "$BASE_URL/api/denemeler/$DENEME_ID" \
  -H "Authorization: Bearer $LALA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "subjects": [ { "subject": "mat", "dogru": 19 } ] }'
```

Fields left off a subject patch keep their stored values. The patch above corrects `dogru` and
keeps the known `yanlis`, and the server recomputes the net and `totalNet`.

Set `remove: true` on a subject or topic row to delete it. `examType` cannot change — it would
re-key every subject. Delete the deneme and record it again.

`DELETE /api/denemeler/:id` removes the paper and every row under it. The averages recompute on
the next read.

## The overview

`GET /api/journey` returns the journey tab in one call:

```json theme={null}
{
  "daysTogether": 44,
  "streak": { "current": 12, "longest": 21 },
  "exams": [
    {
      "examType": "TYT",
      "avgNet": 68,
      "trend": "up",
      "count": 9,
      "subjects": [
        { "subject": "tyt_turkce", "label": "Türkçe", "short": "TÜR", "avgNet": 24, "trend": "up", "count": 9 }
      ]
    }
  ],
  "recentDenemeler": [],
  "study": { "days": 30, "totalMin": 7020, "activeDays": 26, "dailyAvgMin": 270 },
  "strongTopics": [],
  "weakTopics": []
}
```

`avgNet` is the average of the last three denemeler of that exam type. `trend` compares that
window against the same window shifted one deneme back: `up`, `down`, or `flat`. The same pair
exists per subject.

`daysTogether` counts from sign-up, first day inclusive. The streak counts days with meaningful
activity: a chat message, a completed study block, a recorded deneme, or a saved check-in (see
[Check-ins](/guides/check-ins)). `current` reads 0 once a day has been missed; `longest` is the
record.

## One subject in depth

`GET /api/journey/subjects/:subject` serves the per-subject screen. The path parameter is the
canonical key:

```bash theme={null}
curl "$BASE_URL/api/journey/subjects/tyt_turkce?window=10" \
  -H "Authorization: Bearer $LALA_TOKEN"
```

The response holds the rolling average and trend, the subject's net in each deneme of the window
(`series`, newest first), all-time completed study minutes on the subject, and the topic table.

Each topic row aggregates the window: `total` questions, `correct`, `accuracy` (doğru over all
questions, 0–1), and `consistency`. Consistency is `high` when the per-deneme accuracy barely
moves, `low` when it swings, and `null` under three denemeler of data. `strongTopics` and
`weakTopics` are pre-filtered: strong is accuracy at or over 0.85, weak is under 0.6, and both
need at least three questions of sample.

## Study time

`GET /api/journey/study?from=2026-05-16&to=2026-08-13` sums completed planner minutes over a date
range. Both dates are local Istanbul dates. The range is capped at 366 days.

`days` carries every date in the range, zeros included — a heatmap renders straight off it.
`bySubject` is the distribution for the treemap, largest first, each with its share of the total
in `pct`. `dailyAvgMin` averages over the active days, not the calendar: it answers "how much
does a study day hold".

Only blocks with `status: done` count, and a block with no length counts zero. To make study time
appear here, complete blocks through the planner (see [Planner](/guides/planner)).

## What Lala does with it

Lala reads the journey in every conversation: the newest denemeler, the trend, and the weakest
topics. Lala also writes it — a student who reports a result in chat gets it recorded, and a
correction ("matematik 18'di aslında") lands as a patch. Records that Lala creates carry
`source: "chat"` and `createdBy: "lala"`, so the client can tell them apart from form entries.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.