Skip to content

refactor(server): migrate denormalized integration columns off Workspace #1216

@FelixTJDietrich

Description

@FelixTJDietrich

Part of #1197.

What ships

A migration of the 11 denormalized integration columns on Workspace into workspace_integration rows: slack_*, personal_access_token, installation_id, gitlab_*, server_url, account_login, account_type, leaderboard_notification_*. The migration runs with a dual-read window: every read path consults the new table first and falls back to the legacy column; new writes go to the new table only. After one release cycle, the legacy columns are dropped in a follow-on changeset (paired with this sub-issue's PR).

Existing Workspace getters / setters for these columns are removed; the public Java surface lives behind the registry shape.

Why

The denormalized columns are the historical reason a new integration kind requires a wide schema change to Workspace. Migrating them onto workspace_integration makes the next integration kind a row insert, not a column add. The dual-read window protects mid-semester deployments — a hard cutover during the TUM introcourse is not acceptable.

Acceptance criteria

  • A Liquibase data-migration changeset copies every populated Workspace.<integration-column> value into a corresponding workspace_integration row with the appropriate kind and config_jsonb projection
  • All existing read paths now resolve via the registry; a tag (// migrated in #1216; legacy column drop in same PR's sibling changeset) marks each former-direct-column-reader
  • An integration test asserts row-by-row equivalence post-migration: for every populated workspace, the resolved values via the registry match the pre-migration column values
  • The dual-read window is enabled by default; a property toggles it off in tests; an ArchUnit rule (added in #1220) prevents new code from reading the legacy columns directly
  • A sibling Liquibase changeset (committed in the same PR, gated on the dual-read window having elapsed) drops the legacy columns; the down-script restores the columns (without data) for one-release-cycle reversibility
  • Behavior-parity tests for affected integrations pass unchanged (GitHub App install, GitLab webhook ingest, Slack notification toggle)

Tests to write

  • Migration test: seed populated Workspace rows of each shape, run the changeset, assert per-row equivalence.
  • Dual-read test: legacy column populated + new row absent → resolved via legacy; legacy column null + new row present → resolved via new; both present → new wins; both absent → null.
  • Behavior-parity tests across the affected integration code paths.
  • Column-drop reversibility test (Liquibase rollback restores the column shape, without data).

Implementation notes

  • Per-kind config_jsonb projection: the migration sub-issue documents each kind's expected JSONB shape in docs/contributor/integrations/<kind>.md (started in #1215). The shape must round-trip through the kind's handler before the column drop is allowed.
  • The leaderboard_notification_* columns are migrated for completeness; they will be dropped by the profile-centric replacement epic. The migration sub-issue here moves them to the registry shape; the profile epic deletes them. Cross-link the two sub-issues so the deletion is not duplicated.
  • account_login and account_type carry GitHub-org-style attribution; their config_jsonb key names are documented in the GitHub-kind doc.

Dependencies

Depends on #1215. Blocks #1220. Cooperates with #1278.

Metadata

Metadata

Assignees

No one assigned

    Labels

    application-serverSpring Boot server: APIs, business logic, databasebreakingIntroduces breaking API or behavior changespriority:highAddress this sprint - Significant impactrefactorCode restructuring without changing behavior

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions