Descrição da tarefa
Adicionar o app Django journal (singular) ao repositório scielo-tools.
O app gere o catálogo editorial de periódicos e fascículos (modelos Journal e Issue): metadados ISSN, volume/número/ano, painel Wagtail para gestão manual e sincronização periódica com a API SciELO Core (sync_journals_from_api, sync_issues_from_api via Celery). A implementação legada acopla-se a core.models.CommonControlField, core.models.CoreSyncState e utilitários em core.utils — o core do projeto atual está vazio ou mínimo e não deve ser pré-requisito.
O objetivo é tornar journal auto-suficiente e reutilizável:
- Banco de dados próprio com migrations em
journal/migrations/ (tabelas prefixadas journal_).
- Telas Wagtail próprias (snippets Journal Manager: periódicos e fascículos, ícones, autocomplete).
- APIs REST (DRF) para consulta e gestão de periódicos/fascículos por sistemas externos ou por outros apps (
manuscrito, integrações editoriais).
- Sem dependência do app
manuscrito, ia, referencia ou sps.
- Portável para outro projeto Django/Wagtail com Celery e settings documentados.
Âmbito:
| Módulo |
Responsabilidade |
journal/models.py |
Modelos Journal (periódico) e Issue (fascículo); metadados ISSN, volume, número, ano, etc. |
journal/sync_api.py |
Sincronização paginada com API SciELO Core (journals e issues). |
journal/tasks.py |
Tarefas Celery task_sync_journals_from_api, task_sync_issues_from_api. |
journal/wagtail_hooks.py |
SnippetViewSetGroup "Journal Manager", ícones SVG, autocomplete. |
journal/api/v1/ |
Endpoints REST (serializers, viewsets) para Journal e Issue. |
journal/forms.py |
Formulário admin Wagtail com registo de creator / updated_by (desacoplado de core.forms). |
journal/apps.py |
Configuração Django (JournalConfig). |
Fora do âmbito desta issue:
- Adição do app
manuscrito, ia, referencia ou sps.
- Sincronização de outros recursos Core (coleções, artigos publicados) — apenas journal/issue.
- Restauro completo do app
core como dependência obrigatória.
Pré-requisitos (blockers)
| Pré-requisito |
Consumido por |
Notas |
djangorestframework |
journal/api/ |
API REST |
wagtail-autocomplete |
journal/models.py, wagtail_hooks.py |
AutocompletePanel em Issue |
requests |
sync_api.py (via helper HTTP) |
Chamadas à API SciELO Core |
| Celery + Redis |
journal/tasks.py |
Sync assíncrono |
| Settings SciELO Core |
sync_api.py |
CORE_API_DOMAIN, CORE_JOURNAL_API_ENDPOINT, CORE_ISSUE_API_ENDPOINT, CORE_ISSUE_FROM_DATE_CREATED |
Decisões de design para reusabilidade
-
Desacoplamento de core.models e core.forms:
Issue herda metadados de controlo (creator, updated_by, created, updated) via classe abstrata JournalMetadataModel e JournalAdminModelForm em journal/forms.py.
Journal permanece modelo simples (sem campos de auditoria), salvo decisão em contrário na implementação.
-
Estado de sincronização próprio:
- Modelo
JournalSyncState em journal/models.py (recursos journal e issue), com helpers em journal/utils/sync_state.py.
-
Cliente HTTP próprio:
- Helper
fetch_data em journal/utils/requester.py, sem import de core.
-
API REST:
- Camada DRF para
Journal e Issue, além do sync interno com a API Core — requisito de reuso e integração agnóstica (RCT).
Subtarefas
API pública a preservar / expor
Serviços Python (journal.sync_api)
| Função |
Uso |
sync_journals_from_api(collection_acron=None, issn_scielo=None, from_date_updated=None) |
Importa/atualiza periódicos da API Core |
sync_issues_from_api(issn_scielo=None, from_date_updated=None) |
Importa fascículos para periódicos já registados |
get_or_create_issue_from_api_data(issue_data) |
Upsert de fascículo a partir de payload Core |
build_api_url_core(domain, endpoint, params) |
Construção de URL paginada |
Tarefas Celery (journal.tasks)
task_sync_journals_from_api(**kwargs)
task_sync_issues_from_api(**kwargs)
Endpoints REST
| Método |
Endpoint |
Descrição |
GET |
/api/v1/journal/ |
Lista periódicos (filtro por issn, acronym, title) |
GET |
/api/v1/journal/{id}/ |
Detalhe de periódico |
POST |
/api/v1/journal/ |
Cria periódico (autenticado) |
GET |
/api/v1/journal/issue/ |
Lista fascículos (filtro por journal, year, volume) |
GET |
/api/v1/journal/issue/{id}/ |
Detalhe de fascículo |
POST |
/api/v1/journal/issue/ |
Cria fascículo (autenticado) |
POST |
/api/v1/journal/sync/journal/ |
Dispara sync Celery com periódicos Core |
POST |
/api/v1/journal/sync/issue/ |
Dispara sync Celery de fascículos |
Autenticação: IsAuthenticated (JWT/sessão conforme projeto).
Wagtail autocomplete
Journal.autocomplete_search_field = "title"
Issue.autocomplete_custom_queryset_filter — filtro por journal no painel de artigos (consumido futuramente por manuscrito).
Critérios de aceite
Como testar manualmente
- Subir ambiente:
make build && make up && make django_migrate.
- Acessar Wagtail admin → Journal Manager → criar um periódico manualmente (título, ISSN).
- Criar um fascículo ligado ao periódico (volume, número, ano).
- No shell:
from journal.models import Journal, Issue
from journal.sync_api import sync_journals_from_api
print(Journal.objects.count(), Issue.objects.count())
- Testar API autenticada:
curl -H "Authorization: Bearer <token>" http://localhost:8009/api/v1/journal/
- (Opcional, com rede) Disparar sync:
from journal.tasks import task_sync_journals_from_api
task_sync_journals_from_api.delay()
Considerações e notas
- Nomenclatura: app Django
journal (singular); modelos Journal (periódico) e Issue (fascículo). A tabela do modelo Journal será journal_journal (padrão Django).
- Consumidores futuros:
manuscrito referencia Journal e Issue via FK em Article; sps usa metadados de journal/issue na geração XML. O journal deve ser pré-requisito do manuscrito.
- SciELO Core: sync depende de conectividade com
https://core.scielo.org (ou CORE_API_DOMAIN configurável). Em CI, mockar respostas ou marcar testes de integração como opcionais.
- API REST: camada DRF incluída nesta issue como requisito de reuso.
- Issue vs fascículo: na UI Wagtail o label pode permanecer "Issue" (inglês); na documentação em português usar "fascículo".
- Plano de fragmentação: ver
docs/plans/2026-06-28-fragmentar-manuscrito.md.
Referências
- API SciELO Core:
https://core.scielo.org/api/v2/pid/journal/
- Settings sugeridos:
CORE_API_DOMAIN, CORE_JOURNAL_API_ENDPOINT, CORE_ISSUE_API_ENDPOINT, CORE_ISSUE_FROM_DATE_CREATED
Descrição da tarefa
Adicionar o app Django
journal(singular) ao repositórioscielo-tools.O app gere o catálogo editorial de periódicos e fascículos (modelos
JournaleIssue): metadados ISSN, volume/número/ano, painel Wagtail para gestão manual e sincronização periódica com a API SciELO Core (sync_journals_from_api,sync_issues_from_apivia Celery). A implementação legada acopla-se acore.models.CommonControlField,core.models.CoreSyncStatee utilitários emcore.utils— ocoredo projeto atual está vazio ou mínimo e não deve ser pré-requisito.O objetivo é tornar
journalauto-suficiente e reutilizável:journal/migrations/(tabelas prefixadasjournal_).manuscrito, integrações editoriais).manuscrito,ia,referenciaousps.Âmbito:
journal/models.pyJournal(periódico) eIssue(fascículo); metadados ISSN, volume, número, ano, etc.journal/sync_api.pyjournal/tasks.pytask_sync_journals_from_api,task_sync_issues_from_api.journal/wagtail_hooks.pyjournal/api/v1/JournaleIssue.journal/forms.pycreator/updated_by(desacoplado decore.forms).journal/apps.pyJournalConfig).Fora do âmbito desta issue:
manuscrito,ia,referenciaousps.corecomo dependência obrigatória.Pré-requisitos (blockers)
djangorestframeworkjournal/api/wagtail-autocompletejournal/models.py,wagtail_hooks.pyAutocompletePanelem Issuerequestssync_api.py(via helper HTTP)journal/tasks.pysync_api.pyCORE_API_DOMAIN,CORE_JOURNAL_API_ENDPOINT,CORE_ISSUE_API_ENDPOINT,CORE_ISSUE_FROM_DATE_CREATEDDecisões de design para reusabilidade
Desacoplamento de
core.modelsecore.forms:Issueherda metadados de controlo (creator,updated_by,created,updated) via classe abstrataJournalMetadataModeleJournalAdminModelFormemjournal/forms.py.Journalpermanece modelo simples (sem campos de auditoria), salvo decisão em contrário na implementação.Estado de sincronização próprio:
JournalSyncStateemjournal/models.py(recursosjournaleissue), com helpers emjournal/utils/sync_state.py.Cliente HTTP próprio:
fetch_dataemjournal/utils/requester.py, sem import decore.API REST:
JournaleIssue, além do sync interno com a API Core — requisito de reuso e integração agnóstica (RCT).Subtarefas
journal/na raiz do projeto com a estrutura de módulos listada no âmbito.Journal,IssueeJournalSyncStatecom migrations próprias.journal/forms.pycomJournalAdminModelFormeJournalMetadataModel.journal/utils/sync_state.pyejournal/utils/requester.py.sync_api.pyetasks.py(sync paginado Core + Celery).journal/api/v1/serializers.pyeviews.pycom viewsets paraJournaleIssue.wagtail_hooks.py(snippets, ícones, autocomplete)."journal"emLOCAL_APPS(config/settings/base.py).config/settings/base.py(variáveis de ambiente com defaults documentados).config/urls.pyou router DRF global:GET/POST /api/v1/journal/(recursoJournal)GET/POST /api/v1/journal/issue/(recursoIssue)POST /api/v1/journal/sync/journal/(disparo de sync, autenticado)POST /api/v1/journal/sync/issue/(disparo de sync, autenticado)journal.svg,issue.svg).config/menu.pyparaget_menu_order("journal").API pública a preservar / expor
Serviços Python (
journal.sync_api)sync_journals_from_api(collection_acron=None, issn_scielo=None, from_date_updated=None)sync_issues_from_api(issn_scielo=None, from_date_updated=None)get_or_create_issue_from_api_data(issue_data)build_api_url_core(domain, endpoint, params)Tarefas Celery (
journal.tasks)task_sync_journals_from_api(**kwargs)task_sync_issues_from_api(**kwargs)Endpoints REST
GET/api/v1/journal/issn,acronym,title)GET/api/v1/journal/{id}/POST/api/v1/journal/GET/api/v1/journal/issue/journal,year,volume)GET/api/v1/journal/issue/{id}/POST/api/v1/journal/issue/POST/api/v1/journal/sync/journal/POST/api/v1/journal/sync/issue/Autenticação:
IsAuthenticated(JWT/sessão conforme projeto).Wagtail autocomplete
Journal.autocomplete_search_field = "title"Issue.autocomplete_custom_queryset_filter— filtro por journal no painel de artigos (consumido futuramente pormanuscrito).Critérios de aceite
python manage.py checksem erros comjournalemLOCAL_APPS.core.models,core.formsoumanuscritodentro dejournal/.journal_journal,journal_issue,journal_journalsyncstatecriadas via migrations.GET /api/v1/journal/responde com lista paginada (autenticado).POST /api/v1/journal/sync/journal/enfileira tarefa Celery sem erro (com settings Core válidos ou mock em teste).Issuefiltra porjournalno Wagtail admin.Como testar manualmente
make build && make up && make django_migrate.curl -H "Authorization: Bearer <token>" http://localhost:8009/api/v1/journal/Considerações e notas
journal(singular); modelosJournal(periódico) eIssue(fascículo). A tabela do modeloJournalserájournal_journal(padrão Django).manuscritoreferenciaJournaleIssuevia FK emArticle;spsusa metadados de journal/issue na geração XML. Ojournaldeve ser pré-requisito domanuscrito.https://core.scielo.org(ouCORE_API_DOMAINconfigurável). Em CI, mockar respostas ou marcar testes de integração como opcionais.docs/plans/2026-06-28-fragmentar-manuscrito.md.Referências
https://core.scielo.org/api/v2/pid/journal/CORE_API_DOMAIN,CORE_JOURNAL_API_ENDPOINT,CORE_ISSUE_API_ENDPOINT,CORE_ISSUE_FROM_DATE_CREATED