What we changed in each release of SISL Time Machine — no rounded marketing phrases, just file names, class names, SQL columns and endpoints.
password_hash, rp_token, confirmation and login-throttle counters are hard-blacklisted in DeltaExtractor — customer audit must never become a credential leak.
catalog_category_save_after observer now records name / status / parent / url_key / position changes. This is where expensive mistakes hide: someone disables a category or reparents the tree and the shop silently loses a whole navigation section.
CategoryRepository->save() — full plugin chain + audit-of-audit (the revert itself is recorded as a rollback-sourced event).
/metrics endpoint in Prometheus/OpenMetrics format: events_ingested_total{entity_type,source}, rollbacks/replays/timelines, build_info, uptime. Zero extra dependencies — the service stays a single self-contained binary.
/health/deep endpoint — full write→read→verify→delete transaction + partition count. Green = "this instance can actually ingest", not just "PG answers SELECT 1". Kubernetes/Swarm pulls a half-broken instance instead of silently dropping events.
LOG_FORMAT=json) — single-line, ready for ELK / Splunk / Loki. Human-readable format stays the default for dev.
EventContextResolver trait — shared who/where-from logic for product + category observers (ProductSaveAfter slimmed from ~200 to ~75 lines). .NET test suite: 274 green (+17 for MetricsCollector, incl. hostile-label sanitisation and a 1000-thread losslessness test).
license.sisl.pl/check (Traefik adds the prefix → backend /api/licenses/check). The old default sisl.pl/api/licenses/check plus the /api/licenses/check path double-prefixed to a 404. Aligned with Optima Connector.
obscure (Encrypted backend) — Magento decrypts it on read, but the Helper called decrypt() again, turning the key into binary garbage (json_encode crash: “Malformed UTF-8”). Removed — we now read the value directly, like Sisl_Optima.
https://license.sisl.pl (config.xml + Helper). Verified e2e against the live server: valid:true, Ed25519 verified:true.
rollback, HMAC, REST API, Tenant ID, base64, event) kept because Magento admins expect them.
admin_ui → “Panel admina”, cli → “CLI / skrypt”, cron → “Zadanie cykliczne (cron)”, unknown → “Nieznane”.
system.xml: numbered subgroups (“1. Ogólne”, “2. Połączenie z usługą”, “3. Zakres przechwytywania”), all field labels + comments in Polish. “coming soon” → “dostępne wkrótce”.
GET /api/v1/analytics/overview?tenant=X&days=30&topN=10 endpoint in the .NET service. Five SQL aggregations in one round-trip — existing indexes (events_entity_lookup, events_actor_recent, events_source_recent) cover every query.
sisl_changelog_lite in MySQL, no microservice, no rollback. Built-in upgrade CTA → Time Machine PRO. Top-of-funnel lead generation.
SISL-TMC-XXXX-XXXX-XXXX-XXXX. Without a valid key, events are not sent to the .NET service and rollback is blocked.
sisl_timemachine_check_license at 03:00 refreshes the verdict — inline <schedule> in crontab.xml so it registers on a fresh install with no admin intervention.
EventSender::send does a silent skip + log warning (capture quietly waits for reactivation), Rollbacker::rollbackProduct throws RollbackException even for dry-run — the admin UI gets HTTP 409 with a readable message.
rollback, and the rollback itself can be reverted later just like any other change.
RollbackAction.php already returned the full plan (sku, as_of, events_replayed, changes_planned). This is purely the presentation layer in timeline.phtml.
from → to. Green now badge = this change is still in effect, amber = a later event overwrote the field.
Timeline.php controller loads the product once, snapshots values, hands them to the block as current_values. No per-event repository call.
events.source column in PG: admin_ui / rest_api / rollback / cron / cli / unknown. Migration 002 is idempotent and auto-loaded via docker-entrypoint-initdb.
admin:42.
RollbackContext singleton — Rollbacker tags its own saves so the observer knows it's not a regular admin edit.
RollbackContext > area code crontab > URL /rest/|/soap/|/graphql > admin session > PHP_SAPI cli > unknown. Order matters — a rollback always happens inside an admin session.
sisl/timemachine-service:0.5.0.
deploy/ directory: docker-compose.yml, .env.example, migrations/, INSTALL.md. cp .env.example .env && docker compose up -d and you're live.
INSTALL.md covers Linux Docker, Windows Server (Docker Desktop) and native Windows (Windows Service + EDB PostgreSQL).
openssl rand -base64 32) or compose refuses to start.
.env.
/admin/sisl_timemachine/product/timeline page rendering per-product event history + AJAX rollback flow with dry-run preview.
Sisl_TimeMachine::timemachine_admin.
from → to diff, status pill per event, JS confirmation flow before apply.
Rollbacker reconstructs entity state at time T (via the .NET replay) and applies it through ProductRepository->save() — every plugin / validator / observer fires.
from values of the first diff.
GET /api/v1/replay/{type}/{id}?at=ISO — pure replay, applies events in order, returns the reconstructed field state at the given moment.
GET /api/v1/timeline/{type}/{id} — raw event list newest-first, with pagination.
catalog_product_save_after observer + DeltaExtractor (per-attribute diff, internal-field blacklist, from: null skip on existing entities).
/health + POST /api/v1/events. HMAC-SHA256 middleware (constant-time MAC + ±60s clock skew).
events table with monthly partitions, GIN index over the JSONB delta, dedup table for idempotency.
event_ids table — a partitioned UNIQUE would have to include the partition key (which breaks dedup). Claim happens via a CTE INSERT … ON CONFLICT DO NOTHING.
The roadmap shows what we're building in v0.8 (multi-entity capture), v0.9 (snapshots + bulk rollback) and v1.0 (public launch Q3 2026). Every major-version upgrade is included in the subscription.