# Changelog All notable changes to rsync.ai are documented in this file. ## [0.1.8] - 2026-10-02 Everything since v0.1.7. ### โš–๏ธ License #### Changed - **New license from the first release that includes it: the rsync.ai Source-Available License v1.0** (`LICENSE`), replacing the Elastic License 2.0. Running rsync.ai for your own business, and for personal or non-commercial projects, stays free. Without a separate agreement you may no longer sell it, host it for others, embed it in a product you sell, build a competing product from it, or share copies except free of charge for non-commercial purposes. Releases up to and including v0.1.7 stay under the Elastic License 2.0; its text is kept in `LICENSES/`. - **Contributions now need a signed [CLA](CLA.md)**, once, in addition to the DCO sign-off. - **Every connector's `license` field now carries the new license's identifier**, not `MIT` or `ELv2`. The field had defaulted to `MIT` for connectors rsync.ai wrote itself. The identifier is `LicenseRef-rsync.ai-SAL-1.0`. ### ๐Ÿท๏ธ Named rsync.ai, not rsync rsync is also the name of a file-copy tool that has existed for decades. The product is rsync.ai, and the names below now say so. #### Changed - **The repository is `github.com/rsync-ai/rsync.ai`.** The install command is `curl -sSL https://raw.githubusercontent.com/rsync-ai/rsync.ai/main/install.sh | bash`, and a clone lands in `rsync.ai/`. GitHub redirects the old web and git addresses. - **Kubernetes: the default release and namespace are `rsync-ai`**, so resources are named `rsync-ai-frontend`, `rsync-ai-secrets` and so on. `install-k8s.sh` finds an install under the old default (`rsync` in `rsync`) and upgrades it in place. If you run `helm` yourself, keep upgrading under the name you installed with. - **Docker: the self-host containers are named `rsync-ai-*`** (`rsync-ai-postgres`, `rsync-ai-orchestrator`, ...). Your data is in volumes, which keep their names; the next `up` replaces each container under its new name. Scripts that call `docker exec` or `docker logs` with an old name need the new one. - **AI clients: the setup snippets name the MCP server `rsync-ai`**, and the server reports `rsync.ai` as its title. A client you already set up keeps working under the name you gave it. - **Load test: `RSYNC_AI_EMAIL` and `RSYNC_AI_PASSWORD`** replace `RSYNC_EMAIL` and `RSYNC_PASSWORD` in `scripts/loadtest`. The rsync tool reads `RSYNC_PASSWORD` too. ### Removed - **The `petstore` example connector**, a demo of a generated REST connector. ## [0.1.7] - 2026-09-28 Everything since v0.1.6. ### Batch pipelines - A Reload onto object storage (GCS, S3, Azure Blob, MinIO) fails the run when the old files could not all be deleted, instead of loading on top of them. - A resumed run continues a table from where that table's own sweep stopped, and a table whose row count is an exact multiple of the page size records that it finished. - A MongoDB collection whose `_id` mixes types gets one column type per run. - A run completes only after its post-run row check passes; a failed check fails the run. The next run re-sends batches the destination refused in an earlier run. - Stop also stops the pipeline's sink worker. - The sink connector runs on every install, Helm with `connectors.cdc.enabled=false` included, and a batch pipeline with a destination checks for it before it starts. - When MinIO is down, a run stops staging through it after the first failure instead of retrying on every batch. - The `STRICT_PREFLIGHT` setting is removed. It had no effect; the run gate already blocks on error findings. ### Change data capture - **Behaviour change:** a keyless table into a PostgreSQL, MySQL or MongoDB destination is a warning, not a blocker. On such a table an UPDATE adds a row and a DELETE is dead-lettered. - The sink upserts only on a declared key, from the source's message key or the destination config, never on a guessed `id` column that could merge distinct rows. - Keyless MongoDB rows are keyed on their Kafka record, so a replay does not duplicate them, and MongoDB changes within the same second keep their order. - MySQL destination key columns are created indexable (`VARCHAR`), so an upsert matches its row instead of inserting it again on every replay. - A Reload sends its re-snapshot only once the connector reports it is running. - A destination that refuses the sink's credentials stops the pipeline as needing configuration instead of retrying. - Removing a table from a SQL Server pipeline deletes its topic, and the sink no longer creates phantom topics when it restarts after an edit. - CDC lag is reported in messages, from the newest reading. ### Sink - A worker holding rows through a destination outage is no longer restarted as stalled. - The first destination host that answers is final: a refused write is not sent again under another name for the same service, and on Helm the destination's real error is no longer replaced by a `no such host`. - Layout v2 object files are always Parquet. A connection saved with format `infer`, the GCS and Azure Blob form default, used to get gzip JSON under a `.parquet` name. ### Connectors - A database inside the same Kubernetes cluster (`*.svc`, `*.cluster.local`) gets TLS off by default, like a Docker service name, so an in-cluster MongoDB or PostgreSQL connects from host, port, user and password without a connection string. An explicit TLS or `sslmode` setting still wins. - Generate a connector from an OpenAPI document in the UI: upload a file, paste it, or give a URL, which your browser fetches, not the server. - A generated connector deploys: its files are saved readable by the orchestrator, and it is deployed from its saved version. - An upgrade runs the new release's connector code. The `connector-seed` image replaces each shipped connector version and keeps generated connectors, and a connector container is rebuilt when its code changed, not only when its version tag did. ### Interface - Pipeline pages say only what they measured: a stage is marked done on its own evidence, a CDC header reads "Setting up" during a Reload, the header's row count and step agree with the table statistics and the timeline, and a status change shows within seconds. - Table statistics refresh while a run is going and take a final reading when it ends. CDC health reads the current run's probe. - The batch Checkpoints card stays readable with many tables: a summary line, a filter and search, and one compact row per table. It counts every table of the latest run. - Stop closes the actions menu, and a CDC pipeline no longer sticks at "Failed" after Stop and Resume. - A keyless CDC table shows one "Table primary key" check, not two. - Chat resolves a saved connection by its name, such as "Demo warehouse". - The `/chat` heading reads "Data Pipeline". ### Self-hosting - Blob passthrough stages through its own `blob-staging` MinIO, which connectors can reach; the platform MinIO stays off the connector network. Re-running `install.sh` on an existing install adds its keys. - The orchestrator waits for the database migrations before its boot queries. - A Postgres, Kafka or Kafka Connect that is still starting no longer raises a CRITICAL alert. - LLM cost logging works: llm-service gets `DATABASE_URL`. - The first-run demo seed works: `demo-warehouse` joins the connector network. - `install.sh` installs from a checkout (`RSYNC_COMPOSE_DIR`, with an explicit `RSYNC_VERSION`) or pulls images from a mirror (`RSYNC_IMAGE_REGISTRY`). ### Kubernetes - The chart ships a dedicated `blob-staging` MinIO that only connector pods may reach under `networkPolicy.enabled`; `install-k8s.sh` generates its keys. - Generate refuses to save a connector, and says why, instead of reporting "Generated": each pod keeps its own copy of the connector catalog, so a generated connector would reach no other service. ## [0.1.6] - 2026-09-27 Everything since v0.1.5. ### Self-hosting - MinIO now pulls `cgr.dev/chainguard/minio`, pinned by digest, for both the server and the `mc` bucket/lifecycle job. MinIO stopped serving anonymous pulls from `docker.io/minio/*` and then from `quay.io/minio/*`, so a v0.1.5 install, `docker compose pull`, or a Helm install without registry credentials failed at MinIO. The compose MinIO server runs as root (`user: "0:0"`) so a volume written by v0.1.5 stays writable. Helm chart 0.1.5 and older name the withdrawn images: set `objectStorage.minio.image` and `objectStorage.minio.mcImage` as shown in [docs/deployment/kubernetes.md](docs/deployment/kubernetes.md). ### First-run demo - "Start with sample data" now reaches a pipeline confirmation with no language model configured. The chat knows the `sample-data` connector, reads "sample data" as the demo source only when no other connector is named ("copy my postgres sample data to s3" is still PostgreSQL โ†’ Amazon S3), and onboarding opens the chat with the request already sent. The chat home offers a "Sample data โ†’ Postgres" pipeline once both demo connections exist. - The first-run demo no longer fails with "Missing connector: sample-data". The connector check required every connector to subclass `BaseMCPConnector`; the self-contained `sample-data` connector does not, so the chat request stopped before planning. A top-level `MCPServer` class now counts too; stubs are still rejected. ### Kafka topics - **Breaking:** a default install provisions four platform topics โ€” `domain.events`, `rsync.notifications`, `pii.scan.request`, `pii.scan.response` โ€” instead of the 28 a fresh stack used to carry. The agent command bus (`rsync.agent.*`, `task.assignments`/`task.results`, `pipeline.agent.telemetry`, `sentinel.audit`, `healer.actions`) had no live producer or consumer and is removed, together with the planner's Kafka consumer (the planner is HTTP-only), `POST /api/v1/topology/topics/pipeline` and the `ENABLE_KAFKA_CONSUMER` setting. Topics an existing install already has are not deleted; per-pipeline topics go when their pipeline does. - `domain.events` keeps 7 days (`retention.ms=604800000`) instead of growing forever, so a projector rebuild or replay reaches back 7 days. - Schema-drift topics are created only when `RSYNC_SCHEMA_DRIFT_ENABLED=true`. - A PostgreSQL or MongoDB CDC pipeline no longer gets a schema-history topic or an empty DDL topic; only MySQL/MariaDB, SQL Server, Oracle and Db2 sources, which use them, do. - A pipeline's incremental-snapshot signals go to one topic with a fixed key. - Dead-letter topics are created up front (1 partition, 7 days), and a message that cannot be dead-lettered is retried rather than skipped. ## [0.1.5] - 2026-09-23 Everything since v0.1.4. ### Kubernetes - A single 4-vCPU node installs: the installer trims to a set that fits instead of leaving pods `Pending`, and the orchestrator waits for Kafka rather than crash-looping past it. ### Change data capture - A CDC data topic is created with `min(3, brokers)` partitions instead of 1, so its traffic is not pinned to one leader on a multi-broker cluster. `KAFKA_CDC_TOPIC_PARTITIONS` sets it wider. ## [0.1.4] - 2026-09-21 Everything since v0.1.3. ### Kubernetes - **One-command installer** (`install-k8s.sh`) that fits the cluster it lands on, waits for a slow image pull instead of failing, and keeps Kafka Connect credentials across a pod restart. The chart's default image tag is multi-arch (`amd64` and `arm64`). ### Change data capture - Auto-pickup: a new source table joins a running "whole database" CDC pipeline. - MongoDB: a stalled source now fails loudly instead of reporting healthy; the heartbeat topic is named with the key Debezium reads; editing a pipeline's tables updates `collection.include.list`; a standalone `mongod` is refused before `start_sync`; MongoDB CDC/streaming runs that carry an enabled `mask_pii` are refused. - Fixes for wrong row counts, counters that reset on restart, and cooldowns that never blocked. - The assessor warns about PostgreSQL tables without a primary key that sit outside a CDC pipeline. ### Connections and storage - A Scope step, server-level MySQL, MongoDB and ClickHouse connections, multi-database CDC and mirror mapping; namespace listing (`GET /connections/:id/namespaces`). - Table discovery lists up to 5000 tables with totals. - Object-storage layout v2 for GCS, S3 and Azure Blob (no pipeline id in the path). - Deleting a pipeline closes six cleanup gaps and no longer un-owns destination data. ### Security - Plain-`http` OAuth token endpoints are refused for Kafka in all four runtimes. - The connector deploy gate fails closed when `ENVIRONMENT` is unset; MongoDB URI aliases are masked. - Compose Kafka Connect honours `KAFKA_*` security settings. ### Interface - Monitoring Overview shows freshness, backlog, Kafka lag and failures; the pipeline page has an Assessment tab; Activity replaces Trace and Live events; Data flow reads top-down. - Explorer: a model page shows its lineage graph, its schedule in words and who runs it. - Stage durations come from one formatter, so a single transition no longer reads as a retry. ### Removed - The bundled observability-backend stack. Telemetry still exports over OTLP to whichever collector you configure; the seeded `sentinel_config` keys are now backend-neutral (migration `100`). ## Earlier changes Entries from before the release tags; they are not tied to a version. ### ๐Ÿ“š Documentation #### Added - **Solutions guides** under `docs/solutions/`: self-hosted PostgreSQL CDC, PostgreSQL to MySQL sync, Shopify to PostgreSQL, scheduled SQL models with dependency triggers, and data lineage and pipeline observability. Each states its prerequisites, what is and is not supported, and how far it has been verified. - **Public release checklist** (`docs/deployment/public-release-checklist.md`): the manual GitHub steps for a release, and what each download and usage number does and does not measure. #### Changed - README and docs index lead with the same positioning: a self-hosted data platform for batch pipelines, CDC, scheduled data models and lineage. ### โœ… Authentication & Security #### Added - **User Authentication System** - Email/password login and registration - Session-based auth with UUID tokens - bcrypt password hashing (cost 10) - 24-hour session expiration - Protected routes via Next.js middleware - Logout functionality - **Security Enhancements** - Sensitive data masking in logs - Trace ID propagation across all services - Structured logging with context - Input validation on all endpoints - CORS configuration #### Changed - **BREAKING โ€” a plain-`http://` Kafka OAuth token endpoint is now refused at start-up** (it used to log a warning and connect anyway). The client-credentials grant POSTs `KAFKA_SASL_OAUTHBEARER_CLIENT_SECRET` to that URL on *every* token fetch, so one plain-http hop hands a credential that never expires to anyone on the path โ€” worse than the short-lived bearer token it buys, and not repairable by any broker-side setting. Enforced identically by the Go tier, the Python tier, the Debezium connector, the Kafka Connect image, the `kafka-init` scripts and the Helm chart. - **Exception:** a loopback host โ€” `localhost`, `*.localhost`, `127.0.0.0/8`, `::1` โ€” is still allowed, because a token helper on the same host never puts the secret on a network. GCP Workload Identity's `http://localhost:14293` is exactly that case. - **Opt-out, for disposable test rigs only:** `KAFKA_SASL_OAUTHBEARER_ALLOW_INSECURE_TOKEN_ENDPOINT=true` (Helm: `kafka.external.oauth.allowInsecureTokenEndpoint=true`). - **Action required** only if you point `KAFKA_SASL_OAUTHBEARER_TOKEN_ENDPOINT` at a non-loopback `http://` URL: switch the IdP to https. A bundled-broker deployment sets no token endpoint and is unaffected. - Kafka connection failures in the Python tier now name the real cause (rejected SASL credentials, untrusted CA, missing client certificate) instead of surfacing only `KafkaTimeoutError: Failed to update metadata after 60.0 secs`, which every one of those causes used to collapse into. - Removed all hardcoded user IDs - All API calls now use authenticated user's ID - Database cleaned to single admin user #### Files Modified - `api-gateway/internal/handlers/auth.go` - Auth endpoints - `api-gateway/migrations/006_sessions_table.sql` - Sessions table - `frontend/src/lib/auth.ts` - Client-side auth helpers - `frontend/src/middleware.ts` - Route protection - `frontend/src/app/(auth)/login/page.tsx` - Login page - `frontend/src/app/(auth)/signup/page.tsx` - Signup page - `frontend/src/components/layout/Header.tsx` - User dropdown with logout ### โœ… API Integration Fixes #### Added - **Centralized API Configuration** - `frontend/src/lib/config/api.ts` - Single source of truth - All service URLs and endpoints defined in one place - Environment variable support #### Changed - **Fixed API Endpoints Across All Pages** - Connections API: `localhost:8082` โ†’ `localhost:8081` - Pipelines API: `localhost:8000` โ†’ `localhost:5001` - Executions API: `localhost:8082` โ†’ `localhost:5001` - Endpoint paths: `/cdc-connections/*` โ†’ `/connections/*` - **Updated API Libraries** - `frontend/src/lib/api/connections.ts` - Fixed ports and endpoints - `frontend/src/lib/api/pipelines.ts` - Uses API Gateway + auth - `frontend/src/lib/api/executions.ts` - Added auth headers - **Updated Pages** - `/connections/[id]` - Fixed endpoints and user ID - `/connections/page` - Proper auth integration - `/connections/new` - Proper auth integration - `/pipelines/page` - Fixed navigation and API port #### Removed - Local `getUserId()` implementations in API files - Hardcoded user IDs throughout frontend ### โœ… Logo System #### Added - **High-Quality Logo Download System** - Multi-source fallback: Clearbit โ†’ Google High-Res โ†’ Frontend fallback - Automated logo download during connector generation - 512x512 PNG format standardization - Local storage in `shared/mcp-connectors/:name/logo.png` #### Changed - `llm-service/src/utils/logo_downloader.py` - Simplified to 133 lines - Removed PIL dependency - Removed placeholder generation - Frontend handles fallback rendering with emojis #### Removed - `scripts/download_connector_logos.py` - Old low-quality script - `scripts/update_connector_logos.py` - Redundant CDN URL script - Logo URL fields from connector metadata #### Files Added - `shared/mcp-connectors/*/logo.png` - High-quality logos for all connectors - `docs/LOGO_SYSTEM.md` - Logo system documentation ### โœ… Pipeline Navigation Fix #### Changed - **Fixed Pipeline Creation Navigation** - `/pipelines` page: "New Pipeline" button now goes to `/pipelines/new` - Empty state: "Create Your First Pipeline" goes to `/pipelines/new` - Fixed API port: `8082` โ†’ `8081` for CDC pipelines #### Clarified - `/pipelines/new` - General pipeline builder (AI + Manual modes) - `/cdc/new` - CDC-specific conversational AI chat #### Files Modified - `frontend/src/app/(dashboard)/pipelines/page.tsx` - Fixed navigation links ### โœ… Tracing & Observability #### Added - **Distributed Tracing** - `X-Trace-ID` header propagation across all services - Consistent logging with trace context - Request/response tracing #### Changed - **Masking Utilities** - Go: `api-gateway/internal/security/masking.go` - Python: `llm-service/src/utils/masking.py` - Masks: password, secret, api_key, token, access_key, etc. #### Files Modified - `api-gateway/internal/telemetry/middleware.go` - Trace middleware - `backend-orchestrator/internal/kafka/manager.go` - Kafka trace propagation - `llm-service/src/agents/*/service.py` - Added trace logging ### ๐Ÿ—„๏ธ Database #### Added - **Migration Scripts** - `001_init_schema.sql` - Initial database schema - `002_agentic_enhancements.sql` - Agent tracking tables - `003_oauth_tables.sql` - OAuth provider support - `004_genericity_enhancements.sql` - Generic connector support - `005_insert_default_user.sql` - Default development users - `006_sessions_table.sql` - Session management - **Migration Runner** - `scripts/run_all_migrations.sh` - Runs all migrations in order - Idempotent migrations with `CREATE IF NOT EXISTS` - Connection verification before running #### Changed - Database cleaned to single admin user (`admin@rsync.ai`) - Foreign key constraints properly configured - UUID-OSSP extension enabled ### ๐Ÿ“ Documentation #### Added - `docs/services/INDEX.md` - Per-service HLD/LLD documentation index - `CHANGELOG.md` - This file - Inline documentation improvements #### Consolidated - Combined multiple technical documents into single source - Organized by topic and service #### Removed - Individual fix documentation files (consolidated into changelog) - Redundant setup guides ### ๐Ÿงน Cleanup #### Removed Redundant Files - `FRONTEND_API_AUDIT.md` - Temporary audit file - `api-gateway/migrations/README.md` - Redundant documentation - Old logo scripts (download_connector_logos.py, update_connector_logos.py) #### Organized - Scripts consolidated in `/scripts/` - Documentation consolidated in `/docs/` - All migrations properly versioned --- ## Migration Guide ### From Previous Version 1. **Update Environment Variables** ```bash # Ensure correct service ports in .env NEXT_PUBLIC_API_URL=http://localhost:5001 NEXT_PUBLIC_BACKEND_ORCHESTRATOR_URL=http://localhost:8081 NEXT_PUBLIC_LLM_SERVICE_URL=http://localhost:5011 ``` 2. **Run Database Migrations** ```bash ./scripts/migrate.sh ``` 3. **Clear Old Sessions** ```bash # If upgrading from version without auth docker compose exec postgres psql -U rsync -d rsyncdb -c "DELETE FROM sessions" ``` 4. **Rebuild Frontend** ```bash docker compose build --no-cache frontend docker compose up -d ``` 5. **Login with New Auth** - Email: `admin@rsync.ai` (override with `ADMIN_EMAIL`) - Password: set during setup โ€” `install.sh` generates a unique admin password; never rely on a shared default --- ## Known Issues Open issues are tracked at [github.com/rsync-ai/rsync.ai/issues](https://github.com/rsync-ai/rsync.ai/issues) โ€” that list is the register, and it cannot go stale the way a hand-maintained count here does. This heading used to read "None at this time", which was untrue when it was written and had no way of noticing. --- ## Upcoming Features - [ ] Webhook integrations - [ ] Advanced pipeline monitoring dashboard - [ ] SSO/SAML authentication - [ ] Pipeline templates library - [ ] Connector marketplace --- ## Support For issues or questions: - Review: `docs/services/INDEX.md` - Check: `docker compose logs ` - GitHub: [rsync-ai/rsync.ai issues](https://github.com/rsync-ai/rsync.ai/issues) - Email: support@rsync.ai