# Arquivo .olq, o formato do Ciclo de Estudos

Fonte: https://olimpq.com/docs/referencia/arquivo-olq
Atualizado em: 2026-10-05

O `.olq` é o arquivo que guarda um ciclo do OlimpQ. Esta página explica o formato inteiro, campo por campo. Ela foi escrita pra duas pessoas ao mesmo tempo: **quem quer entender o arquivo** e **uma IA que vai montar um ciclo pra alguém**.

Quer só que uma IA monte o seu? Pule pra [Pedir pra uma IA montar seu ciclo](#pedir-pra-uma-ia-montar-seu-ciclo).

## O que é o Ciclo de Estudos

O Ciclo de Estudos é o planejador do OlimpQ. O aluno conta o que precisa estudar e quanto tempo tem, e o app monta a agenda do dia: qual matéria, qual conteúdo, por quanto tempo e que tipo de tarefa (teoria, questões, revisão).

Tudo é organizado em **grupos**. Um grupo é um objetivo, tipo "OBMEP 2027" ou "ENEM". Dentro dele ficam as **matérias**, e dentro de cada matéria os **conteúdos**. O app transforma isso numa fila de **blocos** de estudo e encaixa os blocos nos horários livres do aluno.

A explicação completa, sem parte técnica, está em [Ciclo de Estudos](/docs/produto/ciclo-de-estudos).

## O que é o arquivo .olq

Um `.olq` guarda **um grupo do Ciclo**: as matérias, os conteúdos, a ordem e o quanto cada coisa pesa. Ele serve pra:

- **Compartilhar um ciclo.** Um professor monta o ciclo da turma uma vez e manda o arquivo pra todo mundo.
- **Fazer backup** ou levar o ciclo pra outra conta.
- **Criar um ciclo fora do app**, à mão ou com uma IA, e importar pronto.

O que ele **leva**: a estrutura do grupo e, se quem exportou quiser, a rotina (horários e preferências).

O que ele **nunca leva**: progresso. Tempo estudado, conteúdos dominados, revisões, XP, ofensiva e histórico ficam na conta de quem exportou. Quem importa um ciclo de alguém que já estudou metade do ENEM começa do zero.

Importar **sempre cria um grupo novo**. O arquivo nunca altera um grupo que já existe. Se o aluno já tiver um ciclo com o mesmo nome, a prévia avisa antes.

## Como funciona por dentro

Daqui pra baixo é a parte técnica.

O `.olq` é um **JSON puro** em UTF-8, com a extensão `.olq`. Não é zip nem binário: dá pra abrir em qualquer editor de texto.

Quando o aluno importa, o app:

1. Lê o arquivo e confere se é um `.olq` válido.
2. **Corrige o que dá pra corrigir**: corta texto longo demais, prende número fora da faixa, troca ícone desconhecido pelo padrão.
3. Mostra uma **prévia** com o que vai entrar e o que foi ajustado.
4. Só quando o aluno toca em **Importar** grava tudo de uma vez. Se der erro no meio, nada fica pela metade.

Ou seja: quase todo erro de valor vira ajuste, não falha. Só alguns erros de estrutura recusam o arquivo (estão em [O que faz o arquivo ser recusado](#o-que-faz-o-arquivo-ser-recusado)).

## O menor arquivo que funciona

```json
{
  "format": "olq",
  "version": 3,
  "scale": 10,
  "group": {
    "label": "Física do 1º ano",
    "mode": "rodizio",
    "focusKind": "custom",
    "subjects": [
      { "name": "Cinemática", "topics": [] },
      { "name": "Dinâmica", "topics": [] }
    ]
  }
}
```

Isso cria um grupo em Rodízio com duas matérias, sem conteúdo. O app estuda cada matéria como um todo. Tudo que não aparece no arquivo recebe o valor padrão.

## Um arquivo completo

```json
{
  "format": "olq",
  "version": 3,
  "scale": 10,
  "exportedAt": "2026-10-05T10:00:00.000",
  "exportedBy": "Prof. Ana",
  "group": {
    "label": "OBMEP 2027 · Nível 2",
    "mode": "planejado",
    "focusKind": "olympiad",
    "focusOlympiadId": "41d9c968-8b2c-4183-be8f-280bb114120e",
    "iconName": "sigma",
    "colorHex": "#ECC855",
    "weight": 8,
    "examMinutes": 150,
    "subjects": [
      {
        "name": "Aritmética",
        "weight": 9,
        "difficulty": 6,
        "topics": [
          { "name": "Múltiplos e divisores", "size": 2, "priority": 3 },
          { "name": "Critérios de divisibilidade", "size": 1, "priority": 3 },
          {
            "name": "MDC e MMC",
            "size": 2,
            "priority": 2,
            "note": "Fazer a lista 3 da apostila depois",
            "link": "https://portaldaobmep.impa.br"
          }
        ]
      },
      {
        "name": "Geometria",
        "weight": 8,
        "difficulty": 8,
        "blockMinutes": 60,
        "topics": [
          { "name": "Ângulos", "size": 1, "priority": 2 },
          { "name": "Triângulos", "size": 3, "priority": 3 },
          { "name": "Áreas", "size": 3, "priority": 3 }
        ]
      },
      {
        "name": "A 2ª Fase",
        "weight": 7,
        "difficulty": 9,
        "examPhase": 2,
        "topics": [
          { "name": "Escrever uma solução completa", "size": 3, "priority": 3 }
        ]
      }
    ]
  },
  "routine": {
    "applyByDefault": false,
    "windows": [
      { "weekday": 1, "start_minute": 1140, "end_minute": 1260 },
      { "weekday": 3, "start_minute": 1140, "end_minute": 1260 }
    ],
    "preferences": { "blockMinutes": 50, "breakMinutes": 10 }
  }
}
```

Cada campo está explicado abaixo, com o que ele muda no app.

## A raiz do arquivo

| Campo | Obrigatório | Valor | O que é |
| --- | --- | --- | --- |
| `format` | sim | `"olq"` | identifica o arquivo. Qualquer outro valor recusa |
| `version` | sim | `3` | versão do formato. Use sempre `3` |
| `scale` | recomendado | `10` | escala dos pesos. Sem ele, arquivo de versão 1 é lido na escala antiga (1 a 5) e os pesos dobram |
| `group` | sim | objeto | o grupo. Veja abaixo |
| `routine` | não | objeto | horários e preferências. Veja [`routine`](#routine-horários-e-preferências) |
| `exportedAt` | não | data ISO | quando o arquivo foi feito. Só informativo |
| `exportedBy` | não | texto, até 40 | quem fez. Aparece na prévia da importação |
| `exportedWith` | não | texto | versão do app que exportou. Só pra diagnóstico |

## `group`

| Campo | Valor | Padrão | O que muda |
| --- | --- | --- | --- |
| `label` | texto, até 40 | `"Meu ciclo"` | o nome do grupo na tela |
| `mode` | `"lista"`, `"rodizio"`, `"planejado"` | `"planejado"` | o jeito de estudar. Veja [Os três modos](#os-três-modos) |
| `focusKind` | `"olympiad"`, `"enem"`, `"custom"` | `"custom"` | o tipo de objetivo. Decide de onde vem a data da prova |
| `focusOlympiadId` | id da olimpíada | nenhum | só com `focusKind: "olympiad"`. Liga o grupo ao calendário daquela olimpíada |
| `targetDate` | `"AAAA-MM-DD"` | nenhum | data da prova. Tem prioridade sobre a data automática |
| `weight` | 1 a 10 | `5` | peso do grupo contra os outros grupos ativos do aluno |
| `iconName` | nome da lista abaixo | `"target"` | ícone do grupo |
| `colorHex` | `"#RRGGBB"` | `"#8B45A3"` | cor do grupo |
| `examMinutes` | 15 a 360 | nenhum | duração da prova real. Vira a duração sugerida do simulado |
| `examEvent` | objeto | nenhum | simulado semanal do grupo. Veja [Compromisso fixo e simulado](#compromisso-fixo-e-simulado) |
| `phaseMode` | `"off"` | automático | desliga a mudança de estratégia perto da prova |
| `templateSlug` | texto | nenhum | de qual modelo pronto o grupo veio. Só informativo, pode omitir |
| `subjects` | lista | obrigatório | as matérias, **na ordem de estudo**. Pelo menos uma |

### A data da prova

O grupo descobre a data da prova nesta ordem:

1. `targetDate`, se tiver.
2. Com `focusKind: "enem"`, a próxima data do ENEM, que o OlimpQ já conhece.
3. Com `focusKind: "olympiad"`, a próxima prova daquela olimpíada no [calendário olímpico](/calendario-olimpico).

**Impacto:** com data, o modo Planejado calcula quanto da matéria cabe até a prova, prioriza o que mais importa e muda de estratégia nas últimas semanas. Sem data, o ciclo roda sem prazo. Data que já passou é tratada como sem data, e o app pergunta ao aluno o que fazer.

### Ids das olimpíadas

O `focusOlympiadId` é o id interno da olimpíada no OlimpQ. Os das olimpíadas com banco de questões e modelo pronto:

| Olimpíada | `focusOlympiadId` |
| --- | --- |
| OBMEP | `41d9c968-8b2c-4183-be8f-280bb114120e` |
| OBA | `3f5a3846-69b6-476e-af66-74e407d65cc7` |
| OBI | `8f366598-1c9d-43fe-bf13-0a0687398933` |
| Mandacaru | `8c5c0d1d-0120-4c6f-8465-4b4b8f2c43f0` |
| Jacob Palis | `7e1edafc-7319-4e8e-bef2-0386ba44b383` |
| Elon Lages | `ffe0a701-6412-4208-842d-4cc38b23bbe8` |

Não sabe o id, ou a olimpíada não está aqui? Use `focusKind: "custom"` e coloque a data em `targetDate`. Um id errado não quebra o arquivo: o grupo entra como objetivo livre, sem data automática, e o app avisa o aluno depois de importar.

### Ícones e cores

`iconName` aceita só estes nomes: `target`, `flame`, `atom`, `sigma`, `flask`, `dna`, `globe`, `book`, `code`, `cpu`, `brain`, `compass`, `rocket`, `trophy`, `graduation`, `pen`, `calculator`, `landmark`. Outro nome vira `target`.

`colorHex` aceita qualquer cor `#RRGGBB`. `#RGB` é expandido. As cores do seletor do app são `#8B45A3`, `#AB68C4`, `#ECC855`, `#3B82F6`, `#29B6F6`, `#4CAF50`, `#26C6DA`, `#FFA726`, `#EF5350`, `#FF6B35`, `#E9A14C` e `#D66BFF`. Prefira uma delas.

## Os três modos

O `mode` muda quais campos importam. Escolha antes de preencher o resto.

| Modo | Como o app usa | Campos que importam |
| --- | --- | --- |
| `lista` | checklist: o aluno marca o que fez. Sem fila e sem horário | nomes, `note`, `link` |
| `rodizio` | gira entre as matérias, cada uma com um número fixo de sessões por volta | `sessionsPerRound`, `blockMinutes` |
| `planejado` | o app reparte o tempo por peso, dificuldade, tamanho, prioridade e data da prova | tudo |

**Qual escolher:**

- Prova com data e ementa conhecida (olimpíada, ENEM, vestibular): `planejado`.
- Várias matérias sem prova específica, ou quem quer só revezar: `rodizio`.
- Lista de tarefas pra riscar (capítulos, provas antigas, exercícios): `lista`.

## `subjects[]`, as matérias

| Campo | Valor | Padrão | O que muda |
| --- | --- | --- | --- |
| `name` | texto, até 60 | `"Matéria"` | o nome da matéria |
| `weight` | 1 a 10 | `6` | **Planejado.** O quanto a matéria importa no objetivo |
| `difficulty` | 1 a 10 | `6` | **Planejado.** O quanto ela é difícil pra esse aluno |
| `sessionsPerRound` | 1 a 20 | `2` | **Rodízio.** Quantas sessões da matéria em cada volta. A tela do app oferece de 1 a 6 |
| `blockMinutes` | 25, 30, 45, 50, 60 ou 90 | a da conta | duração do bloco só desta matéria. Outro valor é descartado |
| `lockedMinutesWeek` | 15 a 3000 | nenhum | **Planejado.** Minutos fixos por semana. A matéria sai da divisão automática e leva sempre isso |
| `examPhase` | `2` | nenhum | marca a matéria como da 2ª fase da prova |
| `commitments` | lista | nenhum | compromisso fixo da matéria. Veja abaixo |
| `topics` | lista | vazia | os conteúdos, **na ordem de estudo** |

**Impacto de peso e dificuldade:** no Planejado, a fatia de tempo da matéria cresce com os dois juntos, e um pouco com a quantidade de conteúdos. Matéria peso 9 e dificuldade 8 recebe bem mais tempo que uma peso 4 e dificuldade 3. Toda matéria recebe pelo menos alguma vez, nenhuma some.

**Impacto do `examPhase: 2`:** a matéria pesa bem menos até o aluno dizer no app que passou pra próxima fase. Serve pra prova com 2ª fase diferente da 1ª, como a OBMEP, onde a 2ª fase é escrita.

**Matéria sem conteúdo** (`"topics": []`) é válida. O app estuda ela como um todo, alternando teoria e questões.

## `topics[]`, os conteúdos

| Campo | Valor | Padrão | O que muda |
| --- | --- | --- | --- |
| `name` | texto, até 80 | obrigatório | o nome do conteúdo |
| `size` | 1, 2, 3 ou 4 | `2` | quanto tempo uma passada completa leva |
| `priority` | 1, 2 ou 3 | `2` | o quanto o conteúdo importa pra prova |
| `note` | texto, até 280 | nenhum | anotação que o aluno vê no conteúdo |
| `link` | `https://`, até 300 | nenhum | link de material. Só `https`, o resto é descartado |
| `archived` | `true` | `false` | conteúdo que fica no grupo mas fora da fila |

### `size`, o tamanho

| `size` | Nome no app | Uma passada leva cerca de |
| --- | --- | --- |
| `1` | P | 1 hora |
| `2` | M | 2 horas |
| `3` | G | 3 horas |
| `4` | GG | 5 horas |

**Impacto:** o tamanho decide quantos blocos o conteúdo recebe antes de contar como visto, e quanto tempo ele ocupa no cálculo até a prova. Depois, as respostas do aluno no "Como você saiu?" ajustam o tamanho pra ele. O arquivo só dá o ponto de partida.

Escolha pelo volume de material, não pela importância: um assunto pontual é `1`, um capítulo inteiro de livro é `3` ou `4`.

### `priority`, a prioridade

| `priority` | Nome no app |
| --- | --- |
| `1` | baixa |
| `2` | normal |
| `3` | alta |

**Impacto:** quando o tempo até a prova não cobre a matéria inteira, os de prioridade alta entram primeiro e os de baixa ficam pra "se sobrar tempo". Nas últimas semanas, a prioridade também decide o que é revisado mais vezes. **A prioridade não muda a ordem de estudo.**

Escolha pela frequência com que o assunto cai na prova. Divida mais ou menos em terços: o terço que mais cai é `3`, o do meio `2`, o resto `1`. Se tudo for `3`, nada é prioridade.

### A ordem é a trilha

A posição na lista **é a ordem de estudo**, tanto das matérias quanto dos conteúdos. O app passa pelos conteúdos de cima pra baixo e nunca reordena o arquivo.

Ordene por **pré-requisito**, nunca por importância: frações antes de porcentagem, ângulos antes de triângulos, órbitas antes das Leis de Kepler. Conteúdo avançado no topo faz o aluno estudar o difícil sem a base.

## Compromisso fixo e simulado

Compromisso fixo é um bloco garantido num dia da semana, tipo "Redação toda segunda, 60 minutos". O simulado é a prova inteira, cronometrada, num dia da semana.

```json
"commitments": [
  { "weekday": 1, "minutes": 60, "intent": "simulado", "frequency": "weekly" }
]
```

```json
"examEvent": { "weekday": 6, "minutes": 150, "frequency": "auto" }
```

| Campo | Valor | O que é |
| --- | --- | --- |
| `weekday` | 0 a 6 | dia da semana. **0 é domingo**, 1 segunda, até 6 sábado |
| `minutes` | 15 a 360 | duração |
| `intent` | `teoria`, `questoes`, `revisao`, `correcao`, `resumo`, `simulado` | o tipo de tarefa do bloco. Só em `commitments`. Padrão `questoes` |
| `frequency` | `weekly`, `biweekly`, `monthly`, `auto` | toda semana, a cada duas, uma vez por mês, ou automático |

`commitments` fica dentro de uma matéria, com no máximo 7 por matéria. `examEvent` fica no `group`, um por grupo.

`frequency: "auto"` segue a distância da prova: mais espaçado quando ela está longe, toda semana no fim. É o padrão do `examEvent`. O padrão do compromisso é `weekly`.

**Impacto:** compromisso e simulado são **rotina**, não estrutura. Eles só entram se o aluno marcar **Usar a rotina do arquivo** na importação.

## `routine`, horários e preferências

```json
"routine": {
  "applyByDefault": false,
  "windows": [
    { "weekday": 1, "start_minute": 1140, "end_minute": 1260 }
  ],
  "preferences": {
    "blockMinutes": 50,
    "breakMinutes": 10,
    "reviewMinutes": 15,
    "sessionGroupBlocks": 2,
    "dayStartMinute": 480
  }
}
```

| Campo | Valor | O que é |
| --- | --- | --- |
| `windows` | lista | horários livres. `start_minute` e `end_minute` são minutos desde a meia-noite (`1140` = 19:00). Até 3 por dia |
| `dailyMinutes` | lista de `{ "weekday", "minutes" }` | pra quem não tem horário fixo: minutos por dia, até 960. Use `windows` **ou** `dailyMinutes` |
| `preferences.blockMinutes` | 25, 30, 45, 50, 60, 90 | duração padrão do bloco |
| `preferences.breakMinutes` | 5, 10, 15, 20 | pausa entre blocos |
| `preferences.reviewMinutes` | 10, 15, 20, 30 | duração da revisão curta |
| `preferences.sessionGroupBlocks` | 1 a 4 | quantos blocos seguidos do mesmo conteúdo antes de trocar |
| `preferences.dayStartMinute` | 0 a 1439 | a que horas o dia de estudo começa |
| `applyByDefault` | `false` | informativo. Quem decide é o aluno, na importação |

Valor de `preferences` fora da lista é arredondado pro mais próximo, e a prévia avisa.

> **Atenção:** horários e preferências valem pra **conta inteira**, não só pro grupo. Se o aluno aceitar a rotina do arquivo, ela substitui a dele. Por isso a opção vem desmarcada. Só coloque `routine` quando o próprio aluno pediu e passou os horários dele.

## Limites

| O quê | Limite |
| --- | --- |
| tamanho do arquivo | 1 MB |
| nome do grupo | 40 caracteres |
| nome da matéria | 60 caracteres |
| nome do conteúdo | 80 caracteres |
| matérias por grupo | 30 |
| conteúdos por matéria e por grupo | depende do plano. Quem é Free tem um teto menor que o [PRO](/pro) |

O que passa do limite é cortado (sempre os últimos da lista) e a prévia avisa. Grupos em `lista` não contam no limite de grupos ativos do aluno. Os outros modos contam, e quem já está no limite precisa arquivar um grupo antes de importar.

## O que faz o arquivo ser recusado

Só estes casos recusam o arquivo inteiro:

- não é JSON, nem depois da limpeza abaixo (aspas simples, chave sem aspas, chave fechando no lugar errado). A mensagem diz a linha do erro;
- passa de 1 MB ou está vazio;
- `format` diferente de `"olq"`;
- `version` menor que 1 ou maior que 3;
- não tem `group`, ou o grupo não tem nenhuma matéria.

O resto é ajustado e aparece na prévia. Isso inclui a sujeira que IA costuma deixar: o app tira comentário (`//` e `/* */`), vírgula sobrando antes de `}` ou `]`, a cerca ` ```json ` e qualquer frase antes ou depois do JSON. Número escrito como texto (`"150"`) também é lido como número.

Mesmo assim, entregue JSON limpo: é o que funciona em qualquer versão do app.

## Pedir pra uma IA montar seu ciclo

Dá pra pedir pra qualquer IA (ChatGPT, Claude, Gemini) montar um `.olq` pra você:

1. Nesta página, toque em **Copiar página** lá no topo.
2. Cole numa conversa com a IA.
3. Logo abaixo, cole o pedido que está aqui embaixo, trocando o que está entre colchetes.

```text
Use a referência do formato .olq acima e monte um arquivo .olq pra mim.

Meu objetivo: [ex: OBMEP nível 2, ENEM, vestibular da Unicamp, Física do 1º ano]
Data da prova: [ex: 2027-06-05, ou "não tenho"]
Série: [ex: 9º ano]
Matérias e o que eu já sei: [ex: vou bem em aritmética, travo em geometria]
Quanto tempo tenho por semana: [ex: 6 horas]

Regras:
- Responda só com o JSON, sem comentários dentro dele.
- Ordene os conteúdos por pré-requisito, do básico ao avançado.
- Use priority pela frequência com que o assunto cai na prova.
- Use size pelo volume de material do assunto.
- Não inclua "routine".
```

A IA devolve o JSON. Pra virar arquivo:

- **No computador:** cole num editor de texto (Bloco de Notas, TextEdit, VS Code) e salve como `meu-ciclo.olq`. Se o nome ficar `meu-ciclo.olq.txt` ou `.json`, tudo bem: o app abre também.
- **No celular:** peça pra IA "gerar o arquivo pra baixar". Várias IAs conseguem entregar o arquivo pronto.

Depois, no OlimpQ: **Novo grupo** e **Importar arquivo .olq**. Confira a prévia e toque em **Importar**. Como a conta é a mesma em todo lugar, importar no computador já põe o ciclo no celular.

> Dentro do app tem um caminho mais curto: **Montar com a OlimpQ AI**, na criação do grupo. Ela conhece o seu histórico e propõe a estrutura direto no app, sem arquivo.

## Pra IA que vai montar o arquivo

Se você é uma IA lendo isto pra montar um ciclo, siga esta ordem:

1. **Entenda o objetivo.** Prova com data e ementa: `planejado`. Revezar matérias sem prova: `rodizio`. Lista de tarefas: `lista`. Se o pedido não deixa claro, pergunte antes.
2. **Defina o foco.** ENEM: `focusKind: "enem"`. Olimpíada da tabela de ids: `olympiad` com o id. Qualquer outra coisa: `custom`, com `targetDate` se o aluno deu a data.
3. **Monte as matérias** na ordem em que fazem sentido estudar. Habilidade que a prova cobra e não é "matéria" (escrever solução, interpretar gráfico, conversão de unidades) pode virar matéria própria.
4. **Dê peso e dificuldade** (Planejado). Peso pelo quanto a matéria vale na prova. Dificuldade pelo que o aluno disse sobre ele mesmo. Na dúvida, `6`. Não deixe tudo igual: aí o peso não diz nada.
5. **Liste os conteúdos** por pré-requisito. Nomes curtos e concretos ("Semelhança de triângulos", não "Geometria parte 2"). Prefira um assunto por conteúdo a um conteúdo gigante.
6. **Dê `size` pelo volume** e **`priority` pela incidência na prova**, em terços.
7. **Não invente rotina.** Só use `routine`, `commitments` ou `examEvent` se o aluno pediu, e com os horários dele. Lembre que a rotina substitui a da conta inteira.
8. **Respeite os limites**: nomes dentro do tamanho, no máximo 30 matérias, valores dentro das faixas.
9. **Entregue JSON válido**, sem comentário e sem vírgula sobrando, com `"format": "olq"`, `"version": 3` e `"scale": 10`.

Um bom ciclo de olimpíada costuma ter de 4 a 8 matérias e algumas dezenas de conteúdos no total. Ciclo grande demais faz a primeira volta demorar meses.

## Modelos prontos como referência

O OlimpQ tem modelos prontos (ENEM e olimpíadas) que já nascem com a prioridade calculada a partir das provas reais do banco de questões. Pra ver como um bom `.olq` fica, crie um grupo por um modelo no app e use **Exportar grupo (.olq)**, no menu do grupo. O arquivo exportado é um exemplo real, que dá pra ajustar e reimportar.

## Versões do formato

| Versão | O que mudou |
| --- | --- |
| 1 | primeira versão. Pesos de 1 a 5 e rotina solta na raiz |
| 2 | pesos de 1 a 10 (`scale: 10`), `routine`, peso do grupo, data da prova e minutos fixos por semana |
| 3 | `mode`, `sessionsPerRound`, `commitments`, e conteúdo com `size`, `priority`, `note` e `link` |

Arquivos 1 e 2 continuam abrindo e são convertidos sozinhos. Nos antigos, o conteúdo tinha peso e dificuldade no lugar de prioridade e tamanho. A conversão é:

- tamanho pela dificuldade: até 3 vira `1`, até 6 vira `2`, até 8 vira `3`, acima vira `4`;
- prioridade pelo peso: até 4 vira `1`, até 7 vira `2`, acima vira `3`.

A versão 3 ganhou campos opcionais com o tempo (`blockMinutes`, `phaseMode`, `examMinutes`, `examEvent`, `examPhase`, `frequency`, `archived`, `dailyMinutes`) sem mudar o número. App antigo ignora o que não conhece, e arquivo antigo abre igual. A versão só sobe quando um arquivo antigo deixaria de significar a mesma coisa.