Skip to content

refactor(learningpath-api): move learningsteps into learningpath document#877

Merged
jnatten merged 3 commits intomasterfrom
refactor/move-learningsteps-into-path-table
Feb 26, 2026
Merged

refactor(learningpath-api): move learningsteps into learningpath document#877
jnatten merged 3 commits intomasterfrom
refactor/move-learningsteps-into-path-table

Conversation

@jnatten
Copy link
Contributor

@jnatten jnatten commented Feb 18, 2026

Denne ble større enn jeg så for meg, så hadde satt pris på om dere også testet denne litt! Hadde ikke blitt overrasket om det ikke var noe jeg ikke har tenkt på.


This is part 1 of 3 in a stack made with GitButler:

…ument JSON

Migrate learning step persistence from the separate `learningsteps` table
into the `learningpaths.document` JSONB payload, and update read/write
flows, indexing, and tests to operate on embedded steps.

- Add Flyway migration `V60__MoveLearningStepsToLearningPathDocument` to:
  - read existing path + step rows
  - enrich step documents with `id`, `revision`, `learningPathId`, `externalId`
  - embed sorted steps into each learning path document
  - delete migrated rows from `learningsteps`
- Add migration `V61__AddStepIdIndex.sql` with a GIN index over embedded
  step IDs to keep step lookup performant.
- Refactor `LearningPathRepository` to use `learningpaths.document` as the
  source of truth for steps:
  - fetch steps from embedded JSON
  - update step operations by rewriting the path document
  - assign path IDs + step IDs from existing sequences on insert
  - support imported step IDs while advancing sequence safely
  - add raw/non-filtered read helpers where deleted steps must be preserved.
- Update `UpdateService` to:
  - operate on embedded steps for create/update/delete/seqNo/status actions
  - enforce step-level optimistic locking via revision checks
  - increment step revisions when mutating embedded steps
  - preserve deleted steps in persistence while exposing active-only views
  - index/search using active steps only.
- Update `ConverterService` and search converters:
  - treat `learningsteps` as a required sequence
  - keep API conversion behavior compatible
  - filter to active steps for search indexing payloads.
- Adjust internal endpoints and insert flow to return `Try`-based results for
  unified Tapir error handling.
- Update model contract in `common`:
  - `LearningPath.learningsteps` is now `Seq[LearningStep]` (not `Option`)
  - JSON encoder/decoder now include `learningsteps`
  - add `withOnlyActiveSteps` helper on `LearningPath`.
- Refresh integration/unit/e2e tests and test data across modules to match
  embedded-step persistence and new revision semantics.

wip
@jnatten jnatten force-pushed the refactor/move-learningsteps-into-path-table branch from 82aa663 to b375bc9 Compare February 18, 2026 11:11
@gunnarvelle
Copy link
Member

gunnarvelle commented Feb 19, 2026

Tester i lokal k3d, og sletting av steg oppdaterer ikkje forhåndsvisninga umiddelbart.

  • Opprett eller oppdater en sti med x antall steg
  • Sjekk at alle steg er i forhåndsvisning
  • Gå tilbake og slett et av stega
  • Sjekk forhåndsvisning at steget fremdeles ligger der. F5 fjerner ikkje steget.

Det må være cache for eg ser ikkje at stien hentes på nytt fra backend ved henting av sida på nytt og heller ikkje med disableSSR=true.

@jnatten
Copy link
Contributor Author

jnatten commented Feb 19, 2026

Det må være cache for eg ser ikkje at stien hentes på nytt fra backend ved henting av sida på nytt og heller ikkje med disableSSR=true.

Hmm, testa om det oppfører seg annerledes i test?

@gunnarvelle
Copy link
Member

Oppførte seg visst likt der.

@jnatten jnatten force-pushed the refactor/move-learningsteps-into-path-table branch from b375bc9 to 6b50cc7 Compare February 19, 2026 09:40
@jnatten jnatten requested a review from a team February 19, 2026 10:35
oldLp.mapObject(_.remove("learningsteps").add("learningsteps", Json.fromValues(updatedSteps))).noSpaces
}

private def deleteSteps(learningPathId: Long)(using session: DBSession): Unit = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dette gjør at migreringa ikkje kan kjøres om igjen dersom den skulle feile. Kanskje heller ha en egen migrering i etterkant som berre dropper tabellen?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vil ikke en feil rulle tilbake migreringa?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ja det kan vi godt gjøre 😄

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vil ikke en feil rulle tilbake migreringa?

Om det er en feil som kastes så, men om det er en logisk feil e.l som vi ikke har tenkt på så vil det jo potensielt commites.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ja sant

@jnatten jnatten force-pushed the refactor/move-learningsteps-into-path-table branch from 6b50cc7 to a02369a Compare February 20, 2026 09:11
Copy link
Member

@gunnarvelle gunnarvelle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Har testa dette både fra min ndla og ed i lokalt cluster, så funksjonelt fant eg ingen problemer. @amatho er ofte nøyere enn meg på kode, så fint om du også approver.

Copy link
Member

@gunnarvelle gunnarvelle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glømte sjølve approve

oldLp.mapObject(_.remove("learningsteps").add("learningsteps", Json.fromValues(updatedSteps))).noSpaces
}

private def deleteSteps(learningPathId: Long)(using session: DBSession): Unit = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Vil ikke en feil rulle tilbake migreringa?

val stepWithStatus =
if (isChangedStep) curr.copy(status = newStatus, lastUpdated = now)
else curr
val updatedStep = incrementStepRevision(stepWithStatus.copy(seqNo = seqNo, lastUpdated = now))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Skal revision inkrementeres for alle steps, selv om de ikke er oppdatert status?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For å være ærlig så er jeg ikke helt sikker på hvordan denne burde fungere jeg.
Denne kan jo potensielt endre på sequence number og. Hva tenker du?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm blir kanskje noe som det her hvis vi bare vil endre revision for steps som får endring i enten status eller seqNo?

        val updatedStep =
          if (isChangedStep || stepWithStatus.seqNo != seqNo)
            incrementStepRevision(stepWithStatus.copy(seqNo = seqNo, lastUpdated = now))
          else stepWithStatus

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Joda mer om det er det vi faktisk har lyst til.
Jeg tenker egentlig at enten så må alle revisjoner oppdateres (ellers vil jo låsingen ikke låse så bra om noen oppdaterer et annet steg?).

Evt så må vi kanskje droppe hele learningstep revisjonen og ta i bruk learningpath for hele greia alltid?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Åja tenkte ikke så nøye på at det med låsing er en greie, da er jeg enig med at det er best å bare øke revision på alle

@jnatten jnatten force-pushed the refactor/move-learningsteps-into-path-table branch 3 times, most recently from f8f4ffa to b3a0393 Compare February 23, 2026 09:13
@jnatten jnatten requested a review from amatho February 23, 2026 12:45
…ngpath table

this should make running the migration more robust, as it will not fail if the 
learningstep rows have already been deleted by a previous failed migration attempt.
@jnatten jnatten force-pushed the refactor/move-learningsteps-into-path-table branch from 7ba587c to 5d87a79 Compare February 24, 2026 07:39
@jnatten jnatten merged commit a3ca96c into master Feb 26, 2026
46 checks passed
@jnatten jnatten deleted the refactor/move-learningsteps-into-path-table branch February 26, 2026 09:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants