03 — Implementační plán
Předpoklady
- Start: 21. července 2026
- Délka sprintu: 3 týdny
- Fáze 1 nezahrnuje Beam tracking
- REMP CRM, Mailer, Campaign a SSO jsou nasazeny a přístupné (produkční nebo staging prostředí)
- Ecoidentita SSO redirect + userinfo flow je funkční alespoň ve staging
- REMP CRM je SoT pro produkty, předplatné a platby (FatChilli)
Fáze přehled
| Fáze | Sprint | Název | Cíl |
|---|---|---|---|
| 0 | S1 | Infrastructure & Foundations | REMP klienty, config, CI, dev prostředí |
| 1 | S1–S2 | Identity & User Sync | Ecoidentita → Folio → REMP CRM user provisioning |
| 2 | S2–S3 | Entitlement & Paywall Cache | Entitlement check z CRM, cache, webhook handling |
| 3 | S3–S4 | Paywall UI & Content Locking | Frontend paywall rendering, PaywallTag → entitlement |
| 4 | S4–S5 | Campaign Integration | remplib.js, showtime, segment-based banners |
| 5 | S5–S6 | Mailer Integration | Newsletter authoring handoff, Mailer jobs, digest assembly |
| 6 | S6–S7 | E2E Testing & Hardening | Integration tests, monitoring, SLA, go-live prep |
Detailní plán
Fáze 0: Infrastructure & Foundations (Sprint 1: 21.7.–8.8.)
0.1 REMP Client Library
Cíl: Vytvořit Ruby gem / Rails engine modul pro komunikaci s REMP API.
Implementace:
Economia::Remp::CrmClient— HTTP klient (Faraday) pro REMP CRM APIEconomia::Remp::MailerClient— HTTP klient pro REMP Mailer APIEconomia::Remp::CampaignClient— HTTP klient pro Campaign APIEconomia::Remp::Configuration— Rails initializer, env vars- Error handling, retry logic, circuit breaker (optional)
- Request/response logging
Třída:
# app/services/economia/remp/crm_client.rb
module Economia::Remp
class CrmClient
include ActiveSupport::Configurable
config_accessor :base_url, :api_token, :timeout
def initialize
@connection = Faraday.new(url: base_url) do |f|
f.request :json
f.response :json
f.request :authorization, 'Bearer', api_token
f.adapter Faraday.default_adapter
end
end
def find_user(remp_user_id)
@connection.get("/api/v1/users/#{remp_user_id}")
end
def register_user(email:, ext_id:, **attrs)
@connection.post("/api/v1/users/register", {
email: email, ext_id: ext_id, **attrs
})
end
def active_subscriptions(remp_user_id)
@connection.get("/api/v1/users/#{remp_user_id}/subscriptions", active: true)
end
end
end
Story points: 5 SP Endpoints: Interní (žádné REMP API — jde o klientský kód)
0.2 Development Environment
Cíl: Docker compose nebo přístup k REMP staging.
Implementace:
- Docker compose pro lokální REMP stack (SSO, Mailer, Campaign, CRM)
- Nebo: VPN přístup + staging tokeny
- Seed data pro subscription types, mail types, test uživatele
- CI pipeline step pro integration testy
Story points: 3 SP
0.3 Database Migrations
Cíl: Přidat REMP-specifická pole do CMS modelů.
# Migration
add_column :folio_users, :remp_user_id, :integer, index: true
add_column :folio_users, :remp_synced_at, :datetime
# CMS nemá subscription model — subscriptions řeší REMP CRM
Story points: 2 SP
Fáze 1: Identity & User Sync (Sprint 1–2: 21.7.–29.8.)
1.1 User Sync on Login
Cíl: Při přihlášení přes Ecoidentita vytvořit / nalinkovat uživatele v REMP CRM.
Implementace:
Economia::Remp::UserSyncService#sync!(folio_user)- Volá REMP CRM
POST /api/v1/users/registerneboPUT /api/v1/users/{id} - Ukládá
remp_user_iddoFolio::User - Background job
Economia::Remp::SyncUserJobpro async processing - Deduplikace na základě
ext_id(Ecoidentita user ID)
Integrace v Folio:
# V OmniAuth callback controlleru (Ecoidentita)
after_action :sync_to_remp, only: [:create]
def sync_to_remp
Economia::Remp::SyncUserJob.perform_later(current_user.id)
end
REMP CRM endpoint: POST /api/v1/users/register
REMP CRM handler: Users module — user registration
Story points: 5 SP
1.2 User Update Sync
Cíl: Při změně profilu (CMS self-care) aktualizovat REMP CRM.
Implementace:
- ActiveRecord callback na
Folio::User→ async job - Volá
PUT /api/v1/users/{remp_user_id} - Sync polí: email, first_name, last_name
Story points: 3 SP
1.3 Bulk User Import (Initial Migration)
Cíl: Jednorázový import existujících uživatelů z Folio/legacy do REMP CRM.
Implementace:
- Rake task
economia:remp:import_users - Batched processing (1000 users per batch)
- Volá
POST /api/v1/users/register(nebo bulk endpoint pokud existuje) - Logging a error reporting
REMP Mailer endpoint: POST /api/v1/users/bulk-user-registered
Story points: 3 SP
Fáze 2: Entitlement & Paywall Cache (Sprint 2–3: 11.8.–19.9.)
2.1 Subscription Type Mapping (konfigurace)
Cíl: CMS musí znát kódy REMP CRM subscription types pro vyhodnocení paywallu.
Implementace:
- Config/YAML file s mapováním content_access → PaywallTag
- FatChilli vytváří subscription types v REMP CRM
- CMS jen čte kódy pro entitlement matching
# config/remp_subscription_types.yml
# Mapování REMP CRM subscription types na PaywallTag access levels
hn_digital_monthly:
content_access: ["web", "premium"]
hn_digital_yearly:
content_access: ["web", "premium"]
hn_print_digital_monthly:
content_access: ["web", "premium", "print"]
Story points: 2 SP
2.2 Entitlement Cache Service
Cíl: CMS cachuje entitlement data z REMP CRM pro rychlé vyhodnocení paywallu.
Implementace:
Economia::Remp::EntitlementCache— Redis cache per user- Dotazuje REMP CRM
GET /api/v1/users/{id}/subscriptions?active=true - Cache invalidation přes webhook z CRM (viz 2.4)
- TTL z konfigurace (doporučeno 60–300s)
- Fallback při nedostupnosti CRM → degraded mode (článek zamknutý)
REMP CRM endpoint: GET /api/v1/users/{id}/subscriptions
Story points: 5 SP
2.3 Entitlement Check Service
Cíl: Folio CMS může ověřit, zda uživatel má přístup ke článku s PaywallTag.
Implementace:
Economia::Paywall::EntitlementChecker#has_access?(user:, paywall_tag:)- Volá
GET /api/v1/users/{remp_user_id}/subscriptions?active=true - Cachuje výsledek v Redis (TTL z konfigurace)
- Fallback: při nedostupnosti CRM → degraded mode (článek zamknutý)
REMP CRM endpoint: GET /api/v1/users/{id}/subscriptions
Story points: 5 SP
2.4 Webhook Receiver
Cíl: CMS přijímá webhooky z REMP CRM o změnách subscription stavu.
Implementace:
Api::Internal::Remp::WebhooksController- HMAC-SHA256 verifikace
- Invalidace entitlement cache
- Event logging
Story points: 3 SP
Fáze 3: Paywall UI & Content Locking (Sprint 3–4: 1.9.–10.10.)
3.1 Server-Side Paywall Rendering
Cíl: Články s PaywallTag se renderují jako zamknuté pro neautorizované uživatele.
Implementace:
- V article show controlleru: volání
EntitlementChecker - Dva rendery: plný obsah vs. truncated + paywall lock
- ViewComponent
Economia::Article::PaywallLockComponent - Stimulus controller pro interaktivní paywall UI
Folio třídy:
Economia::ArticlesController#show— rozšířeníEconomia::Article::PaywallTag— existující modelEconomia::Article::PaywallLockComponent— nový ViewComponent
Story points: 8 SP
3.2 Paywall Variants
Cíl: Různé typy paywall lock UI podle kontextu (hard wall, metered, freemium).
Implementace:
- PaywallTag.access_level → typ paywallu
- Konfigurovatelné limity (metered: X článků zdarma)
- Cookie/localStorage pro metered counting
- CTA varianty (subscribe, login, trial)
Story points: 5 SP
3.3 Subscriber Content Indicators
Cíl: V listing stránkách (rubrika, homepage) zobrazit ikonu/badge pro premium obsah.
Implementace:
- Helper
paywall_badge(article)→ renders badge - CSS styling pro premium content markers
- Článek v listingu neodhaluje obsah
Story points: 2 SP
Fáze 4: Campaign Integration (Sprint 4–5: 13.10.–21.11.)
4.1 remplib.js Integration
Cíl: Na všech stránkách Folio CMS načíst remplib.js pro showtime.
Implementace:
- Partial
_remp_campaign.html.slimv layoutu - Konfigurace campaign token, URL
- Předání proměnných z CMS (article_id, section, is_subscriber…)
- Podmíněné načítání (ne na admin, ne na error pages)
Story points: 3 SP
4.2 Segment Provider Configuration
Cíl: Campaign musí vědět, odkud čerpat segmenty.
Implementace:
- Konfigurace v Campaign admin: přidat CRM segment provider
- Nebo: Beam segment provider (pokud Beam bude v budoucnu)
- Mapování segmentů na kampaně
Story points: 2 SP
4.3 Campaign Templates for Paywall Upsell
Cíl: Vytvořit šablony bannerů pro paywall upsell, trial nabídku, login prompt.
Implementace:
- HTML/CSS banner šablony v Campaign admin
- A/B test varianty
- Cílení: anonymous users, registered-non-subscribers, expired subscribers
Story points: 5 SP
4.4 Segment Cache Integration
Cíl: Real-time aktualizace segment cache pro cílení.
REMP Campaign endpoints:
POST /api/segment-cache/provider/{provider}/code/{code}/add-userPOST /api/segment-cache/provider/{provider}/code/{code}/remove-user
Implementace:
- Při subscription change: add/remove user z segmentu “active_subscribers”
- Background job z CMS
Story points: 3 SP
Fáze 5: Mailer Integration (Sprint 5–6: 24.11.–2.1.2027)
5.1 Mail Type Setup
Cíl: CMS zná, které existující mail_type_code v REMP Maileru se používají pro jednotlivé newsletterové use-cases.
Implementace:
- Konfigurace / lookup tabulka
newsletter type → mail_type_code - Admin select pro přiřazení existujícího
mail_type_code - Koordinace s FatChilli nad provisioningem mail types v REMP
- CMS nevlastní reader subscriptions ani Mailer mail type admin
Story points: 3 SP
5.2 Newsletter Content Authoring UI
Cíl: Redaktor připraví newsletter po obsahové stránce v CMS.
Implementace:
- Editor / výběr článků / média / preheader / subject
- Draft/publish workflow v CMS
- Lokální preview email-safe HTML výstupu
- Reader subscription management zůstává mimo CMS v REMP
Story points: 5 SP
5.3 Newsletter Template Handoff & Job Creation
Cíl: CMS předá připravený newsletter do REMP Maileru k rozeslání.
Implementace:
POST /api/v1/mailers/templatespro vytvoření / update templateGET /api/v1/mailers/render-template?code=...pro kontrolu uloženého templatePOST /api/v2/mailers/jobspro vytvoření odesílacího jobu- Uložení
template_code/job_id/contextdo CMS pro audit a dohledatelnost
REMP Mailer handlers: MailCreateTemplateHandler, RenderTemplateApiHandler, MailJobCreateApiHandler
CMS třída: Economia::Remp::NewsletterComposerService
Story points: 8 SP
5.4 Mailer Handoff Hardening
Cíl: Předání newsletteru z CMS do Maileru je bezpečné, idempotentní a dobře operovatelné.
Implementace:
- Stabilní naming a versioning
template_code/context - Retry strategie, chybové stavy a audit log
- Monitoring / alerting na Mailer API handoff
- Reader transactional emails zůstávají mimo CMS v REMP / EGO-SSO
Story points: 5 SP
5.5 Author/Section Digest Content Assembly
Cíl: CMS umí automaticky sestavit content pro digest-type newslettery, ale delivery i subscriptions zůstávají v REMP.
Implementace:
- Sidekiq scheduled job:
Economia::Remp::AuthorDigestJob - Sbírá články publikované za poslední týden per autor / rubriku
- Vyrenderuje newsletter content stejně jako manuální flow
- Předá template + job do Maileru přes stejný handoff jako v 5.3
- Recipient list / segment ownership zůstává v REMP
Story points: 5 SP
Fáze 6: E2E Testing & Hardening (Sprint 6–7: 5.1.–13.2.2027)
6.1 Integration Tests
Cíl: End-to-end testy celého flow.
Implementace:
- System tests (Capybara): login → paywall → subscribe → unlock
- API tests: mock REMP responses, verify request format
- VCR cassettes / WebMock pro unit testy
- CI pipeline s REMP staging
Story points: 8 SP
6.2 Monitoring & Alerting
Cíl: Monitoring API komunikace, error rates, latency.
Implementace:
- ActiveSupport::Notifications instrumentace
- Grafana dashboard pro REMP API calls
- Sentry error tracking pro sync failures
- Dead letter queue pro failed sync jobs
Story points: 3 SP
6.3 Documentation & Runbook
Cíl: Provozní dokumentace, troubleshooting guide.
Implementace:
- Runbook pro časté problémy (sync failure, cache stale, API down)
- SLA definice: kdo řeší co, escalation path
- API dokumentace (OpenAPI/Swagger)
Story points: 3 SP
6.4 Performance Optimization
Cíl: Optimalizace pro produkční zátěž.
Implementace:
- Load testing entitlement check endpoint
- Redis cache tuning
- Connection pooling pro REMP API calls
- Rate limiting pro webhook receiver
Story points: 3 SP
Časová osa (Gantt)
Sprint 1 (21.7.–8.8.) ████ Fáze 0 (Infrastructure) + Fáze 1a (User Sync Login)
Sprint 2 (11.8.–29.8.) ████ Fáze 1b (User Import) + Fáze 2a (Sub Type Mapping, Sub Sync)
Sprint 3 (1.9.–19.9.) ████ Fáze 2b (Entitlement, Webhooks) + Fáze 3a (Paywall Rendering)
Sprint 4 (22.9.–10.10.) ████ Fáze 3b (Paywall Variants, Badges) + Fáze 4a (remplib, Segments)
Sprint 5 (13.10.–31.10.) ████ Fáze 4b (Campaign Templates, Cache) + Fáze 5a (Mail Types, NL UI)
Sprint 6 (3.11.–21.11.) ████ Fáze 5b (NL Job, Transactional, Digest)
Sprint 7 (24.11.–12.12.) ████ Fáze 6 (E2E Tests, Monitoring, Docs, Perf)
Buffer (15.12.–2.1.2027) ░░░░ Bug fixes, go-live prep, UAT
Celkem: 7 sprintů = 21 týdnů = ~5 měsíců (21.7.2026 – 12.12.2026) + buffer
Závislosti a rizika
| Závislost | Vlastník | Riziko |
|---|---|---|
| REMP CRM nasazení a API přístup | Economia / FatChilli | Bez staging CRM nelze začít fázi 1 |
| Ecoidentita SSO fungující | Economia | Bez Ecoidentita nelze testovat user sync |
| REMP CRM subscription types definice | Economia + FatChilli | CMS potřebuje znát kódy pro entitlement check |
| Checkout flow rozhodnutí | Economia + FatChilli | CRM UI vs. CMS frontend + CRM API |
| Newsletter šablony a content strategy | Economia (redakce) | Nelze implementovat mailer bez šablon |
| PaywallTag implementace (Epic 01b) | Sinfin | Musí být hotový před fází 3 |