← All posts

Our course sequencing has exactly one rule, and no way to turn it off

A learning pathway in Klaas is an ordered list of your courses. Put a member on it and they work through the list in order: course two is locked until course one reads 100% complete, course three until course two does.

That is the entire feature. What is interesting is everything we did not build around it.

No configuration

There is no setting for how much of the previous course counts as "enough". No 80% option, no "require the final quiz only", no per-course override, no "unlock after 7 days regardless".

Each of those is a reasonable request and we will probably be asked for all of them. The reason to resist is that the moment sequencing is configurable, the pathway stops being a promise and becomes a puzzle. A member cannot see the configuration. All they see is a padlock, and a padlock whose rule varies by course is indistinguishable from a bug. "Why is this one locked when the other one wasn't?" is not a question a learner should ever have to hold.

The order you put the courses in is the rule. That is the whole design.

No exemption for the host

Hosts are not exempt. If you build a pathway and assign yourself to it, your second course is padlocked until you finish your first one.

This one gets pushback, so let me defend it properly. The argument for an exemption is obvious: it is your content, you wrote it, you should not have to click through your own lessons to check the third one renders.

The argument against is that an exemption makes the lock untestable by the person responsible for it. If the padlock never appears for you, you cannot see what your members see, cannot check that your lock-screen copy makes sense, and cannot notice that you accidentally ordered the courses backwards. Every host-exemption I have seen in access control eventually produces the same bug report: "a member says it's locked but it works fine for me."

If you need to review a later course, take yourself off the pathway. That is two clicks and it is honest.

No member-facing pathway page

This surprises people. There is no /pathways route for members. A member on a pathway never sees a pathway.

What they see is a Learning Pathway badge on each course in it, and a padlock on the ones that are not open yet. That is all.

The reasoning: a pathway is a mechanism, not a destination. Giving it a page invites a member to go there, look at a list of locked things, and feel behind. The course catalogue already answers the only questions they have — what can I do now, what have I finished — and a second screen showing the same information as a progress bar with locks on it adds anxiety and no capability.

There is a real cost to this, and I will name it: a member who does not know pathways exist can be confused about why a course is locked. That is what the lock screen's copy is for, and it is worth writing carefully.

The lock is enforced three times, from one expression

The padlock the browser draws is the least important of the three.

  1. The course outline returns zero rows for a barred course. Not a course object with a locked: true flag for the front end to respect — nothing.
  2. A database trigger refuses the enrolment, with a specific error code, so a request that skips the UI entirely is refused at the last possible layer.
  3. The interface reads the same projection and draws the padlock, and is forbidden from re-deriving lockedness itself.

That third point is the one that keeps this honest over time. If the UI could compute "is this locked" from data it happens to have, then one day it would compute it slightly differently from the database, and the two would disagree. The disagreement would not throw an error — it would just quietly let someone in, or quietly keep someone out. We have a test that fails the build if the member-side code so much as names the pathway tables, precisely to stop that shortcut being available.

Two behaviours that are not obvious and are deliberate

The lock gates entry. It never evicts. If a member is already enrolled in a course, assigning them to a pathway does not throw them out of it, even if the pathway says they should not be there yet. An earlier version did exactly that: reordering a pathway could remove somebody mid-lesson. A rule that can eject a person from something they are in the middle of is not a sequencing rule, it is a trap.

It fails open. If the check cannot run — a transport error, a timeout — a course is treated as not in a pathway rather than locked. This is a deliberate asymmetry, and it is the correct one for this feature: a pathway is a sequence, not an entitlement. Failing closed on an entitlement protects revenue. Failing closed on a sequence means one bad database moment padlocks a member's entire catalogue for no reason. The worst case of failing open is that somebody starts course three early. The worst case of failing closed is that everyone's library goes dark.

Knowing which way each check should fall over is most of the work in access control, and the answer is different per feature. Anyone who tells you "always fail closed" has not had to explain a blank catalogue to a paying member.

When to use one

Pathways are worth it when the order genuinely matters — a foundations course that later courses assume, a certification with prerequisites, an onboarding sequence.

They are worth avoiding when your courses are a library people should browse. Sequencing a catalogue that does not need sequencing is a good way to make a member who wanted one specific thing bounce off three padlocks and leave.

If you are unsure, the tell is this: would you be comfortable telling a member "do these in this order" out loud, in a sentence? If yes, a pathway is just that sentence, enforced. If you find yourself explaining exceptions, you do not want a pathway — you want a well-written course catalogue.