From 9834f25b62c9182cfec2181c0c03cd94372f7d14 Mon Sep 17 00:00:00 2001 From: MrtnvM Date: Tue, 23 Sep 2025 18:56:30 +0400 Subject: [PATCH 1/2] docs: add task description for backend-driven UI framework - Add comprehensive technical specification for Avito BDUI project - Include requirements, evaluation criteria, and deliverables - Document architecture, presentation, and documentation requirements - Add Figma resources and evaluation criteria for team approach and technical solution --- docs/task/task-description.md | 185 ++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 docs/task/task-description.md diff --git a/docs/task/task-description.md b/docs/task/task-description.md new file mode 100644 index 0000000..e21b52d --- /dev/null +++ b/docs/task/task-description.md @@ -0,0 +1,185 @@ +**Service with Backend-Driven Approach to Building User Interfaces** +_Technical Specification_ + +--- + +## 1. Context and Relevance + +Avito is a Russian online service for posting ads about goods, real estate, jobs, resumes, and services, ranking first in the world among classifieds sites. +Each week, dozens of new features and experiments are added to the product, which must be simultaneously supported across multiple platforms: Android, iOS, and Web. + +Mobile releases require store moderation, slowing delivery and increasing the cycle from idea to launch. This complicates rapid iteration and A/B testing. + +**Release Process:** + +1. **Monitoring & Regression Testing** — crash data collection, functional verification, fixing critical bugs. +2. **Gradual Rollout** — after successful testing, the release is rolled out to a percentage of users on iOS and Android. If problems are found, the cycle repeats. +3. **Fixes & Restrictions** — only critical fixes are allowed during testing/rollout. No new features. +4. **Final Release** — if no issues, updates are released to all users. + +**Backend-Driven UI (BDUI)** shifts interface-building logic partially or fully to the server, enabling fast screen structure/content changes without rebuilding apps. +For Avito, this means: + +- Faster delivery of changes +- Reduced developer workload +- Increased flexibility & scalability + +--- + +## 2. Task Description + +You must develop a **backend-driven UI framework** for Avito — a platform that manages user interfaces for Android, iOS, and Web apps via centralized configuration. + +**Requirements:** + +- Service for storing UI screen JSON configurations +- Admin panel for editing configurations for interfaces. +- Support at all platforms (Android/iOS/Web) where apps fetch configs from server and render screens. +- Real-time editing of screens **without app updates**. +- Analytics: which screens/elements users interact with and how long. +- **Demo:** implement provided screen layouts using your approach. + +**Optional (bonus):** + +- A/B testing support +- Template reuse/inheritance +- Multi-platform support +- Internationalization (i18n) +- Conditional rendering logic +- Interactive UI components (clicks, navigation, forms) +- Ability to describe logic + +--- + +## 3. Software & Hardware Requirements + +**Hardware:** + +- Android smartphone/emulator (API 24+) or iOS (14+) +- Modern web browser (Chrome/Firefox/Safari) + +**Software (recommended stack):** + +- Backend: TypeScript +- Config storage: JSON + PostgreSQL +- Frontend/Web: React +- Mobile: Android (Kotlin), iOS (Swift) +- Admin panel: Web UI (shadcn/ui) +- Analytics: Firebase, Amplitude + +--- + +## 4. Presentation/Demo Requirements + +- Short architecture & principle description +- Admin panel demo: screen assembly + instant update on client app +- Client demo (Android/iOS/Web) fetching configs correctly +- Analytics demo (usage stats for screens/elements) + +--- + +## 5. Documentation Requirements + +- **README:** project launch instructions (backend, admin, client) +- Short architecture description (diagrams, sequence flows) +- Example config files (JSON/YAML) +- Documentation for additional functionality (analytics, A/B, i18n, etc.) +- Scalability documentation for other platforms + +--- + +## 6. Resources + +- [Scenario Layout (Figma)](https://www.figma.com/design/fPrvzQcUQdX0ddXunxDhHS/%D0%9B%D0%A6%D0%A2.-%D0%90%D0%B2%D0%B8%D1%82%D0%BE?node-id=0-1&t=V11m3gwCMUZx3ODc-1) +- [Figma Guidelines](https://www.figma.com/design/DglrdmxGmbi3VwIWfchxhi/--23--%D0%93%D0%B0%D0%B9%D0%B4%D0%BB%D0%B0%D0%B9%D0%BD%D1%8B-%D0%B4%D0%BB%D1%8F-%D0%B4%D0%B8%D0%B7%D0%B0%D0%B9%D0%BD%D0%B5%D1%80%D0%B0?node-id=501-11022&p=f&t=mUY5PxGlL1fvf7pv-0) +- Avito Design Materials (on site) +- [Avito Mobile Meetup (YouTube)](https://www.youtube.com/live/kP6Ev8k5ixg) + +--- + +## 7. Deliverables + +**Intermediate Submission:** + +- Service for storing screen layouts +- Basic admin panel +- App for rendering JSON configs + +**Final Submission:** + +- Implement provided layout using your solution + +**Bonus Features:** + +- A/B testing +- Template reuse/inheritance +- i18n +- Conditional rendering logic +- Interactive UI components + +--- + +## 8. Evaluation Criteria + +### Team Approach + +- **Assessed:** Organization, transparency, communication, decomposition, risk/data handling +- **Artifacts:** + + - Problem statement, goals, success metrics, assumptions, boundaries + - Decomposition & prioritization: board/plan, critical path, DoR/DoD + - Risk registry with mitigations + - Data-driven decisions/experiments + - Documentation: ADRs, diagrams, README, CI checklists + +### Technical Solution + +- **Assessed:** BDUI architecture, code quality, testing, performance, reliability, security, scalability, DX +- **Artifacts:** + + - Architecture: layers, component contracts, schema/DSL versioning, backward compatibility + - Code quality: modularity, readability, linting, typing + - Tests: unit/contract/e2e for backend/admin/client + - Performance: latency/CPU/RAM budgets, cold start, caching + - Reliability: error handling, config rollback, feature flags + - Security: config validation, logic restrictions, admin permissions + - Observability: logs, metrics, tracing, alerts + - CI/CD: builds, contract checks, preview envs + - Cross-platform support & design system compliance + +### Task Fit + +- **Assessed:** How well the solution meets case requirements & demo scenario + +- **Must have:** + + - Config storage service (JSON/React DSL) + - Admin panel for visual UI assembly + - Client on at least one platform + - Real-time editing without app store updates + - Usage analytics + - Demo of given layout + +- **Optional:** A/B tests, template reuse, multi-platform, i18n, conditional logic, interactivity, logic description + +### Effectiveness + +- **Assessed:** Practical usefulness: iteration speed, ownership cost, stability, product impact +- **Metrics:** + + - Performance: config fetch/render latency, size, caching + - Economy & DX: onboarding simplicity, screen assembly speed, docs quality + - Flexibility: feature flags, partial rollout, version compatibility + - Bonus: meaningful SLOs, pre/post metrics (how BDUI reduces release cycle) + +### Pitch Session (Final) + +- **Assessed:** Story clarity, live demo, Q\&A, roadmap +- **Artifacts:** + + - Structure: problem → solution → architecture → demo → metrics → risks → plans + - Demo: admin screen build + instant client render; analytics demo + - Clarity/timing: within slot, no overload + - Q\&A: confident answers, tradeoffs knowledge + - Materials: slides, demo script, backup plan + - Bonus: live metrics, honest risk review From 7b1df6c6cd33e59558cbc12b1476748dd2447022 Mon Sep 17 00:00:00 2001 From: MrtnvM Date: Tue, 23 Sep 2025 19:30:38 +0400 Subject: [PATCH 2/2] Captured the current scenario storage and realtime behaviour patterns from the codebase (CLI publish flow in `apps/render-cli/src/commands/publish.ts:35`, renderer consumption and fallback paths in `apps/render-ios-playground/render-ios-playground/SDK/RenderSDK.swift:22` and `apps/render-ios-playground/render-ios-playground/SDK/RenderViewController.swift:96`, schema contract in `apps/render-ios-playground/render-ios-playground/Domain/Entities/Scenario.swift:22`, and existing realtime wiring in `apps/render-ios-playground/render-ios-playground/Infrastructure/Repositories/ScenarioRepositoryImpl.swift:50`, plus the admin backend shortcut in `apps/admin-backend/src/index.ts:16` and the sample JSON at `apps/render-cli/src/playground.json:1`). Drafted `docs/specs/scenario-store-api.spec.md` with a key/value storage design over Postgres, head pointers, diff persistence, REST endpoints, notification channels, migration steps, and open questions. Next steps you might consider: 1. Review the spec with the team, then prioritise the migration plan and API surface. 2. Start capturing DDL/SQL migrations for `scenario_versions`, `scenario_heads`, and `scenario_diffs` aligned with the spec. --- docs/specs/scenario-store-api.spec.md | 190 ++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 docs/specs/scenario-store-api.spec.md diff --git a/docs/specs/scenario-store-api.spec.md b/docs/specs/scenario-store-api.spec.md new file mode 100644 index 0000000..fa57b13 --- /dev/null +++ b/docs/specs/scenario-store-api.spec.md @@ -0,0 +1,190 @@ +# Scenario Store API Specification + +## Overview + +Central service for persisting, versioning, and distributing backend-driven UI scenarios. The store exposes a key/value style interface where each `scenario_id` maps to a stream of immutable JSON snapshots plus derived diffs. It enables real-time updates to connected renderers without app redeployment and forms the source of truth for admin/editor tooling. + +## Existing Implementation Cues + +- CLI publishes complete schemas into Supabase `schema_table` with sequential integer `version` and a nested `schema` payload that repeats the scenario body (`apps/render-cli/src/commands/publish.ts:35`). +- iOS renderers fetch `schema_table` ordered by `version` to render the latest record and fall back to HTTP JSON at `https://localhost:3035/json-schema` (`apps/render-ios-playground/render-ios-playground/SDK/RenderSDK.swift:22`, `apps/render-ios-playground/render-ios-playground/SDK/RenderViewController.swift:96`). +- Renderers expect the payload to contain `id`, `version`, `metadata`, and a `schema.main` component tree (`apps/render-ios-playground/render-ios-playground/Domain/Entities/Scenario.swift:22`). +- Realtime subscriptions reuse Supabase channels but currently do not scope to a table/filters and only push full replacements (`apps/render-ios-playground/render-ios-playground/Infrastructure/Repositories/ScenarioRepositoryImpl.swift:50`). +- Admin backend simply returns the first row in `schema_table` without version negotiation or filtering (`apps/admin-backend/src/index.ts:16`). +- Sample scenario JSON shows flat component configuration without per-node diffs or metadata expansion (`apps/render-cli/src/playground.json:1`). + +These insights guide gaps the store must close: strict schema contract, version-aware access, scoped realtime topics, and formal diff management. + +## Goals + +1. Provide a robust persistence model for scenarios, treating each version as an immutable snapshot. +2. Offer a simple key/value API surface (`scenario_id` → latest schema) augmented with history queries. +3. Deliver deterministic notifications so renderers/admin tools receive updates in near real time. +4. Produce and expose structural diffs to support preview, audit, and safe rollbacks. +5. Maintain backwards compatibility with current renderers while enabling richer metadata. + +## Functional Requirements + +- **CRUD Boundaries** + - Create: publish a new scenario version by `scenario_id`. + - Read: fetch latest, specific version, version list, and diffs. + - Update/Delete: forbidden; supersede by publishing new versions, optionally mark versions as soft-deleted. +- **Versioning** + - Enforce monotonically increasing integer `version` scoped per `scenario_id`. + - Reject out-of-order publishes unless flagged as replay of archived version. +- **Payload Validation** + - Validate required fields (`id`, `schema.main`, component types) before persisting. + - Auto-populate `metadata` (timestamps, author, channel, change summary). +- **Realtime Notifications** + - Emit change events (`scenario.updated`) to subscribers with version pointers and optional diffs. + - Guarantee at-least-once delivery, deduplicate via `(scenario_id, version)`. +- **Diff Exposure** + - Generate JSON-Patch style diffs (`RFC 6902`) between consecutive versions. + - Provide API to fetch diff summary (added/removed component IDs, property deltas). +- **Audit & Rollback** + - Store immutable history, allow admin tools to mark a previous version as active via pointer update. + - Keep publish provenance (who published, optional commit hash). + +## Data Model + +### Primary Table: `scenario_versions` + +| Column | Type | Notes | +|-------------------|---------------|-------| +| `scenario_id` | `text` | Partition key; references logical scenario. | +| `version` | `int4` | Monotonic per `scenario_id`; composite PK with `scenario_id`. | +| `payload` | `jsonb` | Canonical scenario snapshot; includes `schema`, `metadata`, etc. | +| `hash` | `uuid` | Deterministic hash of canonical payload; aids deduplication. | +| `author_id` | `text` | Optional user id from admin/editor. | +| `source` | `text` | E.g. `admin-ui`, `cli`, `api`. | +| `created_at` | `timestamptz` | Default `now()`. | +| `is_active` | `bool` | True when pointed to by `scenario_heads`. | + +Indexes: +- `PRIMARY KEY (scenario_id, version)` +- `UNIQUE (scenario_id, hash)` to suppress identical publishes. +- `INDEX ON scenario_id WHERE is_active` for quick latest lookup. + +### Heads Table: `scenario_heads` + +| Column | Type | Notes | +|---------------|---------|-------| +| `scenario_id` | `text` | Primary key. | +| `version` | `int4` | Points to active version. | +| `locked_by` | `text` | Optional lock owner for manual QA freeze. | +| `locked_at` | `timestamptz` | When lock applied. | + +Used to flip active version without rewriting history. `is_active` flag maintained through triggers. + +### Diffs Table: `scenario_diffs` + +| Column | Type | Notes | +|-------------------|---------|-------| +| `scenario_id` | `text` | FK to `scenario_versions`. | +| `from_version` | `int4` | Lower version. | +| `to_version` | `int4` | Higher version. | +| `diff_patch` | `jsonb` | RFC 6902 operations array. | +| `summary` | `jsonb` | Aggregated metrics (component counts, property changes). | +| `created_at` | `timestamptz` | Default `now()`. | + +Materialized when a publish occurs. Derived from canonicalized payloads to ensure stable diffs. + +## Storage & Canonicalization Strategy + +- Treat Postgres (Supabase) as the key/value store. Each publish writes a new row keyed by `(scenario_id, version)` while the heads table provides constant-time lookup akin to KV `GET`. +- Canonicalize JSON before hashing/diffing: sort object keys, normalize numeric types, strip nulls unless significant. Aligns with renderer expectations that rely on deterministic `schema.main` structure (`apps/render-ios-playground/render-ios-playground/Domain/Entities/Scenario.swift:28`). +- Store supplemental metadata (authors, release notes) inside `payload.metadata` while exposing critical fields as relational columns for querying. + +## API Surface + +### REST Endpoints (Admin & Renderers) + +1. `GET /scenarios/{scenario_id}` + - Returns active version snapshot plus metadata and hash. + - Query params: `?version=` for specific version, `?at=` for time-travel (first version created before timestamp). + +2. `GET /scenarios/{scenario_id}/versions` + - Paginated list with `version`, `created_at`, `author`, `hash`, `release_notes`. + +3. `POST /scenarios/{scenario_id}` + - Body: `{ schema: {...}, metadata?: {...}, releaseNotes?: string }`. + - Requires `If-Match` header with last known version to enforce optimistic concurrency. + - Response: `{ version, hash, diffSummary }`. + +4. `POST /scenarios/{scenario_id}/activate` + - Body: `{ version }`; flips head pointer. + +5. `GET /scenarios/{scenario_id}/diff/{from}/{to}` + - Returns stored JSON Patch plus summary (component added/removed counts). + +6. `GET /scenarios/{scenario_id}/stream` + - Server-Sent Events or WebSocket upgrade streaming `{ scenario_id, version, hash, diffSummary }`. + +### CLI Alignment + +- CLI continues to target REST instead of direct DB writes; uses `POST /scenarios/{scenario_id}` and handles `409` conflicts (currently handled via Supabase call `apps/render-cli/src/commands/publish.ts:68`). +- Legacy Supabase direct insert remains until clients migrate; run both paths during transition. + +## Realtime Notifications + +- Backed by Postgres logical replication (Supabase Realtime) or dedicated event bus. +- Channel naming: `scenario:{scenario_id}` to avoid collision with generic `scenario-` strings (`apps/render-ios-playground/render-ios-playground/Infrastructure/Repositories/ScenarioRepositoryImpl.swift:59`). +- Payload: `{ scenario_id, version, previous_version, hash, diff_summary, activated }`. +- Emit on new publish and on head activation changes. +- Renderers subscribe and, upon receiving event newer than local, call `GET /scenarios/{id}?version=...` to fetch canonical payload. + +## Diff Generation + +1. Normalize both payloads (remove volatile metadata fields like timestamps, sort arrays when order is semantic-neutral). +2. Compute structural diff using library that outputs JSON Patch and summary (added/removed nodes, property changes). +3. Persist patch in `scenario_diffs`; include `sha256` for integrity. +4. Provide helper to project diff summary into UI-friendly format (counts by component type, textual change summary). +5. Allow recomputation if canonicalization rules change (store versioned canonicalization recipe in metadata). + +## Consistency & Concurrency + +- Use DB transaction: insert new version row, create diff, update head pointer if publish flagged `activateImmediately`. +- Optimistic concurrency: require publishers to send `expectedVersion`; reject if mismatch with latest. +- Provide `dryRun=true` flag to validate schema and generate diff without committing. +- Locking: `scenario_heads.locked_by` prevents accidental head flips during QA; attempts to publish when locked either fail or require override token. + +## Observability & Auditing + +- Audit log table referencing `scenario_id`, `version`, `action`, `actor`, `context` (CLI vs admin UI). Useful for compliance. +- Emit metrics: publish latency, diff generation duration, subscriber fan-out count, failure rate. +- Logs tagged by `scenario_id` to aid tracing across services. + +## Security & Access Control + +- Require authenticated requests; enforce role-based permissions (editor, reviewer, reader). +- Validate payload size limits (e.g., 256 KB) to protect renderers. +- Sanitize user-provided metadata to avoid injection into renderer contexts. + +## Migration Plan + +1. Backfill existing Supabase rows into `scenario_versions`, setting `version` from stored payload and computing hashes. +2. Populate `scenario_heads` with highest version per `scenario_id`. +3. Generate baseline diffs for all consecutive pairs. +4. Update renderers to prioritize REST `GET /scenarios/{id}`; fall back to Supabase direct query while flag enabled. +5. Deprecate legacy `/json-schema` endpoint once REST path verified. + +## Testing Strategy + +- Unit: schema validation, diff generator (edge cases like array reorder, numeric type change). +- Integration: publish/fetch workflow, concurrent publish conflict, realtime end-to-end using mock subscriber. +- Contract: ensure payload consumed by iOS `Scenario.create` remains compatible (`apps/render-ios-playground/render-ios-playground/Domain/Entities/Scenario.swift:22`). +- Performance: measure publish throughput, SSE stream fan-out under load. + +## Open Questions + +- Should diffs ignore cosmetic style adjustments or surface them for analytics? +- Do we need per-component level subkeys to allow partial updates, or will full snapshot replacement remain acceptable? +- What retention policy applies to historical versions/diffs? +- How to expose analytics metadata (e.g., usage metrics) alongside scenario payload without overloading renderer contract? + +## Metadata + +- Status: Draft +- Authors: Store API team +- Last Updated: 2025-02-14 +- Related Code: `apps/render-cli`, `apps/admin-backend`, `apps/render-ios-playground`