Skip to main content
The planner holds blocks of study work. One block is one thing to do: a subject, an optional topic, and how much of the slot is decided. A block belongs to a local Istanbul date. It carries a wall-clock time, not an instant. A device with the wrong timezone still shows the plan the student made.

What a block is

A block always has a date and a subject. The time and the length are separate, and each one can be undecided: The response always holds both startTime and durationMin, and it adds endTime when both are known. The scheduled field is true when the block has a time. An endTime needs a startTime, and it wins over durationMin. An endTime before the startTime is a block that runs past midnight. The block stays on the day it starts.

Read a range

GET /api/plan returns every date from from to to. Empty days are in the response, so a calendar renders straight off it. The default window is today and the next six days.
The blocks of a day come back in display order: blocks with a time first, in time order, then the blocks with no time. The position field orders that second group. The range is 62 days at most. Read a month at a time. There is no cursor, because a date range is already a bounded read.

Add blocks

POST /api/plan always takes an array. One block and a whole week are the same call, and the batch lands whole or not at all.

Activity

activity says what the block is. The values and their Turkish labels: On write, the Turkish label works too. "activity": "branş denemesi" and "activity": "subject_mock" store the same value. A response always holds the English value. An unknown activity is a 400. The server also folds subject spellings, so mat, Mat and MATEMATİK all become Matematik. A subject that is not in the list survives as the student typed it.

Conflicts

Two blocks that overlap in time come back in conflicts:
The write is never refused for an overlap. The student can mean it. Show the overlap and let the student decide. Blocks that touch do not conflict. A block that ends at 10:00 and a block that starts at 10:00 are two separate blocks.

Change a block

PATCH /api/plan/{id} writes only the fields in the body. Timing merges onto what is stored: Tick a block off with status:
The server stamps completedAt when the status becomes done, and clears it when the status goes back to planned. The field is read-only. Use skipped for a block the student did not do. The block stays in the plan, and it stays out of the conflict check.

Remove a block

DELETE /api/plan/{id} returns {"id":"...","deleted":true}. A second delete of the same id returns deleted: false.
A deleted block leaves no trace. To record that the student did not do the work, set the status to skipped instead.

Lala and the plan

Lala reads the plan on every turn: yesterday and the next six days. It can add blocks, move them, and mark them done from the chat. A block that Lala created has createdBy: "lala". The student can ask for this directly. “Put maths on Friday” and “maths is done” both work in chat, and the change is in the plan before the reply arrives. Read the plan again after a chat turn, or listen on GET /api/chat/stream and read after each message.