Skip to content

View Operations

End-to-end flows for view CREATE, UPDATE, DELETE, and schema sync/reset. Views map to database tables in the customer database — creating or deleting a view means creating or dropping an actual table.

View CREATE

Creates a new view (table) — always asynchronous because it requires CREATE TABLE on the customer database.

Response: 202 Accepted

Frontend (Spread)                  Quarkus REST                         RabbitMQ              Processor (Spring Boot)
─────────────────                  ────────────                         ────────              ───────────────────────
User clicks "Add View"


NgRx action: createView


ViewCrudEffects
    │ POST /api/metadata/views

ViewResource.createView()


ViewService
  .createByWorkspaceUuid()

    ├── Generates EntityMetadataDTO
    │   (no View entity yet —
    │    processor creates it)

    └── Queues outbox message

                                                              MetadataUpdateProducer
                                                            .onEntityChange(CREATE)


                                                                  metadata-updates
                                                                     exchange


                                                              EntityMetadataConsumer
                                                            .processEntityMetadataInternal()


                                                              CREATE TABLE IF NOT EXISTS
                                                              (via FlywayMigrationService)


                                                              TaskCompletionProducer
                                                                .sendSuccess()


                                                                  task-completion
                                                                     exchange
    ┌─────────────────────────────────────────────────────────────────────┘

Quarkus TaskCompletionConsumer


ViewOperationHandler
  .handleCreate()

    ├── Creates View entity
    ├── Creates all ViewColumns
    └── Creates ColumnMetadata records


SSE: metadata.view.created


Frontend receives SSE


NgRx action: viewCreatedFromSSE


Navigate to new view

Key Detail: Deferred View Entity Creation

Unlike columns (where metadata is created before the processor runs), views are only created in the metadata DB after the processor succeeds. The flow:

  1. REST endpoint generates an EntityMetadataDTO describing the table structure
  2. This DTO is sent to the processor via RabbitMQ (no View entity exists yet)
  3. Processor creates the physical table
  4. On success, ViewOperationHandler.handleCreate() creates the View, ViewColumn, and ColumnMetadata records

This means if the processor fails, no orphan View record exists in the metadata DB.

Frontend Optimistic Create

  • A temporary view is added to the sidebar immediately with a generated UUID
  • The view shows a loading state until SSE confirms creation
  • A timeout mechanism removes the temp view if no SSE confirmation arrives within a configured window
  • On SSE metadata.view.created: the temp view is replaced with the real view and the user is navigated to it

View DELETE

Deletes a view (drops the table) — asynchronous with optimistic archival.

Response: 202 Accepted

Frontend (Spread)                  Quarkus REST                         RabbitMQ              Processor (Spring Boot)
─────────────────                  ────────────                         ────────              ───────────────────────
User deletes view
(confirm dialog)


NgRx action: deleteView


ViewCrudEffects
    │ DELETE /api/metadata/
    │   views/{uuid}

ViewResource.deleteView()


ViewService
  .deleteByUuid()

    ├── Archives the view
    │   (soft delete)

    └── Queues outbox message

                                                              MetadataUpdateProducer
                                                            .onEntityChange(DELETE)


                                                                  metadata-updates
                                                                     exchange


                                                              EntityMetadataConsumer
                                                            .processEntityMetadataInternal()


                                                              DROP TABLE IF EXISTS
                                                              (via FlywayMigrationService)


                                                              TaskCompletionProducer
                                                                .sendSuccess()


                                                                  task-completion
                                                                     exchange
    ┌─────────────────────────────────────────────────────────────────────┘

Quarkus TaskCompletionConsumer


ViewOperationHandler
  .handleDelete()

    ├── Cascade delete ViewColumns
    ├── Cascade delete ColumnMetadata
    └── Delete View entity


SSE: metadata.view.deleted


Frontend: viewDeletedFromSSE


Remove view from sidebar,
navigate to next view

Archive-First Strategy

The view is archived (soft-deleted) before the processor runs. This allows rollback:

  • On success: ViewOperationHandler.handleDelete() performs the hard delete of all related records
  • On failure: the view is unarchived (restored) and an error notification is shown to the user

Cascade Delete Order

ViewOperationHandler.handleDelete() cleans up in this order:

  1. ViewColumnPath records
  2. ViewColumn records
  3. ColumnMetadata records
  4. View entity itself

View UPDATE

Updates view properties (name, slug, position) — synchronous, no processor involvement.

Response: 200 OK

Frontend (Spread)                  Quarkus REST
─────────────────                  ────────────
User renames view
or changes position


NgRx action: updateView


ViewCrudEffects
    │ PUT /api/metadata/views/{uuid}

ViewResource.updateView()


ViewService.updateByUuid()

    ├── Updates View entity
    │   (name, slug, position)

    └── Returns updated view


SSE: metadata.view.updated


Other clients: viewUpdatedFromSSE

View updates are simple because they only affect metadata — no table structure changes, no processor involvement.


Schema Sync / Reset

Re-synchronizes the metadata DB with the actual state of the customer database. Used when a customer modifies their database directly (outside SchemaStack) and needs the UI to reflect the changes.

Frontend (Admin)                   Quarkus REST
─────────────────                  ────────────
User clicks "Sync Schema"


POST /api/workspace/
  {uuid}/schema/sync


SchemaResetService
  .resetSingleView()

    ├── 1. Connect to customer DB
    │      (decrypt credentials,
    │       JDBC connection)

    ├── 2. Introspect actual schema
    │      (DatabaseMetaData.getTables()
    │       + getColumns())

    ├── 3. Compare with metadata
    │      (detect added/removed/
    │       changed columns)

    ├── 4. Create new ViewColumns
    │      for added columns

    ├── 5. Update changed columns
    │      (type mismatches, etc.)

    └── 6. Remove ViewColumns for
          dropped columns


SSE: workspace notification


Frontend: reload view

SchemaSyncOrchestrator

The full workspace-level sync uses the SchemaSyncOrchestrator which manages a state machine with checkpoint/resume:

INITIATED → SCHEMA_EXTRACTED → ENTITIES_MERGED → RELATIONSHIPS_MERGED
    → VIEW_COLUMNS_GENERATED → HASH_UPDATED → COMPLETED

Each step is checkpointed so that a failed sync can be resumed from the last successful step rather than starting over.

Cross-reference

See the Multi-Tenancy page for full details on the SchemaSyncOrchestrator state machine, progress tracking, and the schema import flow.

What Sync Does NOT Do

  • Does not create or drop tables — only syncs column-level changes within existing views
  • Does not go through the processor — reads the customer DB directly via JDBC
  • Does not modify the customer database — it only updates SchemaStack's metadata to match reality

Response Code Summary

OperationSync/AsyncSuccess CodeNotes
View CREATEAsync202 AcceptedRequires CREATE TABLE
View DELETEAsync202 AcceptedRequires DROP TABLE
View UPDATESync200 OKMetadata only
Schema SyncSync200 OKDirect DB introspection

Cross-References

SchemaStack Internal Developer Documentation