dfd.alftech.space is where the courses I write are listed: two of them exist today, one on Kubernetes and one on Luxembourgish, and both are source code you clone and run on your own machine rather than a site you log into.
Neither is finished. Every number on this page was counted from the repository it describes, with the commands printed at the bottom; where a count disagrees with the project's own README, the counted number is the one shown here. Each course also lists what is broken in it today, in the words I would use in a code review.
Both repositories are private right now, so this page does not link into them — those URLs 404 for anyone who is not on the repository. The paths are printed below as text; write to a@alftech.space and I will add you.
Courses
KubeLearn — Kubernetes
Not ready to learn from
An interactive Kubernetes course in the Duolingo shape: a path of units, short lessons, a few questions after each one, XP and a daily streak. Node, Express and SQLite on the back, React and Vite on the front. It runs, it looks finished, and it currently teaches wrong associations — see the defects.
Units
14
Lessons
81
Questions seeded
116
Questions written
122, of which 6 are silently dropped
Lessons with no question
10
Questions per lesson
1 to 3
Question types
4: multiple choice, fill in the blank, true/false, code
Pass mark
70% of a lesson's questions
Known defects
75 of the 116 seeded questions (65%) sit on the wrong lesson. Questions reference lessons by array position, and the question file was written against an intended 84-lesson layout; only 81 lessons exist, so everything after the first short unit is shifted and the drift compounds. A Helm question is graded inside the storage lesson.
10 lessons can never be completed. With no questions, the score is 0/0, which is NaN, which fails the 70% check. They are dead ends in the path — including Container Networking and Container Volumes, both in the very first unit.
The answers are shipped to the browser. The lesson endpoint returns each question's correct answer before you have answered it.
Code exercises are graded by exact string comparison.kubectl get pods --selector=app=nginx is marked wrong; only -l app=nginx passes.
The production build fails on two TypeScript errors, so only the dev server runs. A page refresh also logs you out, because the route guard redirects while the profile request is still in flight.
Run it
git clone git@github.com:alexff91/learn-kubernetes.git
cd learn-kubernetes/backend && npm install && npm run build && npm start
cd ../frontend && npm install && npm run dev # http://localhost:3000
The backend defaults to port 5000, which macOS holds for the AirPlay receiver; change it in backend/.env and in the proxy in frontend/vite.config.ts first. npm run build in the frontend exits 2 — use the dev server.
Source: github.com/alexff91/learn-kubernetes — private, and not linked, because the URL 404s without access. Ask for access.
Learn Luxembourgish
Not ready: builds for no platform
A Flutter app for Luxembourgish, pointed at the Sproochentest: four levels from A-1 to A3, an offline vocabulary where every word carries a pronunciation hint and English, German and French, and a genuine SM-2 spaced-repetition implementation behind the review queue. The vocabulary is the asset here; the shell around it needs two mechanical fixes before anyone can open it.
Levels
4: A-1, A1, A2, A3
Units
32
Lesson nodes
202
Vocabulary
602 words, all 602 with pronunciation, English, German and French
Categories
34
Phrases
38
Grammar
12 lessons, 25 exercises (2 lessons have none)
Hand-written questions
42: 25 grammar, 9 exam, 8 story
Sproochentest drills
3 listening passages, 6 speaking prompts
Stories
4, with 8 comprehension questions
Known defects
202 lesson nodes is a count of buttons, not of written exercises. Tapping a node generates a lesson by shuffling that unit's word list, so the eight nodes of a unit draw from the same pool. The hand-written total is the 42 above.
It builds for nothing as cloned. The Android folder has no gradle files and fails on the deleted v1 embedding; there is no web folder at all.
Once the web target is created, the page loads blank. Storage init calls sqflite, which has no web implementation, and it throws before the app is mounted. Guarding that one call makes the whole app render.
The LOD.lu dictionary integration is dead. Every documented endpoint answers 404, the browser blocks the remaining one on CORS, and the importer that is supposed to bundle extra vocabulary discovered 0 lemmas over 144 seeds.
Listening drills have no audio in all three passages, no word carries an audio id, and the listening question type returns a plain multiple-choice question.
18 achievements are computed and never shown.Achievements.all holds 18 entries and the progress provider evaluates every one of them, but nothing renders that list: the Profile tab has an Achievements card which hardcodes three rows of streak and XP counters instead, and no achievements screen exists. Its own CI command, flutter analyze, exits 1. FEATURES.md describes an earlier, different app: 18 categories, 1,125 words, Firestore sync, a bundled font and audio comprehension, none of which are in the code.
Run it
git clone git@github.com:alexff91/learn-luxembourgish.git
cd learn-luxembourgish && flutter pub get
flutter create . --platforms web # the web target is not committed
flutter build web --release # 253s, 3.1MB of main.dart.js
The built page is blank until the storage init call in lib/main.dart is guarded. With that one line changed it renders and plays: word of the day, the unit path, the word-match game, the offline dictionary.
Source: github.com/alexff91/learn-luxembourgish — private, and not linked, because the URL 404s without access. Ask for access.
Not a course
learn-elastic
Not listed above
A third repository has an Elastic-flavoured name and is not a course: 3 study paths, 0 lessons, 0 questions. It is a study-hours tracker with a title, a hero line and a footer that mention Elastic; nothing in it teaches anything, so it is named here rather than dressed up as a third course.
How these numbers were counted
Run from a clone of each repository. Both scripts parse the seed files and evaluate the array literals, rather than trusting the README.
# KubeLearn
node count_content.js learn-kubernetes
UNITS : 14
LESSONS : 81
QUESTIONS (objects in seedQuestions.ts): 122
lessons with ZERO questions : 10
questions dropped at seed time (lesson_idx out of range): 6
node count_misplaced.js learn-kubernetes
actually seeded : 116
on the lesson they were written for : 41
on a DIFFERENT lesson : 75 (65% of seeded questions)
# Learn Luxembourgish
grep -c "LevelUnit(categoryId:" lib/data/level_data.dart # 32
grep "LevelUnit(categoryId:" lib/data/level_data.dart \
| grep -oE "lessonCount: [0-9]+" | awk -F': ' '{s+=$2} END {print s}' # 202
grep -o "WordModel(" lib/data/vocabulary_data.dart \
lib/data/vocabulary_extended.dart | wc -l # 602
grep -o "ipa: '" lib/data/vocabulary_*.dart | wc -l # 602
grep -o "WordModel(" lib/data/phrases_data.dart | wc -l # 38
grep -o "GrammarExercise(" lib/data/grammar_*.dart | wc -l # 25
# learn-elastic
grep -c "targetHours:" src/main.js # 3
grep -riE "lesson|quiz|question|answer|exercise" src index.html | wc -l # 0