
What if you could take the Reading section from an IELTS practive test, combine it with the Writing section from a different test, and create a custom exam without duplication any questions?
That's the Package Combiner. And its database design is the most elegant patter in our entire code base.
In Labas, a "package" is a collection of exam sections (Reading, Writing, Listening, etc.) with questions. Users can create packages from the question bank or generate them with AI. But what if a user wants:
Without a combiner, the user would need to create three separate exam sessions. With a combiner, they create one custom package that remixes sections from different sources.
It's like Spotify playlists: you don't need to own the songs you just need to reference them in a new order.
The combiner uses two tables:
But it also create a shadow testPackage record:
Why two tables? Because the rest of the application the package listing page, the exam interface, the analytics dashboard all expect a testPackage record. The comboPackage is a logical grouping; the shadow testPackage is a physical record that makes combos appear alongside regular packages.
The create mutation in packages/api/src/routers/combo.ts does four things:
This is the logical grouping the "playlist" record.
Each comboSection record points to a source section in a source package. No questions are copied just references.
The exam type is derived from the first source package. If a user combines an IELTS Reading section with an IELTS Writing section, the combo is an IELTS package. The estimated duration is sections.length * 20 minutes a simple heuristic that gives users a realistic expectation.
This step copies the sectionQuestion associations into the shadow testPackage. The questions themselves aren't duplicated only the many-to-many join records. This means if a source question is edited, the combo automatically reflects the change.
Finally, the totals are updated:
When a user views a combo package during an active exam attempt, the answers must be hidden. The getById query handles this with strupAnswer():
The stripAnswer utility removes correctAnswer and explanation from any question object. Owners see full questions; test-takers see questions without answers. This applies to both regular packages and combos the same anti-cheat logic works for both because the shadow testPackage makes them structurally identical.
The combiner UI needs to show users which sections are available to combine. The availableSections query returns packages and their sections:
The UI renders this as a two-panel interface: left panel shows packages, right panel shows sections from the selected package. Users click sections to add them to thier combo, then reorder them with drag-and-drop.
Here's where the combiner gets interesting. A user could combine:
The result is a multilingual practice session something no single exam package could provide. The combiner doesn't restrict sections to the same exam type; it just derives the exam type from the first source package for categorization purposes.
This flexibility is intentional. Language learners often study multiple languages simultaneously. A student preparing for both IELTS and JLPT might want to practice reading comprehension in both languages in a single session. The combiner makes this possible.
The Package Combiner demonstrates a generalizable pattern: when a new concept is conceptually different but functionally similar to an existing entity, create a parallel table for the conceptual difference and a bridge record for functional compatibility.
In our case:
This pattern appears in many systems:
The key is recognizing when two concepts need separate tables for clarity but shared functionality for usability