> ## Documentation Index
> Fetch the complete documentation index at: https://docs.amazingzebra.com/table-mutation-tracker/llms.txt
> Use this file to discover all available pages before exploring further.

# Data model

> The snapshot files n8n commits and the rolling index the scraper maintains.

All data lives in a private GitHub repository, separate from the code. A snapshot is addressed by its date and time, and each class inside it by a slug from the scraper's configuration.

```text theme={null}
snapshots/
  2026-06-05/
    153000/
      geometry/assignments.json
      french_i/assignments.json
      metadata.json
index/
  rolling_index.json
```

* Dates are flat ISO directories (`YYYY-MM-DD`), not nested by year and month.
* Times are `HHMMSS`, so several scrapes per day sort correctly.
* Test data uses the same layout under `snapshots/synthetic/` and `index/synthetic/`. The frontend's `DATA_PREFIX` setting chooses which tree it reads.

> [!NOTE]
>
> Examples on this page use generated test data. Names are invented.

## assignments.json

An array with one object per assignment row in the class's portal table.

```json assignments.json theme={null}
[
  {
    "due_date": "2026-05-19",
    "category": "Chapter Tests/Project Based",
    "name": "Unit 3 Exam",
    "flags": {
      "collected": false,
      "late": false,
      "missing": false,
      "exempt": false,
      "absent": false,
      "incomplete": false,
      "excluded": false
    },
    "score_raw": "47.7/60",
    "points_earned": 47.7,
    "points_possible": 60,
    "percent": 79.5,
    "grade": "C+",
    "has_comments": false
  }
]
```

**name** `string` *required*

Assignment name as shown in the portal. Together with `due_date`, it identifies the assignment across snapshots.

**due\_date** `string` *required*

ISO date, `YYYY-MM-DD`. If the portal shows a date that is not in `MM/DD/YYYY` form, the original text is kept as is, and an empty date becomes an empty string.

**category** `string`

Grading category, such as homework or tests.

**score\_raw** `string`

Score text exactly as displayed, for example `47.7/60`. Kept alongside the parsed numbers so nothing is lost in normalization.

**points\_earned** `number | null`

Parsed from `score_raw`. Null when the assignment is not yet scored (`--/60`) or when `score_raw` is not in `earned/possible` form.

**points\_possible** `number | null`

Parsed from `score_raw`.

**percent** `number | null`

Percentage shown by the portal.

**grade** `string | null`

Letter grade shown by the portal.

**has\_comments** `boolean`

True when the teacher has left a comment on the assignment.

**flags** `object`

Status markers from the portal. Each is true when its icon appears in the row.

**flags**

**collected** `boolean`

**late** `boolean`

**missing** `boolean`

**exempt** `boolean`

**absent** `boolean`

**incomplete** `boolean`

**excluded** `boolean`

## metadata.json

One per snapshot. Built by n8n from the scrape response and committed after the class files.

```json metadata.json theme={null}
{
  "date": "2026-06-05",
  "time": "153000",
  "scrape_timestamp": "2026-06-05T15:30:00-08:00",
  "classes": {
    "geometry": {
      "course": "Geometry",
      "teacher": "Rivera, Ana",
      "expression": "1(A)",
      "term": "S2",
      "final_grade": "B",
      "final_percent": 85.4,
      "assignment_count": 19,
      "last_updated": "6/5/2026"
    }
  }
}
```

**date** `string` *required*

Snapshot date, `YYYY-MM-DD`.

**time** `string` *required*

Snapshot time, `HHMMSS`.

**scrape\_timestamp** `string`

ISO 8601 timestamp of the scrape.

**classes** `object` *required*

Keyed by class slug. A class present in one snapshot and absent from the next is reported as a class-level change.

**class**

**course** `string`

Course name.

**teacher** `string`

Teacher name as shown in the portal.

**expression** `string`

Period or schedule expression.

**term** `string`

Term code.

**final\_grade** `string | null`

Current letter grade for the class.

**final\_percent** `number | null`

Current percentage for the class.

**assignment\_count** `integer`

Number of assignment rows scraped.

**last\_updated** `string | null`

The portal's own last-updated date for the class.

## rolling\_index.json

A single file with one entry per snapshot, oldest first. The calendar reads only this file, so it never has to fetch individual snapshots to color a month.

```json rolling_index.json theme={null}
{
  "snapshots": [
    {
      "date": "2026-06-05",
      "time": "153000",
      "scrape_timestamp": "2026-06-05T15:30:00-08:00",
      "previous_snapshot": "2026-06-05/083000",
      "changes": {
        "class_level": 0,
        "added": 1,
        "modified": 2,
        "deleted": 0,
        "total": 3
      },
      "classes": {
        "geometry": {
          "course": "Geometry",
          "final_grade": "B",
          "final_percent": 85.4,
          "assignment_count": 19
        }
      },
      "gpa": 3.65
    }
  ]
}
```

**previous\_snapshot** `string | null`

The `date/time` this entry was diffed against. Null for the first snapshot.

**changes** `object`

Counts from comparing this snapshot with `previous_snapshot`.

**changes**

**added** `integer`

Assignments present now and not before.

**modified** `integer`

Assignments with at least one changed field. One assignment counts once, however many fields changed.

**deleted** `integer`

Assignments present before and not now.

**total** `integer`

Sum of added, modified, and deleted.

**class\_level** `integer`

Classes added or removed, plus classes whose final grade changed. Not included in `total`.

**classes** `object`

A summary of each class in the snapshot: course, final grade, final percent, and assignment count.

**gpa** `number | null`

Weighted GPA on a 4.0 scale. Honors classes add 0.5 and AP classes add 1.0. Weights come from the scraper's class configuration. Null when no class has a gradeable letter grade.


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