Metadata-Version: 2.4
Name: dashpacks
Version: 0.3.4
Summary: Biblioteca compartilhada das stacks Dash
Author: Rike Morais
License: Proprietary
Project-URL: Homepage, https://github.com/rikemorais/dashpacks
Project-URL: Issues, https://github.com/rikemorais/dashpacks/issues
Keywords: dash,observabilidade,jobs
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: >=3.12
Description-Content-Type: text/markdown
Requires-Dist: starlette>=0.40
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: ruff>=0.14; extra == "dev"

# dashpacks

Biblioteca compartilhada pelas stacks **DashFy**, **DashTube**, **DashTime** e
**DashHealth**.

## Por que existe

As quatro stacks nasceram de um monorepo e mantinham uma cópia da camada
`common` cada uma. A medição de 2026-09-08 mostrou o resultado: dos 34 arquivos
dessa camada, **19 eram byte a byte idênticos nas quatro**, e outros 9 divergiam
apenas porque uma stack ficara para trás.

As cópias não evoluíram em direções diferentes. Ficaram paradas em versões
diferentes do mesmo código — e três defeitos vieram daí, todos na mesma semana:

- a correlação por `request_id` não chegava ao log **nas quatro stacks**
- as regras de exclusão de chave estrangeira divergiram com o modelo idêntico
- a redefinição administrativa de senha foi portada três vezes à mão

A decisão e o levantamento estão no ADR 0003 do DashTube.

## O que entra aqui

**A regra é não depender do que fica nas stacks.** Ser idêntico nas quatro não
basta: três serviços eram idênticos e não puderam vir nesta fase, porque
importam os modelos de usuário.

Hoje:

| módulo | o que faz |
|---|---|
| `dashpacks.observability.context` | `request_id` e `job_id` em `ContextVar` |
| `dashpacks.observability.logging` | formato JSON com os identificadores |
| `dashpacks.observability.middleware` | fixa o `request_id` por requisição |
| `dashpacks.observability.job_metrics` | métricas dos trabalhos de fundo |
| `dashpacks.services.jobs` | fila serializada de trabalhos |
| `dashpacks.services.job_registry` | registro dos trabalhos disponíveis |
| `dashpacks.services.password_policy` | validação de força de senha |

## Como usar

No `requirements.txt` da stack, **com versão fixa**:

```
dashpacks @ git+ssh://git@github.com/rikemorais/dashpacks@v0.1.0
```

A versão é fixada por tag de propósito: nenhuma stack sobe sozinha, e a
atualização passa por PR e CI em cada uma. É o que impede uma versão ruim de
alcançar as quatro de uma vez.

```python
from dashpacks.observability.logging import configure_logging
from dashpacks.observability.middleware import RequestContextMiddleware

# Depois das migrações, não antes: o fileConfig do Alembic reinstala o
# formatador da raiz, e o efeito é silencioso.
configure_logging(json=settings.log_json, level=settings.log_level)
```

`configure_logging` recebe a configuração por parâmetro em vez de importar um
`settings`. São quatro aplicações com configurações próprias, e ler a de uma
delas aqui dentro amarraria as quatro ao mesmo objeto.

## O pacote de frontend

O mesmo repositório traz um pacote npm, em `js/`, com o que é comum ao frontend
das quatro stacks. A regra de entrada é a mesma: **não pode depender do que fica
nas stacks**, e ser idêntico nas quatro não basta.

| módulo | o que faz |
|---|---|
| `usePolling` | consulta periódica com cancelamento |
| `PollingController` | o controlador por trás dela, testável sem React |
| `onSessionExpired` | avisa a aplicação quando a sessão cai |
| `flagOf` | bandeira do país a partir do código |
| `titleCasePt` | capitalização que respeita as preposições do português |

O que é tema, cor e marca de cada produto **não** mora aqui: entra por
propriedade.

```
npm install @rikemorais/dashpacks@0.3.4
```

**Do registro público do npm, e não do GitHub.** O npm 12 desabilitou por padrão
as duas alternativas — `allow-git` e `allow-remote` vêm como `"none"` —, e
instalar da release ou do repositório recusa com `EALLOWREMOTE` e `EALLOWGIT`.

Ligar essas opções resolveria, e foi descartado: elas valem para **todas** as
dependências do projeto, não só para esta, e existem para barrar dependência de
origem não verificada.

O GitHub Packages seria a outra saída, e reintroduz o problema que o lado Python
evitou: exige token de autenticação nas quatro CIs e na máquina local, mesmo
para pacote público.

## Versão

**Os dois pacotes compartilham a versão do repositório.** Uma tag `vX.Y.Z`
publica os dois, mesmo que só um tenha mudado.

Uma consequência aprendida na prática: **uma versão publicada e depois
despublicada no npm fica queimada para sempre** — o registro recusa publicar
sobre ela com `You cannot publish over the previously published versions`. Foi o
que aconteceu com a `0.2.0`, e a saída foi subir para a `0.3.0`. Não há como
reaproveitar o número.

A alternativa seria versionar cada um por conta própria, com tags `py-` e `js-`.
Foi descartada porque dobra o que é preciso lembrar na hora de publicar, e o
custo de subir um pacote que não mudou é zero: quem consome fixa a versão e só
atualiza quando quiser.

Consequência prática: a `v0.2.0` traz o pacote npm novo e o Python **sem
mudança de código** desde a `v0.1.0`. Uma stack que só usa o Python não tem
motivo para atualizar.

## Publicar uma versão

```
git tag -a v0.2.1 -m "v0.2.1" && git push origin v0.2.1
```

Depois, anexar os dois artefatos à release: a wheel do Python (`python -m build
--wheel`) e o tarball do npm (`npm pack --workspace js`).

Depois, subir a versão no `requirements.txt` de cada stack, por PR. O atraso de
uma stack fica visível no arquivo, em vez de invisível na cópia.
