Add Product
Select the items this product covers — at least 1 item must be selected in total (from Courses + Special Programs + Tags).
Screen Flow (from uc-bil-07-manage-product.flow.puml):
📝 Spec notes — UC-BIL.07 / SCR-BIL.09 (fields, actions, requirements)
- Screen: SCR-BIL.09 — Product Form
- Use case: UC-BIL.07 — Manage Product
- Primary actor: Sale Admin (ACT-12)
Form for creating or editing a Product in the Billing catalog — mode determined by URL parameter (create | edit). Three core fields (name, type, price) plus four multi-select pickers (Central Courses, Institute Courses, Special Programs, Tags) that lazy-load from LMS Core API; at least 1 item must be selected in total. Tags picker displays tags grouped by TagGroup with group-level select/deselect and autocomplete. In edit mode a Status field (active/inactive) is also shown. When editing a Product that has active subscriptions, a blocking dialog requests confirmation before save. Validation errors shown inline per field.
product_name"Product Name" — text ·Product.name· required · min 1 / max 255 chars · fallback ""product_type"Type" — enum (lifetime / period) ·Product.type· required · fallback ""price"Price (LAK)" — number ·Product.price· required · min 1 · fallback ""product_status"Status" — enum (active / inactive) ·Product.status· required when mode == edit · visible when mode == edit · fallback: activelinked_central_courses"Central Courses" — multi-select ·Product.linked_central_courses· lazy-loaded from LMS Core API · shared-visibility active InstituteCourses only · fallback []linked_institute_courses"Institute Courses" — multi-select ·Product.linked_institute_courses· lazy-loaded from LMS Core API · institute-only active InstituteCourses only · fallback []linked_special_programs"Covered Special Programs" — multi-select ·Product.linked_special_programs· lazy-loaded from LMS Core API · active special programs only · fallback [] (SpecialProgram entity pending /analyze-entities)linked_tags"Covered Tags" — multi-select ·Product.linked_tags· lazy-loaded from LMS Core API · grouped by TagGroup · fallback [] (TagGroup entity pending /analyze-entities)lms_load_status"LMS load status" — enum (loading / loaded) · computed on screen load · read-only · drives the loading indicator while pickers lazy-loadactive_subs_warning_message"Edit warning message" — computed text · visible when mode == edit && save_triggered && active_subs_count > 0 · read-only · "This product has N active Subscriptions. Changes will not affect existing subscriptions."
save"Save" — enabled when required_fields_valid && lms_load_status == loaded && (linked_courses + linked_special_programs + linked_tags).length > 0 · triggers UC-BIL.07-M-4 (create) or UC-BIL.07-A-2A-3 (edit)confirm_edit"Confirm" — always enabled (in edit warning dialog) · triggers UC-BIL.07-A-2A-5 · visible only when active_subs_warning_message dialog is showncancel"Cancel" — always enabled · returns to SCR-BIL.08 (Product List)
- Validation errors shown inline beneath each invalid field immediately — do not use page-level banner for field errors. (AF-5A) [refs: NFR-04]
- LMS pickers show a loading indicator during lazy-load. [refs: NFR-02]
- Edit warning dialog (active_subs_warning_message) is a blocking modal — focus trapped inside; backdrop click does not dismiss; exit via "Confirm" or "Cancel" only. [refs: NFR-09]
- AF-5B (LMS items invalid): highlight each invalid item inside its picker with a per-item error message — do not use separate error list outside the picker. [refs: —]
- Covered Tags picker displays tags grouped by TagGroup; selecting a group header auto-selects all tags in that group; deselecting group header deselects all; autocomplete searches both group name and tag name. [refs: —]
- Product schema (multi-link lists) conflicts with entities.puml and UC-BIL.01 data_touched (old link_type/link_ref single-link) — awaiting /analyze-entities reconcile.
- SpecialProgram + Tag entities not yet registered in LMS Core entities.puml — /analyze-entities must add them.
- Price/type change on a Product with active Subscriptions — current design: "no impact (snapshot pricing stored in Transaction)" — awaiting DTVE confirmation.