The configurator
Pick a product line, select features with live validation against its model, and copy the splent commands that build your product.
Table of contents
The flow
- Choose a product line. The chooser lists every SPL in the marketplace index. A line whose UVL model is not in the index shows a Model not published badge instead of a Configure button.
- Select features. The page renders the model as mandatory features, optional features and alternative groups.
- Validate live. Every change validates the selection against the model again and shows the result, valid or not, and why.
- Copy the commands. A valid selection produces a block of
splentcommands that create and derive the product.
What the page enforces
| Rule | Behaviour |
|---|---|
| Mandatory features | Selected and locked. They are part of every product of the line. |
Requires-constraints (a => b) |
Applied transitively. Selecting a adds b and whatever b implies. Added features carry an amber badge, so you see what the model added and why. |
| Alternative groups | At most one member may be selected (for example one session backend). A group whose members are mandatory needs exactly one, and leaving it empty is a violation. |
Violations are explained in plain language next to the selection (an unknown feature, two members of an alternative group, a required group left empty), so you never have to read UVL to fix one.
The page validates by posting the selection as JSON to /configurator/<spl>/validate. The browser sends no CSRF token with that request, so the configurator exempts this one endpoint from the product’s CSRF protection. Validation changes nothing on the server. It only computes what the selection means and the commands that build it, as the API endpoints of spl_registry and apikeys do.
The command block
A valid configuration ends in the command sequence, ready to copy.
splent product:deselect
splent product:create my_app --spl marketplace_spl --spl-doi <the line's DOI>
splent product:select my_app
splent feature:install splent-io/splent_feature_settings --pinned --version <latest tag>
splent feature:install splent-io/splent_feature_theme --pinned --version <latest tag>
splent feature:install splent-io/splent_feature_auth --pinned --version <latest tag>
...
splent product:resolve
splent product:derive --dev
| Part | Why it is there |
|---|---|
product:deselect |
product:create refuses to run while a product is selected. If SPLENT_APP is exported in your shell, run unset SPLENT_APP first, since product:deselect cannot clear it |
--spl-doi |
Lets an empty workspace find the model. Left out when the index has no DOI for the line |
| The install order | Each feature comes after the features it requires, by the model’s a => b constraints and the requires list of its contract, so feature:install never asks to install a dependency first |
--pinned --version |
The latest released version. When the index knows no version for a feature, as in a --local index, the line uses --editable instead |
feature:install, not feature:add |
It clones each feature that is not in the workspace yet, so the recipe works from an empty workspace |
No line prompts, so the block can be pasted whole. Nothing runs on your behalf and no account is involved.
The product name in the block is the one typed in the name field, rewritten when needed into the nearest name product:create accepts. Letters are lowercased and anything that is not a letter, a digit or an underscore becomes _. A name that starts with a digit gets an app_ prefix (2shop becomes app_2shop), a Python keyword gets an _app suffix (class becomes class_app), and the name of a SPLENT repository gets a my_ prefix (splent_feature_blog becomes my_splent_feature_blog). An empty field gives my_app. When the name changes, a notice under the field says which name the commands use.
Scope of the validation
The configurator validates with its own logic over the index’s parsed model, covering mandatory presence, the transitive closure of a => b constraints and alternative group rules. It does not embed a SAT solver, which keeps the web app light and instant. Flamapy analysis stays in the CLI (product:validate, the spl:* commands) and in UVLHub.
- Only simple implications (
a => b) are understood. Other cross-tree formulas in the UVL are not evaluated. - No cardinality or numeric constraints.
- It sees the index’s parsed snapshot, not the live
.uvl.
The command block ends in product:resolve and product:derive, which validate the configuration against the real UVL model, so the CLI has the final word.