Modelo de Dados
As entidades persistidas em Room que sustentam a biblioteca, o leitor e as configurações. Para o mecanismo de migração e o arquivo de banco em si, ver Banco de Dados.
Entidades
| Entidade | Tabela | Representa |
|---|---|---|
FolderEntity | folders | Um nó da árvore de pastas espelhada da biblioteca |
FileEntity | files | Um arquivo de leitura (CBZ/CBR/PDF/EPUB/ZIP/RAR), com progresso e metadados ComicInfo.xml embutidos |
CoverEntity | covers | Caminho da miniatura de capa em cache, por arquivo |
SettingsEntity | settings | Uma preferência do usuário, como linha chave-valor |
ReadingHistoryEntity | reading_history | Um registro de arquivo concluído — cópia independente de título/capa/pasta no momento da conclusão |
DailyStatisticsEntity | daily_statistics | Agregado de uso e leitura de um dia específico |
ReadingSessionEntity | reading_sessions | Uma sessão de leitura individual (início, fim, páginas) |
BookmarkEntity | bookmarks | Um marcador de página dentro de um arquivo |
ChapterPaginationCacheEntity | chapter_pagination_cache | Contagem de páginas já calculada para um capítulo de EPUB, sob uma combinação específica de zoom de texto e dimensões de tela |
RemoteSourceEntity | remote_sources | Um servidor Komga/Kavita conectado — tipo, URL. A credencial não fica aqui (cifrada à parte, ver abaixo) |
RemoteLibraryEntity | remote_libraries | Uma biblioteca selecionada dentro de uma fonte remota, com suas próprias opções (organização, modo de raiz, capas HQ) |
Ver Fontes Remotas para o modelo completo de fontes remotas.
Identificadores
FolderEntity e FileEntity usam como chave primária uma string derivada do document ID do SAF (Base64 do ID do documento), não um inteiro sequencial — o identificador de um item na biblioteca é, na prática, uma codificação da sua própria localização no sistema de arquivos. A pasta raiz da árvore usa o literal "root" como parentId.
Entidades sem relação direta com um arquivo específico do SAF (ReadingHistoryEntity, ReadingSessionEntity, ChapterPaginationCacheEntity) usam Long autoincrementado, por não terem um identificador natural próprio. BookmarkEntity usa chave composta (fileId, pageIndex), já que a combinação das duas é naturalmente única — no máximo um marcador por página de um arquivo.
Arquivos/pastas que vêm de uma fonte remota continuam usando FileEntity/FolderEntity — não há entidade separada por provedor. O que muda são campos extras, todos null para um item local: remoteSourceId/remoteLibraryId (qual fonte/biblioteca é dona do item), komgaBookId (Komga) ou remoteItemId/remoteVolumeId/remoteSeriesId (Kavita — capítulo/volume/série, os IDs que a própria API de progresso do Kavita exige no corpo da requisição), e localProgressUpdatedAt (carimbo de última mudança local de progresso — usado pelo merge de sync pra decidir se uma proteção "progresso local nunca regride" ainda vale ou se o servidor já pode ser tratado como fonte da verdade). RemoteLibraryEntity usa chave composta (sourceId, remoteLibraryId).
Relações são lógicas, não impostas pelo schema
Não há @ForeignKey declarado em nenhuma entidade — FileEntity.folderId, FolderEntity.parentId, CoverEntity.fileId e os demais vínculos entre tabelas são mantidos por convenção de código, não garantidos pelo banco. Remover um FolderEntity sem também remover os FileEntity filhos, por exemplo, não é impedido pelo schema; é responsabilidade de quem escreve a operação (ver como o Scanner faz isso).
Isso não significa ausência de índices: as colunas mais consultadas (folderId+name, isFavorite, isRead+currentPage em files; parentId+name, isFavorite em folders; a combinação completa de chave em chapter_pagination_cache) têm @Index dedicado — só as chaves estrangeiras em si não são impostas.
Configurações como linhas, não colunas
Preferências do usuário não viram uma coluna nova a cada funcionalidade — são todas linhas de key/value na tabela settings. As chaves e os valores padrão de cada uma vivem como constantes no companion object do repositório central (ver 02 - Arquitetura Geral).
Credencial remota não é uma coluna de tabela
A credencial de uma fonte remota (senha, API key, Auth Key) não fica em remote_sources nem em nenhuma outra tabela do Room — fica cifrada (AES/GCM) num SharedPreferences separado, com a chave de criptografia por sourceId mantida no Android Keystore, nunca em texto plano e nunca exportável junto de um dump do banco.
Cache de paginação do EPUB é sensível ao viewport
Diferente das demais entidades de cache (que dependem só do arquivo), ChapterPaginationCacheEntity é indexada pela combinação de arquivo + capítulo + zoom de texto + largura + altura da tela. Isso reflete uma particularidade real do Leitor EPUB: quantas páginas um capítulo ocupa depende de como o texto foi paginado, e isso muda se o tamanho da fonte for alterado ou o aparelho girar de orientação — o mesmo capítulo pode ter contagens de página completamente diferentes em cada combinação.