# Migrating a TopLogic application from 8.0.0-alpha10 to 8.0.0-alpha11

Audience: an AI coding agent (or developer) upgrading a TopLogic application project.
Sources: release notes https://dev.top-logic.com/tl/content/releases/TL_8.0.0-alpha11/ and the
TopLogic Trac tickets of milestone `TL_8.0.0-alpha11` (ticket numbers given as `#NNNNN`; the
per-ticket page is `https://dev.top-logic.com/tl/content/releases/TL_8.0.0-alpha11/NNNNN/`).

## How to use this document

1. Work through the sections in order. Section 1 first (the project must build); the rest in any order.
2. Every step has a **Detect** line: run the search in the application's source tree. No hit → the
   step does not apply, skip it. Do not invent changes for steps that do not apply.
3. Many changes surface only as **configuration errors at application start or when a view is
   loaded**. After migrating, start the application, log in, open every view, and read the log.
4. The engine ships developer articles in its jars (`META-INF/tl-docs/**/*.md`). If the `tl-mcp`
   tools are available, read them with `read_doc` (names given as `doc:<name>`).
5. If the application comes from TopLogic 7.10 / 7.11, follow the upgrade guide `doc:upgrade-7.11-to-8.0`
   first (#29790); it covers all 8.0 changes in the required order and needs **Maven 3.8.9 or newer**.
6. If you continue to 8.0.0-alpha12 afterwards: alpha12 changes view scripts again (named arguments,
   no lambda heads, see the alpha11→alpha12 guide). Still do the alpha11 steps first; they are the
   basis of the alpha12 rules.

Search commands assume the project root as working directory and GNU grep.

---

## 1. Build, wrapper generation, Java API

### 1.1 Version bump
Set the TopLogic version to `8.0.0-alpha11` (parent `tl-parent-app` / `tl-parent-core` version, or
the `tl.version` property).

### 1.2 Snapshot repository (#29789) — only for SNAPSHOT versions
`tl-parent-all` no longer declares the TopLogic snapshot repository. An application inheriting the
TopLogic parent POMs and building against a TopLogic **SNAPSHOT** from the TopLogic Nexus must declare it
itself (archetype-generated applications already do). Released versions need no change.
```xml
<repositories>
  <repository>
    <id>tl-snapshots</id>
    <url>https://dev.top-logic.com/nexus/repository/toplogic-snapshots/</url>
    <releases><enabled>false</enabled></releases>
    <snapshots><enabled>true</enabled></snapshots>
  </repository>
</repositories>
<pluginRepositories>
  <pluginRepository>
    <id>tl-snapshots</id>
    <url>https://dev.top-logic.com/nexus/repository/toplogic-snapshots/</url>
    <releases><enabled>false</enabled></releases>
    <snapshots><enabled>true</enabled></snapshots>
  </pluginRepository>
</pluginRepositories>
```
Detect: `grep -n -e 'SNAPSHOT' -e 'tl-snapshots' pom.xml */pom.xml`

### 1.3 Regenerate the Java wrappers (#29806, #29807) — mandatory if the app uses generated wrappers
Run the wrapper generation (`tl:generate-java` / the module's generate step) for all application modules,
then fix compile errors:
- **#29806:** after regeneration, a class that does **not** specialize `tl.element:StructuredElement`
  gets `AttributedWrapper` as implementation base (before: every top-level class of a module with a
  singleton extended `StructuredElement`). Code treating such objects as `StructuredElement` (casts,
  `getParent()`, `getChildren()`) no longer compiles → correct the code, or let the model class declare
  the `tl.element:StructuredElement` generalization it relied on. The `XImpl` of a class whose primary
  generalization is a concrete or bound type now extends that type's implementation class (hand-written
  code unaffected).
- **#29807:** factory members for classifier constants are deprecated (still compile). After
  regenerating, replace their uses (optional, recommended):

| Old (deprecated) | New |
|---|---|
| `MyFactory.MY_MODULE_STRUCTURE` | `MyFactory.MY_MODULE_MODULE` |
| `MyFactory.KO_NAME_A` | `A.TABLE_NAME` |
| `MyFactory.MY_ENUM_ENUM` | `MyEnum.TYPE_NAME` |
| `MyFactory.FIRST_MY_ENUM_CLASSIFIER` | `MyEnum.FIRST_CLASSIFIER` |
| `MyFactory.getMyEnumEnum()` | `MyEnum.type()` |
| `MyFactory.getFirstMyEnumClassifier()` | `MyEnum.firstClassifier()` |

  A factory that did not compile because of colliding classifier names compiles after regeneration
  (colliding legacy aliases are not generated).

Detect: `grep -rln -e 'StructuredElement' -e 'getParent()' -e 'getChildren()' --include=*.java src` and
`grep -rn -E '[A-Z][A-Za-z]*Factory\.(KO_NAME_|[A-Z_]+_(ENUM|STRUCTURE|CLASSIFIER)\b|get[A-Za-z]+(Enum|Classifier)\()' --include=*.java src`

### 1.4 Wrapper hierarchy clean-up (#29840) — Java
- Calls to deleted members of `AbstractWrapper`, `StructuredElementWrapper`, `WrapperFactory` no longer
  compile (they had no engine callers) → use the replacement or remove.
- `touch()` → `TLObject.tTouch()`.
- `handleLoad()`, `handleDelete()`, `notifyUpcomingDeletion()` are public interface methods of
  `WrapperLifecycle`: overrides in application code must be declared `public`.
- `resolveWrappers`, `resolveWrappersTyped`, `resolveLinks`, `updateOrderedLinkSet` are public `Wrapper`
  defaults; typed accessors (`getString(String)`, …) and the `AbstractBoundWrapper` methods are no longer
  `final`. Overrides of `getValue(String)` / `setValue(String, Object)` or `tValue` / `tUpdate` keep working.
- `instanceof AbstractBoundWrapper` → `BoundObject` / `BoundWrapper`; `instanceof AbstractWrapper` → `Wrapper`.

Detect:
```
grep -rn -e 'touch()' -e 'handleLoad()' -e 'handleDelete()' -e 'notifyUpcomingDeletion' \
  -e 'instanceof AbstractBoundWrapper' -e 'instanceof AbstractWrapper' --include=*.java src
```

### 1.5 `SimpleDBExecutor` (#29838) — Java, rare
The unused methods `beginTransaction(CommitHandler)`, `releaseCommitContext()`, `beginWithDefaultKB()` are
removed; a `SimpleDBExecutor` only works with its own transaction started by `beginTransaction()`.

Detect: `grep -rn -e 'releaseCommitContext' -e 'beginWithDefaultKB' -e 'SimpleDBExecutor' --include=*.java src`

---

## 2. Server configuration

### 2.1 Access parent in the security configuration (#29760) — mandatory if used
(Has a migration section in Trac but is not listed on the release-notes website.)
The access parent of a type is no longer set by the attributes `access-parent` / `access-reference` of a
`<class>` entry of `SecurityConfigurationService`, but by an element `<access-parent>` with exactly one
definition. The old attributes are rejected at startup.

| Old | New |
|---|---|
| `access-parent="container"` | `<access-parent><container/></access-parent>` |
| `access-parent="container" access-reference="X"` | `<access-parent><container reference="X"/></access-parent>` |
| `access-parent="target" access-reference="X"` | `<access-parent><target reference="X"/></access-parent>` |
| `access-parent="self"` | `<access-parent><self/></access-parent>` |
| `access-parent="auto"` | remove the attribute |

Also check `WEB-INF/autoconf/com.top_logic.model.security.SecurityConfigurationService.config.xml` (the
"Access rights…" dialog of the coverage view writes there). Java: record `TypeCoverage` holds the origin
of the marks (`withoutSecurityOrigin`, `internalOrigin`) instead of booleans; `withoutSecurity()` and
`internal()` remain. New in this release: a TL-Script function can determine the access parent.

Detect: `grep -rn -e 'access-parent=' -e 'access-reference=' -e 'TypeCoverage' .`

### 2.2 OpenAPI server: request body validation (#29785)
Requests whose body does not match the declared schema (incomplete `properties` with
`additionalProperties: false`, wrong `required` lists, wrong types) are now answered with **400**. A schema
that cannot be translated **prevents the OpenAPI server from starting**. Fix the schema in the OpenAPI
server's service configuration to match the actual values, or remove the schema from the parameter if no
validation is wanted. Test every operation with real requests.

Detect: `grep -rln -e 'OpenApiServer' -e 'request-body' -e 'additionalProperties' --include=*.xml .`

### 2.3 OpenAPI server: empty passwords / API keys (#29784) — no RequiresMigration flag
Basic authentication (technical user) and API-key authentication now ignore a secret with an empty
password / key (error in the log naming domain and user/parameter) and always reject requests with an
empty password/key. If an environment variable behind an alias is unset (e.g. `${env:api_passwd}`), the
operation is no longer reachable (500, missing-secret message) instead of being open. Make sure all
deployment environments set these variables.

Detect: `grep -rn -e 'basic-auth-server-secret' -e 'api-key-server-secret' -e '\${env:' .`

### 2.4 Encrypted configuration values (#29788, #29849) — check, no mandatory step
- A plain-text value in an `@Encrypted` property without the prefix `unencrypted:` fails as before, but
  the error message no longer contains the value.
- New encrypted values are written in a new format (prefix `{gcm}`); an invalid value in this format is a
  configuration error. Values without prefix are still read with the old method — no migration needed.
- If startup now fails with an "undecodable value" error for a property, add `unencrypted:` to plain-text
  values (typically passwords coming from an environment variable via an alias) or encrypt them properly.

---

## 3. React views (`*.view.xml`)

### 3.1 Unified drag and drop (#29776) — mandatory if the views use `<drag>`/`<drop>`
- `<drag type="module:Type">` no longer exists → `<drag kind="…">` with a freely chosen name (e.g. `ticket`).
- `<drop accept="…">` names drag **kinds**, not model types: replace `accept="module:Type"` by the kind of
  the matching `<drag kind>`, or omit `accept` to accept every drag. A restriction to a model type (before:
  including subtypes) moves into `refuse-if`, e.g.
  ``objects -> !$objects.filter(o -> !$o.instanceOf(`module:Type`)).isEmpty()`` (the type literal needs
  both backticks; the published release notes lost the closing one).
- `refuse-if` receives the dragged objects as **first** argument: `target -> objects -> …` becomes
  `objects -> target -> …`. Per drop kind (`target` attribute of `<drop>`):

| Element | `target` | Meaning | `refuse-if` arguments | Channels |
|---|---|---|---|---|
| `<table>` | `table` | onto the table as a whole | `objects -> target -> reason` (target = null) | `target-channel` |
| `<table>` | `row` | onto a row | `objects -> target -> reason` | `target-channel` |
| `<table>` | `ordered` | between rows (insertion line); beside the rows = at the end | `objects -> before -> reason` | `before-channel` |
| `<tree>` | `tree` / `node` / `ordered` | as above; `ordered` = between siblings or as child | `objects -> parent -> before -> reason` (ordered) | `parent-channel`, `before-channel` |
| `<tree-table>` | `table` / `row` / `ordered` | as for the tree | as for the tree | as for the tree |

  A script with fewer parameters ignores the rest (`objects -> reason` is enough). Misplaced options
  (e.g. `target-channel` with `ordered`, `parent-channel` in a flat table, `target-executability` outside
  `row`/`node`) are configuration errors.
- Several `<drop>` on one element are checked in **declared order** (before: row drops before table
  drops) → reorder mixed drops if needed.
- Java: `DropTarget#dropOnRows()` → `dropModes()`, `acceptedTypes()` → `acceptedKinds()`,
  `check(DropEvent)` → `check(DropRequest)`, `DragSourceControl#dragType()` → `dragKind()` /
  `isDragEnabled()`; `DropEvent` carries a `DropLocation` instead of target and `DropPosition`
  (`DropPosition` removed).

Detect:
```
grep -rn --include=*.view.xml -e '<drag' -e '<drop' -e 'refuse-if' .
grep -rn --include=*.java -e 'dropOnRows' -e 'acceptedTypes' -e 'DropEvent' -e 'dragType()' -e 'DropPosition' .
```

### 3.2 `<adaptive-detail>` (#29801)
- Attribute `detail-size` of `<adaptive-detail>` is renamed `drawer-size`.
- Content inside `<selector>` / `<detail>` that stores personalization (e.g. table column widths) uses a new
  personalization key; stored values are lost once (inform the user, nothing to migrate).

Detect: `grep -rn --include=*.view.xml -e 'detail-size' .`

### 3.3 `<text>` tone and text classes (#29821)
- `<text tone="accent">` no longer loads (ConfigurationException listing allowed values) → use
  `css-class="tl-type-body-strong"`.
- `css-class="tlText--strong"` has no effect → `tl-type-body-strong` (label variant: `tl-type-label-strong`).

Detect: `grep -rn --include=*.view.xml -e 'tone="accent"' -e 'tlText--strong' .`

### 3.4 `<value-input>` with `<on-submit>` (#29808) — behavior change, no RequiresMigration flag
New attribute `submit-on` decides when the `<on-submit>` command of a typed input runs. Text and number
inputs are unchanged (Enter). **Multi-line text, password and I18N text inputs with `<on-submit>` ran on
every value change before; without `submit-on="change"` they now run only on their Enter gesture
(password) or not at all (multi-line text, I18N text).** Add `submit-on="change"` where the old behavior is
needed (the "Apply with Enter" placeholder then disappears).

Detect: `grep -rn --include=*.view.xml -B3 -A3 '<on-submit' .` (check the input type of each hit)

### 3.5 Column selection state (#29825) — custom code only
The state of `ReactColumnSelectControl` changed. Only relevant for code/adapters reading that state;
opening the dialog is unaffected. Note: the published migration text ("grouping is one value instead of a
flag per entry") describes a superseded design. According to the Trac comments, the dialog that shipped is
a layer panel: a row is handle · name · lock · eye (no checkbox), hidden columns stay in place (dimmed),
the lock freezes a column (same `frozenColumnCount` as the freeze handle in the header), and **grouping is
no longer in the dialog** — it is in the column header's context menu. Inspect the actual state contract
in the engine source before adapting custom code.

Detect: `grep -rn -e 'ReactColumnSelectControl' -e 'TLColumnSelect' .`

---

## 4. Custom React components / component library (#29787)

Only relevant if the application customizes the React client (e.g. `installMui`, own adapter modules).
- `installMui({ replace })` selects atomic parts by **part name**, not control name. An old name fails at
  startup (unknown component). With `replace: 'all'` nothing to do.

| Old name | New part name |
|---|---|
| `'TLButton'`, `'TLToggleButton'` | `'Button'` |
| `'TLCheckbox'` | `'Checkbox'` |
| `'TLTextInput'`, `'TLPasswordInput'`, `'TLNumberInput'` | `'TextInput'` (read-only values: `'FieldValue'`) |
| `'TLOptionChips'` | `'Chip'` |
| `'TLProgress'` | `'ProgressBar'` |
| — (new) | `'MenuTrigger'`, `'DisclosureToggle'`, `'Badge'`, `'Divider'`, `'Spinner'` |

- Own modules replacing `TLButton`, `TLToggleButton`, `TLCheckbox`, `TLTextInput`, `TLPasswordInput`,
  `TLNumberInput`, `TLOptionChips` or `TLProgress` with `replace()` must instead replace the part with
  `replacePart()` and implement its props contract (`ButtonPartProps`, `CheckboxPartProps`, …; see
  `doc:view-layer/parts`). Command, keyboard and visibility logic stay in the control.
- The configured CSS class of text, password and number fields now sits on the outermost element of the
  field (`tl-field-group`), not on the `<input>`: CSS `input.myClass` → `.myClass input`.
- (#29808) The bridge hook `useTLTypingField()` replaces `useTLSubmitOnEnter()` and the MUI-internal
  `useTypingField()`; custom typed inputs using the old hooks must switch.

Detect:
```
grep -rn -e 'installMui' -e 'replace(' -e "'TL\(Button\|ToggleButton\|Checkbox\|TextInput\|PasswordInput\|NumberInput\|OptionChips\|Progress\)'" \
  -e 'useTLSubmitOnEnter' -e 'useTypingField' --include=*.ts --include=*.tsx --include=*.js .
grep -rn -E 'input\.[a-zA-Z_-]+' --include=*.css .
```

---

## 5. Stylesheets: design system waves 3b, 4a, 4b, 4c (#29821, #29836, #29866, #29870)

Only relevant if the application has own CSS (or code) addressing the old `tl*` classes of React
controls. General rule: **states are attributes, not classes** (`aria-selected`, `aria-sort`,
`aria-expanded`, `aria-current`, `data-tl-state`, `data-tl-role`, `data-tl-tone`). The complete old→new
tables are in the design system repository, `docs/migration/altlast.md`, sections "Welle 3b", "Welle 4a",
"Welle 4b", "Welle 4c". Rewrite affected rules against the package classes; do not reintroduce old names.

### 5.1 Table, tree, column selection, text (#29821)
Removed: `tlTableView*`, `tlTreeView*`, `tlColumnSelect*`, `tlColumns*`, `tlText*`, `tlRelativeTime`,
`tl-pill--<role>`, `tl-avatar--category-<n>`, `tl-alert--<status>`, `tl-alert--closable`,
`tl-select__status`. Stylesheets reading `--tl-status-error-border` / `--tl-status-warning-border` see a
darker line in light mode.

### 5.2 Dialog, window, drawer, snackbar, notice bar (#29836)
Removed: `tlDialog*`, `tlWindow*`, `tlDrawer*`, `tlSnackbar*`, `tlNoticeBar*`, `tlOverlay*`,
`tlPhotoCapture__overlay*`.
- Dialog animations: `.tlDialog__backdrop--entering` / `--exiting` → `.tl-dialog[data-tl-state~="entering"]` /
  `[data-tl-state~="exiting"]` (the package ships a fade; override on the same state).
- `--tlSnackbar-bg` / `--tlSnackbar-fg` are gone (snackbar is a tinted alert, `data-tl-role`).
- `.tlOverlay__layer--<anchor>` → `.tl-overlay__layer--<anchor>`.

### 5.3 App shell, app bar, sidebar, bottom bar (#29866)
Removed: `tlAppShell*`, `tlAppBar*`, `tlSidebar*`, `tlBottomBar*`, `tlDrawerToggle`. Small-screen rules read
`[data-tl-display~="compact"]` on `.tl-app-shell` instead of `@media (max-width: 768px)`. Visible: app bar
48px (40 compact), sidebar a modal drawer on small screens, hamburger only on small screens.

### 5.4 Layout containers (#29870)
Removed classes `tlPanel*`, `tlCard*`, `tlStack*`, `tlGrid*`, `tlInset`, `tlBounded`, `tlItem`, `tlDeckPane`,
`tlSplitPanel*`, `tlTileStack*`, `tlWizard*`, `tlAdaptiveDetail*`, `tlViewError*`, `tlHtml__error`; dialog
footer `tl-dialog__footer` is now `tl-button-bar`. Removed custom properties `--page-inset` (insets come from
`tl-inset`, `tl-inset--panel`, `tl-inset--card`) and `--tlGrid-gap`; `--tl-item-index` → `--item-index`.
States: panel `[data-tl-state~="minimized"|"maximized"]`; split pane `[data-tl-state~="collapsed"]`, all
`[data-tl-state~="all-collapsed"]`; tile stack/wizard transitions `[data-tl-state~="entering"|"exiting"|"covered"|"backward"]`;
wizard steps `[data-tl-state~="done"]`, current `[aria-current="step"]`; selected item `[aria-selected="true"]`.

| Old | New |
|---|---|
| `.tlPanel` | `.tl-panel` |
| `.tlPanel--card` | `.tl-panel.tl-card` |
| `.tlPanel__header`, `__title`, `__toolbar`, `__actions` | `.tl-titlebar`, `__title` (h2), `__actions`, `__buttons` |
| `.tlPanel__content` | `.tl-panel__body` |
| `.tlPanel__buttonBar`, `.tl-dialog__footer` | `.tl-button-bar` |
| `.tlCard`, `--outlined`, `--elevated` | `.tl-card` (surface by nesting: `--nested`, `--overlay`; no shadow) |
| `.tlStack`, `.tlGrid`, `--gap-*` | `.tl-stack`, `.tl-grid`, `--gap-compact/default/loose` |
| `.tlInset` | `.tl-inset` |
| `.tlBounded`, `.tlItem`, `.tlDeckPane` | `.tl-bounded`, `.tl-item`, `.tl-deck` |
| `.tlSplitPanel`, `__child`, `__splitter` | `.tl-split`, `__pane`, `__handle` (`role="separator"`) |
| `.tlTileStack`, `__frame` | `.tl-tile-stack`, `__frame` |
| `.tlWizard*` | `.tl-wizard*` |
| `.tlAdaptiveDetail`, `__breadcrumb` | `.tl-adaptive-detail`, `__bar > .tl-breadcrumb` |
| `.tlViewError`, `.tlHtml__error` | `.tl-alert[data-tl-role="error"]` |

Visible changes (expect, do not "fix"): narrower gaps (1rem), untinted panel heads with non-bold 40px
titles, card bodies padded 1rem, no card shadows, split handle as a line (keyboard-movable).

Detect (all of section 5, including `css-class` values in views):
```
grep -rn -E 'tl(TableView|TreeView|ColumnSelect|Columns|Text|RelativeTime|Dialog|Window|Drawer|Snackbar|NoticeBar|Overlay|AppShell|AppBar|Sidebar|BottomBar|DrawerToggle|Panel|Card|Stack|Grid|Inset|Bounded|Item|DeckPane|SplitPanel|TileStack|Wizard|AdaptiveDetail|ViewError)|tlHtml__error|tlPhotoCapture__overlay|tl-pill--|tl-avatar--category-|tl-alert--|tl-select__status|tl-dialog__footer|--page-inset|--tlGrid-gap|--tl-item-index|--tlSnackbar-' \
  --include=*.css --include=*.java --include=*.ts --include=*.tsx --include=*.xml --include=*.html .
```

---

## 6. Further notes (no `RequiresMigration` flag, but possibly relevant)

- **Known regression in alpha11 (#29870 → fixed by #29933 in alpha12):** dragging the handle of a
  `<split-panel>` with the mouse "runs away" (movement accumulates). Keyboard and double-click reset work.
  Probably also affects the split of `<adaptive-detail>`. Not a migration step — do not try to fix it in
  the application; mention it to the user, or move on to alpha12.
- **Maven (#29790, #29789):** Maven 3.8.9 or newer is required. A POM that does not inherit the TopLogic
  parents should pin its build plugins (e.g. `maven-compiler-plugin`, `maven-resources-plugin`); otherwise
  Maven 3.8.x may bind ancient plugin versions.

- **Model patch (#29800):** a class may gain a generalization and override attributes in the same change;
  the generated SQL migration processors now apply `add-generalization` before the overrides. If the
  application worked around this with split migrations, they can stay but are no longer needed.
- **Column type changes (#29846):** `AlterColumnProcessor` / `RecollateStringColumnsProcessor` now work on
  Oracle for columns with content and on MS SQL Server for indexed columns — migrations that failed there
  before can be retried.
- **Table `row-class` (#29815):** new `<table row-class="row -> …">` / `<composition-table row-class=…>`;
  with `<inputs>` the input channel values come first and the row object last. (In alpha12 these scripts
  lose their lambda head.)

---

## 7. Verification checklist

1. Regenerate wrappers, then `mvn clean install` (enable tests if possible).
2. Start the application; read the startup log for configuration errors (`access-parent`, OpenAPI
   schemas, unknown MUI part names, `<text tone>`, `detail-size`, drop configuration).
3. Log in, open every React view; try every drag-and-drop interaction (kinds, order, `refuse-if`).
4. Call every OpenAPI operation with realistic request bodies (400 = schema mismatch); check that
   technical users have non-empty passwords in every environment.
5. Check custom styling visually (tables, trees, dialogs, app shell, panels, cards, split panes, wizard).
6. Report to the user every skipped step and every user-visible effect (lost personalization of
   `<adaptive-detail>` content, changed `<on-submit>` behavior, visual changes).
