- DRAFT validation was removed from orchestrator_validation.py (moved to service layer)
- Integration test expected ValueError for DRAFT jobs — fixed to test actual behavior
- 194/194 integration tests pass, 0 failures
Introduce a deployment recording system to track dashboard versions
across environments and improve the Git management user experience.
- Add `Deployment` model and Alembic migration to persist deployment
history.
- Implement `GitDeploymentRecorder` and `GitFingerprint` plugins to
automate deployment logging and content hashing.
- Add `get_deployment_status` API endpoint to retrieve real-time
environment states.
- Refactor `GitLifecycleHeader` to prioritize Call-to-Action (CTA)
buttons and improve visual hierarchy.
- Update `GitWorkspacePanel` to emphasize version saving and
streamline commit workflows.
- Enhance `GitEnvironmentTimeline` with deployment status integration,
collapsible UI, and improved theme consistency.
- Add auto-navigation logic in `GitManagerModel` to guide users to
relevant tabs based on recommended actions.
- Clean up obsolete documentation and update i18n strings for
git visualization features.
Implement a new Git environment timeline component to visualize dashboard
versions across different deployment stages (Development, Pre-production,
and Production). This includes new backend endpoints and frontend
services to support historical data retrieval and version comparison.
- Add `get_branch_commits` and `get_commit_diff` endpoints to backend
API and Git service.
- Implement `GitEnvironmentTimeline` Svelte component for visual
representation of deployment history.
- Update `GitManagerModel` to manage timeline state, including
environment histories and version selection for comparison.
- Add `getBranchCommits` and `getCommitDiff` methods to `gitService`.
- Improve UX by separating the branch selector from the version map.
- Add comprehensive i18n support for the new visualization features.
- Add pendingRemovals tracking and isEventRemoving() to maintenance store for better in-flight UX in EventsTable.
- Strongly type maintenance API client and store (replace unknown[]).
- Migrate selectedTask/taskLogs to dedicated lib/stores/selectedTask.svelte.ts (proper rune store with separate subscribers).
- Remove legacy central stores.svelte.ts and related dead code (src/pages/, old tests) to comply with ADR-0006 (global stores must be individual files in lib/stores/).
- Update mocks, components, models and tests accordingly.
- Fix related bugs (subscriber decoupling, test mocks).
- Add dedicated test_selectedTask.ts.
- Minor cleanups: semantic tokens, @RATIONALE for model-first, contracts update.
- All key tests (maintenance, selectedTask, store) pass.
Refs: ADR-0006, specs/031-maintenance-banner
Root cause: saveJob() used stale sourceDatasourceId (set once on load)
instead of live datasourceId (updated by ConfigTabForm via $bindable).
Since sourceDatasourceId was always truthy, the || fallback to datasourceId
never triggered — the old datasource ID was always sent to PUT.
Fixes:
- Removed dead sourceDatasourceId atom; saveJob() uses datasourceId directly
- Bound sourceTable via $bindable through ConfigTabForm; updated on select
- loadDatasourceColumns() syncs databaseDialect from Superset columns API
- saveJob() sends undefined for database_dialect="unknown" to force re-detect
- Backend: added direct_db+connection_id validation on update (mirroring create)
- Removed redundant "Язык ист." column from TranslationPreview table
- Removed unused getDetectedLang function
Tests:
- TranslationJobModel: datasourceId save mapping, dialect sync, unknown→undefined
- TranslateJobService: reject direct_db without connection_id, preserve existing
Verified: browser — translate_cross datasource persisted after save+reload,
dialect detected as "clickhouse", columns loaded (2), translation column preserved.
- Footer.svelte: replace hardcoded '2025' with new Date().getFullYear()
- build.sh: append git short hash to APP_VERSION for all bundle commands
(bundle, bundle:embeddings, bundle:light). Format: '0.5.2+6f029903'.
Previously only the tag was passed (e.g. '0.5.2'), and .git was not
available in Docker context so vite.config.js fell back to '0.0.0'.
Verified: frontend assets contain '0.5.2+6f029903', getFullYear() replaces
hardcoded 2025.
Modal now mounts at document.body level via svelte mount/unmount.
Extracted WizardContent.svelte for portal rendering.
Eliminates 32px margin from page layout wrapper
(max-w-7xl/space-y-6/px-4 container).
Added KeyRecoveryWizard as portal wrapper, WizardContent as
the actual modal component.
Critical (C1): Added has_permission('security', 'READ') to /health and
/fingerprint endpoints; has_permission('security', 'WRITE') to /recover.
Previously any authenticated user could enumerate encrypted secrets and
overwrite stored values.
High (Bug #1): Fixed recover endpoint — updated/failed status now correctly
reflects whether a non-empty replacement value was submitted. Empty values
now report 'skipped' instead of falsely 'updated'.
High (Bug #2, #3): Replaced all hardcoded English strings in
KeyRecoveryWizard.svelte and SystemSettings.svelte with $t.settings.*
i18n lookups. Keys already existed in en/ru settings.json.
High (H1): Added _sanitize_error() helper to truncate + scrub exception
messages before logging, preventing potential secret leakage in log output.
Cleanup: Moved LLMProviderConfig import to module top. Instantiate
ConnectionService once before for-loop. Added @TEST_EDGE declarations
and @PRE/@SIDE_EFFECT to C4 contract.
Tests: 226 passed
Canonical variables:
- AUTH_SECRET_KEY — JWT signing key for backend + agent (was split across
AUTH_SECRET_KEY / JWT_SECRET)
- SERVICE_JWT — agent→backend service token
- No JWT_SECRET fallback: decoder fails with migration guidance if only
JWT_SECRET is set
Compose files unified:
- docker-compose.yml, docker-compose.enterprise-clean.yml,
docker-compose.e2e.yml — all use AUTH_SECRET_KEY
- build.sh generated compose now passes AUTH_SECRET_KEY + ENCRYPTION_KEY
to backend
Env examples unified and completed:
- .env.example — comprehensive template, all compose vars
- .env.enterprise-clean.example — production template
- backend/.env.example — backend-only run
- docker/.env.agent.example — agent-only run
- NEW: .env.current.example, .env.master.example,
.env.e2e.example, frontend/.env.example
Tests aligned:
- conftest sets AUTH_SECRET_KEY (canonical value matched across test files)
- test mocks use canonical name
- 1176 passed, 0 failed
- Quick status pills (Упавшие/В работе/Успешные) always visible
- Search input with flex spacer in same row
- Explicit "Фильтры" disclosure button with filter icon, badge count, chevron
- aria-expanded / aria-controls for accessibility
- Expandable panel: type, status, time range, sort controls
- Remove bottom status bar ("Показано X из Y", "Активно фильтров")
- Update tests for expanded state and quick pill interactions
- Replace raw <button> with <Button variant="ghost">
- Dim zero-count badges with opacity-50
- Add transition-colors duration-300 to count numbers
- Replace inline reconnect link with themed <Button>
- Add min-w-0 overflow-hidden to TaskList shell container
- Add filtered_empty UX state to contract
- Update layout contract test to verify TaskList source directly
- Add transition-colors to status badges
{model.targetLanguages} is invalid shorthand — Svelte only supports
bare identifiers, not property access. Changed to explicit
targetLanguages={model.targetLanguages}