SelebeYone (SLY) — Gateway Carrefour
SelebeYone signifie carrefour en wolof. C'est le hub unique de l'écosystème DYNORS : toute requête — interne ou partenaire B2B — passe par SLY avant d'atteindre un service.
Code : SLY
Stack : Spring Cloud Gateway · WebFlux · R2DBC PostgreSQL · Redis
Repo :dynors-platform/selebeyone/
Rôle
Client (app DYNORS ou partenaire B2B)
│
▼
┌───────────────────────┐
│ SelebeYone (SLY) │ ← une seule URL publique
│ sly.dynors.com │
│ │
│ 1. Identification │ Qui appelle ? (interne ou B2B)
│ 2. Autorisation │ Droits sur ce path ?
│ 3. Routage │ Vers quel backend ?
│ 4. Forward + headers │ Propagation contexte
└───────────┬───────────┘
│ réseau privé — backends invisibles de l'extérieur
┌───────────▼────────────────────────────────────────┐
│ FISCAL · BOOKS · TRACIUM · notify · DAWALALE · … │
└────────────────────────────────────────────────────┘
Deux types de trafic
| Type | Signal | Validation | Quotas |
|---|---|---|---|
| Interne DYNORS | X-Source-App + réseau privé |
Token service (HMAC/JWT) + tenant en DB | Non |
| B2B (partenaires) | X-Sly-Pass |
Hash SHA-256 → sly_passes + scope vs path |
Oui |
Tout autre cas → 401.
Table de routage
| Path entrant | Backend | Variable env |
|---|---|---|
/fiscal/** |
FISCAL | FISCAL_BASE_URL |
/books/** |
dynors-books | BOOKS_BASE_URL |
/tracium/** |
TRACIUM | TRACIUM_BASE_URL |
/notify/** |
notify | NOTIFY_BASE_URL |
/dawalale/** |
DAWALALE | DAWALALE_BASE_URL |
/supergest/** |
supergest-api | SUPERGEST_BASE_URL |
/mediconnect/** |
mediconnect-api | MEDICONNECT_BASE_URL |
/yobale/** |
yobale-api | YOBALE_BASE_URL |
/ragnar/** |
ragnar-api | RAGNAR_BASE_URL |
/books-app/** |
books-api | BOOKS_APP_BASE_URL |
Les routes /supergest/**, /mediconnect/**, etc. sont des routes de callback — elles permettent aux services de rappeler les applications pour les traitements asynchrones (ex. DGI → SuperGest).
Passe B2B (sly_passes)
- Chaque partenaire B2B dispose d'un pass délivré par l'admin SLY.
- Le pass brut n'est jamais stocké — seulement son hash SHA-256 (table
sly_passes). - Le pass porte un
tenant_codeet desscopes(ex.fiscal:certify,fiscal:invoices:write). - Révocation :
active = falsedanssly_passes→ effective en < 10 min (TTL cache). - Gestion via interface admin SLY — accès LDAP uniquement.
Scope B2B activé (v1)
| Service | Scopes disponibles |
|---|---|
| FISCAL ✅ | fiscal:certify, fiscal:invoices:write, fiscal:invoices:read, fiscal:invoices:finalize, fiscal:invoices:pdf |
| TRACIUM | ⏳ v2 |
| BOOKS | ⏳ v2 |
| notify, DAWALALE | ❌ interne uniquement |
returnUrl (callbacks async)
Certaines opérations sont asynchrones (ex. certification DGI). L'app appelante passe un returnUrl dans le body — SLY route le callback de retour vers elle.
SuperGest → POST /fiscal/certify (returnUrl: sly.../supergest/callbacks/fiscal)
│
FISCAL traite + appelle DGI
│
DGI répond → FISCAL appelle returnUrl
│
SLY route /supergest/callbacks/... → supergest-api
Logs de routage (debug)
SLY trace chaque requête à trois niveaux :
| Niveau | Ce qui est loggé |
|---|---|
INFO |
Requête entrante (method, path, IP, tenant), résultat final (status, durée, type, source/partner, route matchée) |
DEBUG |
En plus : headers entrants/sortants sanitisés (valeurs sensibles masquées), route SCG matchée, URI backend résolue, signal de fin |
WARN |
Requêtes rejetées (401/403), pass invalide, cible non résolue |
Activer le mode DEBUG pour une app ou un path :
# application.yml SLY
logging:
level:
com.dynors.sly: DEBUG
org.springframework.cloud.gateway: DEBUG
Exemple de log :
SLY ► IN requestId=abc-123 POST /fiscal/api/v1/fiscal/certify ip=10.0.1.5 tenant=supergest-dakar
SLY ✓ ROUTE requestId=abc-123 POST /fiscal/api/v1/fiscal/certify → routeId=fiscal backend=http://fiscal-service:8080/api/v1/fiscal/certify
SLY ◄ END requestId=abc-123 type=INTERNAL source=supergest tenant=supergest-dakar route=fiscal backend=fiscal-service POST /fiscal/api/v1/fiscal/certify status=200 42ms signal=onComplete
Signature de transit — preuve que la requête vient de SLY
Problème résolu : sans mécanisme, rien n'empêchait une app malicieuse de forger X-Source-App: supergest et d'appeler FISCAL directement, en contournant SLY et ses contrôles.
Solution : SLY signe chaque requête qu'il transfère avec un HMAC-SHA256 calculé sur un secret partagé (SLY_FORWARD_SECRET). Les backends vérifient cette signature avant d'accepter la requête.
Algorithme
message = "<timestamp_ms>:<X-Request-Id>:<path>"
signature = HMAC-SHA256( SLY_FORWARD_SECRET, message )
SLY ajoute deux headers :
| Header | Valeur | Posé par | Vérifié par |
|---|---|---|---|
X-Sly-Timestamp |
epoch ms (ex. 1710345678123) |
SLY | SlyTransitFilter |
X-Sly-Signature |
hex HMAC-SHA256 | SLY | SlyTransitFilter |
Anti-replay
Le backend rejette toute requête dont X-Sly-Timestamp est > 30 secondes dans le passé (configurable via sly-signature-window-ms).
Intégration côté backend (FISCAL, BOOKS, TRACIUM…)
@Bean
FilterRegistrationBean<SlyTransitFilter> slyTransit(
@Value("${dynors.interapp.sly-forward-secret:}") String secret,
@Value("${dynors.interapp.sly-signature-window-ms:30000}") long windowMs) {
var filter = new SlyTransitFilter(secret, windowMs,
Set.of("/actuator/health", "/v3/api-docs", "/swagger-ui"));
var reg = new FilterRegistrationBean<>(filter);
reg.setOrder(Ordered.HIGHEST_PRECEDENCE + 10);
reg.addUrlPatterns("/api/*");
return reg;
}
SlyTransitFilter et SlyTransitValidator sont dans dynors-commons (module com.dynors.commons.interapp).
Configuration complète
dynors:
interapp:
source-app: <code-app>
gateway-url: ${SLY_BASE_URL:https://sly.dynors.com}
return-base-url: ${SLY_BASE_URL:https://sly.dynors.com}/<code-app>
cache-ttl-ms: 60000
sly-forward-secret: ${SLY_FORWARD_SECRET} # ← OBLIGATOIRE en production
sly-signature-window-ms: 30000
Variable d'environnement
SLY_FORWARD_SECRET: à définir comme variable CI/CD protégée et masquée dans GitLab pour chaque projet.
Développement local
En local, sly-forward-secret peut rester vide — SlyTransitFilter logue un avertissement mais laisse passer les requêtes. Ne jamais laisser vide en production.
Configurer une app pour passer par SLY
Dans application.yml de chaque app DYNORS :
dynors:
interapp:
source-app: <code-app>
gateway-url: ${SLY_BASE_URL:https://sly.dynors.com}
return-base-url: ${SLY_BASE_URL:https://sly.dynors.com}/<code-app>
cache-ttl-ms: 60000
sly-forward-secret: ${SLY_FORWARD_SECRET}
sly-signature-window-ms: ${SLY_SIGNATURE_WINDOW_MS:30000}
Voir routage-interapp.md pour la synthèse complète des flux et la matrice d'appels.
Références
- Spec complète :
docs/GATEWAY_SELEBEYONE_SLY.md - Flux et routage :
docs/SLY_FLUX_ET_ROUTAGE_COMPLET.md - Config par app :
docs/SLY_CONFIG_PAR_APP.md - Politique inter-app :
docs/POLITIQUE_ROUTAGE_ET_AUTH_INTERAPPLI.md