02 — API kontrakt mezi systémy
Přehled komunikačních kanálů
Folio CMS ──HTTP JSON──► REMP CRM (subscription sync, user sync, entitlement check)
Folio CMS ──HTTP form/json──► REMP Mailer (newsletter template handoff, job creation)
Folio CMS frontend ──JS (remplib)─► REMP Campaign (showtime, banner delivery)
REMP CRM ──Webhook──► Folio CMS (subscription state changes, optional)
Ecoidentita ──SSO / userinfo──► Folio CMS (authentication)
Ecoidentita ──identity sync──► REMP CRM (user provisioning)
A. Economia → REMP CRM API
Poznámka: Na rozdíl od sekcí Mailer/Campaign níže nemáme lokálně k dispozici zdrojový kód REMP CRM. Následující CRM endpointy jsou tedy pracovní návrh integračního kontraktu, který je potřeba potvrdit s FatChilli.
A1. User Provisioning
Po registraci / přihlášení uživatele přes Ecoidentita, Folio CMS musí zajistit existenci uživatele v REMP CRM.
Endpoint (volaný z Folio CMS):
POST /api/v1/users/register
Authorization: Bearer {crm_api_token}
Content-Type: application/json
{
"email": "user@example.com",
"ext_id": "ecoidentita_user_id_12345",
"source": "economia-cms",
"first_name": "Jan",
"last_name": "Novák",
"send_email": false,
"disable_email_validation": true
}
Response:
{
"status": "ok",
"user": {
"id": 42,
"email": "user@example.com",
"ext_id": "ecoidentita_user_id_12345"
}
}
Kdy se volá: Při prvním přihlášení uživatele přes Ecoidentita (pokud ještě neexistuje v CRM). Implementuje se jako after_sign_in callback nebo background job.
CMS třída: Economia::Remp::UserSyncService (nová)
Folio model: Folio::User → remp_user_id (nové pole)
A2. User Update
Endpoint:
PUT /api/v1/users/{remp_user_id}
Authorization: Bearer {crm_api_token}
{
"email": "new@example.com",
"first_name": "Jan",
"last_name": "Novák"
}
Kdy se volá: Při změně profilu uživatele v CMS (pokud CMS spravuje profil UI).
A3. Subscription Lifecycle (vlastní REMP CRM)
Důležité: Předplatné (subscription) vytváří, spravuje a ruší REMP CRM (FatChilli). CMS nevytváří subscriptions v CRM — místo toho se dotazuje na stav (viz A5 Entitlement Check) a přijímá webhooky (viz D1).
Typický flow:
- Čtenář přejde na checkout (REMP CRM UI nebo CRM API volaný z CMS frontendu)
- REMP CRM zpracuje platbu, vytvoří subscription
- REMP CRM notifikuje CMS webhookem (D1) → CMS invaliduje entitlement cache
- CMS ověřuje přístup přes A5 Entitlement Check
Self-care (zrušení, změna): Probíhá v REMP CRM — buď vlastní UI, nebo API volané z CMS frontendu. K vyjasnění s FatChilli.
A5. Entitlement Check (paywall)
Folio CMS volá při renderování článku s PaywallTag.
Endpoint:
GET /api/v1/users/{remp_user_id}/subscriptions?active=true
Authorization: Bearer {crm_api_token}
Response:
{
"status": "ok",
"subscriptions": [
{
"id": 789,
"subscription_type": {
"code": "hn_digital_monthly",
"content_access": ["web", "premium"]
},
"start_time": "2026-08-01T00:00:00+02:00",
"end_time": "2026-09-01T00:00:00+02:00"
}
]
}
Logika v CMS:
# Economia::Paywall::EntitlementChecker (nová třída)
class EntitlementChecker
def has_access?(user:, paywall_tag:)
return true unless paywall_tag.present?
return false unless user&.remp_user_id
subscriptions = Remp::CrmClient.active_subscriptions(user.remp_user_id)
subscriptions.any? do |sub|
sub.content_access.include?(paywall_tag.access_level)
end
end
end
Cachování: Výsledek cachovat v Redis s TTL 60-300s per user, aby se nevolalo CRM API při každém page load.
Alternativa: REMP CRM by mohl poskytnout jednodušší endpoint GET /api/v1/users/{id}/access?content_type=premium — záleží na CRM verzi.
A4. Subscription Type Configuration
Před integrací FatChilli nakonfiguruje subscription types v REMP CRM. CMS potřebuje znát kódy pro entitlement check.
Endpoint (admin/setup — volá FatChilli):
POST /api/v1/subscription-types
Authorization: Bearer {crm_api_token}
{
"code": "hn_digital_monthly",
"name": "HN Digital – měsíční",
"length": 31,
"content_access": ["web", "premium"],
"active": true
}
Mapování (REMP CRM definuje produkty, CMS zná kódy pro paywall):
| REMP CRM produkt | Subscription Type Code | Content Access |
|---|---|---|
| HN Digital – měsíční | hn_digital_monthly | ["web", "premium"] |
| HN Digital – roční | hn_digital_yearly | ["web", "premium"] |
| HN Print + Digital | hn_print_digital_monthly | ["web", "premium", "print"] |
| HN Premium | hn_premium_monthly | ["web", "premium", "archive"] |
B. Folio CMS → REMP Mailer API
Scope boundary: CMS v této integraci připravuje newsletterový obsah a předává ho do REMP Maileru. Reader subscriptions, user registration events, transactional reader e-maily, mail types a delivery ownership zůstávají na straně REMP/FatChilli.
B1. Newsletter Template Handoff
CMS vytvoří nebo zaktualizuje template v REMP Maileru z obsahu připraveného v editoru Folio.
Endpoint:
POST /api/v1/mailers/templates
Authorization: Bearer {mailer_api_token}
Content-Type: application/x-www-form-urlencoded
name=HN%20Denni%20prehled%20-%202026-08-01&
code=hn_daily_digest_20260801&
description=Generated%20by%20Folio%20CMS&
mail_type_code=hn_daily_digest&
mail_layout_code=hn_newsletter_layout&
subject=HN%20Denni%20prehled&
template_text=...&
template_html=...&
preheader=To%20nejdulezitejsi%20za%20dnesek
Poznámky z reálného remp kódu:
- Handler přijímá form data, ne JSON
mail_type_codemusí v Maileru existovat- Template musí mít
mail_layout_idnebomail_layout_code codeje v Maileru deduplikován na unikátní hodnotu
Relevantní Mailer handler: MailCreateTemplateHandler
B2. Stored Template Preview
REMP umí vyrenderovat již uložený template podle code.
Endpoint:
GET /api/v1/mailers/render-template?code=hn_daily_digest_20260801
Authorization: Bearer {mailer_api_token}
Důležité omezení: RenderTemplateApiHandler renderuje uložený template podle code; není to endpoint pro preview libovolného draft HTML. Draft preview je potřeba primárně řešit lokálně v CMS a/nebo až po uložení template do Maileru.
Relevantní Mailer handler: RenderTemplateApiHandler
B3. Newsletter Job Creation
Po předání template CMS vytvoří job, který REMP Mailer odešle na REMP-spravovaný segment / subscriber base.
Doporučený endpoint:
POST /api/v2/mailers/jobs
Authorization: Bearer {mailer_api_token}
Content-Type: application/json
{
"template_code": "hn_daily_digest_20260801",
"include_segments": [
{
"provider": "crm-segment",
"code": "all_hn_digital"
}
],
"context": "daily_digest_2026_08_01",
"start_at": "2026-08-01T06:00:00Z"
}
Poznámky z reálného remp kódu:
- v1 endpoint používá
template_id,segment_code,segment_provider - v2 endpoint používá
template_code,include_segments[],exclude_segments[] - Mailer používá aliasy providerů
crm-segment,remp-segment,mailer-segment
Relevantní Mailer handler: MailJobCreateApiHandler
CMS třída: Economia::Remp::NewsletterComposerService (nová)
B4. Reader E-mail Flows V REMP
Tyto endpointy v aktuálním remp existují, ale nejsou součástí CMS integračního kontraktu. Patří do reader části spravované v REMP/FatChilli:
POST /api/v1/users/user-registeredPOST /api/v1/users/subscribePOST /api/v1/users/un-subscribePOST /api/v1/users/user-preferencesPOST /api/v1/mailers/send-emailPOST /api/v1/mailers/mail-type-upsert
C. REMP Campaign ← Folio Frontend
C1. Showtime (banner delivery)
Na frontendu Folio CMS se načte remplib.js, který komunikuje s Campaign:
<!-- V layoutu Folio CMS -->
<script src="https://campaign.remp.economia.cz/assets/lib/js/remplib.js"></script>
<script>
var rempConfig = {
userId: "<%= current_user&.remp_user_id %>",
userSubscribed: <%= current_user_subscribed? %>,
cookieDomain: ".hn.cz",
campaign: {
url: "https://campaign.remp.economia.cz",
variables: {
article_id: {
value: function () { return "<%= @article.id %>" }
},
content_type: {
value: function () { return "<%= @article.content_type %>" }
}
},
pageviewAttributes: {
section: "<%= @article.primary_category&.slug %>",
content_type: "<%= @article.content_type %>"
}
}
};
remplib.campaign.init(rempConfig);
</script>
Campaign interně:
- Vyhodnotí segmenty (přes segment provider → CRM nebo Beam)
- Vrátí banner config pro showtime
C2. Campaign API (admin)
Vytváření a správa kampaní přes API (pro automatizaci z CMS):
POST /api/campaigns
Authorization: Bearer {campaign_api_token}
GET /api/campaigns
GET /api/banners
POST /api/schedule/{id}/start
POST /api/schedule/{id}/pause
Relevantní Campaign routes: Campaign/extensions/campaign-module/routes/api.php
Route::apiResource('campaigns', CampaignController::class)Route::apiResource('banners', BannerController::class)Route::apiResource('schedule', ScheduleController::class)
D. REMP → Economia (webhooky, volitelné)
D1. Subscription State Change Webhook
REMP CRM může notifikovat Folio CMS o změnách (pro cache invalidation):
POST https://hn.cz/api/internal/remp/webhooks/subscription-changed
X-REMP-Signature: {hmac_sha256}
{
"event": "subscription.updated",
"user_id": 42,
"subscription_id": 789,
"subscription_type_code": "hn_digital_monthly",
"status": "expired",
"timestamp": "2026-09-01T00:00:01+02:00"
}
CMS třída: Api::Internal::Remp::WebhooksController (nová)
Akce: Invalidace entitlement cache, update lokálního stavu
E. Autentizace API komunikace
| Směr | Mechanismus | Správa tokenů |
|---|---|---|
| CMS → REMP CRM | Bearer token (REMP CRM API token) | Generován v REMP CRM admin |
| CMS → REMP Mailer | Bearer token (Mailer API token) | Konfigurace v Mailer .env |
| CMS → REMP Campaign | Bearer token (Campaign API token) | Konfigurace v Campaign .env |
| REMP → CMS webhook | HMAC-SHA256 signature | Sdílený secret v konfiguraci obou systémů |
| Frontend → Campaign | Veřejný showtime request přes remplib.js | Bez write tokenu; případný top-level rempConfig.token je Beam property token, ne Campaign admin token |
| Čtenář → CMS | EGO-SSO session / cookies | Session cookie na doméně |
F. Nové třídy a služby v Economia CMS
| Třída / Modul | Odpovědnost |
|---|---|
Economia::Remp::CrmClient | HTTP klient pro REMP CRM API |
Economia::Remp::MailerClient | HTTP klient pro REMP Mailer API |
Economia::Remp::CampaignClient | HTTP klient pro REMP Campaign API (admin) |
Economia::Remp::UserSyncService | Synchronizace uživatelů Folio → CRM |
Economia::Remp::NewsletterComposerService | Render newsletter obsahu v CMS a handoff template/jobu do Maileru |
Economia::Paywall::EntitlementChecker | Ověření přístupu uživatele k obsahu |
Economia::Remp::EntitlementCache | Redis cache pro entitlement data z CRM |
Economia::Remp::SyncUserJob | Sidekiq job pro async user sync |
Api::Internal::Remp::WebhooksController | Příjem webhooků z REMP CRM (cache invalidation) |
Economia::Remp::Configuration | Rails config/initializer s URL/tokeny |
G. Konfigurace (Environment Variables)
# REMP CRM
REMP_CRM_URL=https://crm.remp.economia.cz
REMP_CRM_API_TOKEN=xxxxxxxx
# REMP Mailer
REMP_MAILER_URL=https://mailer.remp.economia.cz
REMP_MAILER_API_TOKEN=xxxxxxxx
# REMP Campaign
REMP_CAMPAIGN_URL=https://campaign.remp.economia.cz
REMP_CAMPAIGN_API_TOKEN=xxxxxxxx
# Webhook
REMP_WEBHOOK_SECRET=xxxxxxxx
# Entitlement cache
REMP_ENTITLEMENT_CACHE_TTL=120