mic-core
Fondations agnostiques du framework MIC (Model / Interface / Controller).
mic-core est le socle : il ne dépend d'aucune brique de persistance ni de
plateforme (voir le DAG platform → data → core dans
../README.md).
Modules
| Module | Rôle |
|---|---|
mic.contracts |
Contrats statiques (StrictSchema) et gouvernés (SchemaRegistry) |
mic.model |
Erreurs de domaine (DomainError, TransientError), value objects |
mic.tenancy |
Contexte d'organisation et store relationnel à portée obligatoire |
mic.http |
Spécifications HTTP agnostiques (HttpRouteSpec, HttpResponseSpec, HttpCookieSpec, HttpRequestContext) |
mic.fastapi |
Adaptateur FastAPI (router builder, middlewares) — extra [fastapi] |
mic.litestar |
Adaptateur Litestar — extra [litestar] |
mic.auth |
JWT service-to-service [auth] et vérification OIDC/JWKS [oidc] |
mic.client |
Client HTTP inter-services (httpx) — extra [client] |
mic.observability |
Logs JSON, métriques Prometheus, traces OTel — extra [observability] / [full-observability] |
mic.healthcheck |
Sondes liveness/readiness |
mic.resilience |
Circuit breaker, retry, timeouts |
mic.cli |
Squelette CLI (argparse stdlib) — extra [cli] |
mic.grpc |
Transport gRPC — extra [grpc] |
mic.event_replay |
Replay d'events archivés vers un bus (CLI mic-events-replay) |
Le paquet est un namespace PEP 420 (pas de mic/__init__.py) : import mic.*
reste identique côté consommateur, qu'on installe mic-core seul ou avec
mic-datastore / mic-platform.
Replay d'events (mic-events-replay)
Rejoue des events archivés (DLQ outbox exportée en JSON, ou archive ClickHouse long-terme) vers un sink. Cas d'usage : audit forensic, bug-fix rétroactif (un handler a swallow des events pendant N heures → on les rejoue après fix), amorçage d'un nouveau read-model depuis l'historique.
# Dry-run (compte uniquement) depuis un dump JSON
mic-events-replay --from-json dump.json \
--topic mail.send --from 2026-06-22T08:00:00Z --to 2026-06-22T10:00:00Z
# Source ClickHouse + filtre payload (répétable)
mic-events-replay --from-clickhouse http://clickhouse.svc:8123 \
--topic mail.send --from 2026-06-22T08:00:00Z --to 2026-06-22T10:00:00Z \
--filter to_email=user@example.com
# Sink NATS JetStream (republie avec header x-replay) — extra mic-datastore[nats]
mic-events-replay --from-clickhouse http://clickhouse.svc:8123 \
--topic mail.send --from ... --to ... \
--to-nats nats://nats-0:4222,nats://nats-1:4222 --nats-stream events
Sinks : aucun = dry-run ; --target module:callable = callback sync ;
--to-nats = NATS JetStream. Exit 0 = OK, 1 = aucun event matché
(topic/range mal pinnés ?), 2 = erreur de setup.
Convention header x-replay
Chaque event republié via --to-nats porte deux headers transport
(le payload n'est pas réécrit — flag transparent) :
| Header | Valeur |
|---|---|
x-replay |
true |
x-replay-batch-id |
UUID unique par invocation (corrélation / traçabilité) |
⚠️ Les consumers doivent être idempotents — un replay redélivre des events
déjà traités. Un consumer idempotent (clé dérivée de event_id / original_id,
ou opérations naturellement idempotentes) absorbe les replays sans effet de
bord ; le header x-replay lui permet en plus de tracer ou ignorer
explicitement un replay sans changer son décodage de payload. Le support des
headers est fourni par mic.queue (cf. mic-datastore).
Installation
pip install "mic-core[fastapi,auth,client,observability]"
Contrats gouvernés
SchemaRegistry construit un StrictSchema à partir de FieldDef chargés
depuis une source de vérité versionnée. Le modèle reste immuable et refuse les
champs inconnus. Le cache TTL évite de reconstruire le modèle à chaque requête ;
un événement distribué appelle registry.invalidate(key) sur chaque instance,
et le TTL sert de filet de rattrapage si cet événement est perdu.
from mic.contracts import FieldDef, SchemaRegistry
registry = SchemaRegistry(
loader=lambda key: (
FieldDef("cluster", str),
FieldDef("replicas", int, default=1),
),
ttl=300,
)
Payload = registry.get("deployment@v2")
payload = Payload.model_validate({"cluster": "prod", "replicas": 3})
Isolation par organisation
TenantScopedRelationalStore injecte le filtre d'organisation dans les lectures
et comptages, contrôle les insertions et refuse toute opération hors d'un
tenant_context. Le repository métier doit recevoir cette vue sécurisée, jamais
le store brut.
from mic.tenancy import TenantScopedRelationalStore, tenant_context
store = TenantScopedRelationalStore(raw_store)
with tenant_context(organization_id):
rows = store.find(Project, query)
Le champ est organization_id par défaut (tenant_field permet de l'adapter).
Un filtre explicite sur ce champ est refusé : sa gestion appartient au store et
ne peut pas être neutralisée par l'appelant.
Jetons de service à portée limitée
ServiceAuthSigner.sign(scopes=[...]) encode le claim JWT standard scope.
ServiceAuthVerifier.verify() expose les valeurs dans claims.scopes, tandis
que require(token, scope=...) exige une correspondance exacte et renvoie une
erreur 403 service_auth.insufficient_scope si le service authentifié n'a pas
la permission demandée. Les tokens historiques sans scope restent valides pour
verify() ; les opérations protégées doivent appeler explicitement
require().
Extras
| Extra | Tire |
|---|---|
fastapi |
fastapi + uvicorn[standard] + starlette |
litestar |
litestar |
auth |
pyjwt |
oidc |
pyjwt + cryptography |
client |
httpx |
observability |
prometheus-client + opentelemetry-api |
sentry |
sentry-sdk (+ urllib3 patché) |
tracing |
opentelemetry-sdk + exporter OTLP |
full-observability |
observability + sentry + tracing |
grpc |
grpcio + grpcio-health-checking |
cli |
(rien — argparse stdlib) |
Versionnage
mic-core démarre en 0.x (pré-releases dev/rc sur TestPyPI). Il graduera
en 1.0 une fois les frontières prouvées et les services migrés (fin du split,
cf. ADR-0001).
En 0.x, un bump minor peut porter un changement cassant (SemVer 0.x) —
contraindre avec >=0.1,<1.
Release
Voir ../../RELEASING.md § « Release par paquet »
(make release-pkg PKG=core VERSION=x.y.z → tag core-vX.Y.Z).
Metadata
Release files for mic-core 0.1.31
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| mic_core-0.1.31.tar.gz | 129.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mic_core-0.1.31-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 301.3 kB
Release files / mic_core-0.1.31.tar.gz
| Download URL | mic_core-0.1.31.tar.gz |
|---|---|
| Size | 129.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2e9090e33e2876bcffd7307d15fc20c6f30e0a7d9728045845f88d494a1c1c18
|
|
BLAKE2b-256 checksum How to use checksums |
43e12ab93c9674d0dec03c791852aadbbded4d085ccff71f5ca9fa9d87cfc330
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Release files / mic_core-0.1.31-py3-none-any.whl
| Download URL | mic_core-0.1.31-py3-none-any.whl |
|---|---|
| Size | 171.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5283eb47fee1a07325b0cc77f9714c0c805dbc4747f61b7f29df427272482fe0
|
|
BLAKE2b-256 checksum How to use checksums |
651243d1e8b59e2dbd3bb7788dd1d173fd6c11fcbee28dfd157721e9238286a4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Security for mic-core 0.1.31
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.