Appearance
Meduse frontend interface map
This is a source-level map from the visible Vue navigation and registered routes to page actions, frontend requests, and Laravel route/controller declarations. API paths below include Laravel's /api prefix. The frontend base URL is configuration-driven; no environment value is included here.
Active navigation
The menu model is in src/App.vue; src/AppSubmenu.vue renders its links. Menu visibility is not the same as route registration.
| Visible item | Route and view | Main operator actions and request boundary |
|---|---|---|
| Gestion des catégories | /manage-categories → pages/ManageCategories.vue | Select channel/store/device; inspect and edit the category menu, reorder parents/children, hide entries, set menu attributes, upload category images, save, and start a channel-specific export/sync. See category and menu workflows. |
| Liste des produits | /products2 → pages/Products2.vue | Search/filter products, choose displayed attributes, browse category hierarchy, edit grid values, edit names/descriptions, manage associations, families and media, and export the visible table. See product workflows. |
| Vimeo Stories | /vimeo-stories → pages/VimeoStories.vue | Filter/export the product list, edit or restore/delete video records, and request per-product or all-product sync. The menu and router each gate this as Menzzo-only, with a predicate mismatch described below. |
| Processus | /jobs → pages/jobs.vue | Filter/paginate tracked jobs and open a job detail view. The product screen also checks whether work is queued. |
| Attributs | /attributs → pages/Attributs.vue | List, add, edit and remove catalog attributes; detail forms also edit translated option labels and family links. |
| Familles | /families → pages/Families.vue | List, add and edit product families; the product grid has a separate bulk family-assignment dialog. |
| Asir Mapping → Attributs Asir traités | /asir-attributes/processed → pages/AsirAttributes.vue | Review processed ASIR attributes, their Menzzo mappings, families, options, and sample product data. |
| Asir Mapping → Attributs Asir non traités | /asir-attributes/non-processed → pages/AsirAttributes.vue | Review unprocessed ASIR attributes and map or create attributes/options. |
| Sync des Attributs Asir | /sync-asir-attributes → pages/SyncAsirAttributes.vue | Start ASIR synchronization and poll its progress. The UI reports launch and progress; it does not independently verify a downstream consumer. |
The breadcrumb channel dropdown is also an active global interface. It loads GET /api/list-channels-static, writes the selected channel and tenant IDs to local storage, and reloads the app. Channel-aware catalog and menu-manager calls pass the selected channel/store as request data or route parameters. The /administrer-categories tree is an exception: its request omits channel context and the backend handler fixes channelId at 3. The tenant ID is used for the AX-Tenant request header during auth verification, subject to the direct-link ordering noted below.
Registered router paths
All current route declarations are listed below. “Menu” means the route is linked by the current menu model. “Internal” means a component pushes the route from an action. “Route-only” means it is registered but absent from the current menu; known internal links are called out separately. Commented router records are omitted.
| Path | View | Current entry point |
|---|---|---|
/ | components/Dashboard.vue | Route-only default dashboard. |
/categories-old | pages/Categories.vue | Route-only; the corresponding menu entry is commented out. |
/manage-categories | pages/ManageCategories.vue | Menu. |
/administrer-categories | pages/AdministrerCategories.vue | Internal link from category management. |
/products2/:categoryId?/:level? | pages/Products2.vue | Menu; optional category/depth context. |
/products2/:sku | pages/Products2.vue | Direct product-grid link; named Access_to_product_grid_by_link. After auth verification, its guard sets channel 1 and tenant null; see the stale-header note below. The router declares this alongside the optional category route. |
/products | pages/Products.vue | Route-only; the older menu entry is commented out. |
/vimeo-stories | pages/VimeoStories.vue | Menu when shown by App.vue; route has tenantOnly: 'menzzo'. |
/jobs | pages/jobs.vue | Menu. |
/asir-attributes/:status | pages/AsirAttributes.vue | Menu subroutes for processed and non-processed; they map to status values 1 and 0. |
/sync-asir-attributes | pages/SyncAsirAttributes.vue | Menu. |
/job/show/:id | pages/JobDetails.vue | Internal link from a job row. |
/attributs | pages/Attributs.vue | Menu. |
/attribut/edit/:id | pages/AttributDetails.vue | Internal link from the attribute list. |
/attribut/add | pages/AttributDetails.vue | Internal link from the attribute list and settings page. The router declares this same path and name twice. |
/families | pages/Families.vue | Menu. |
/family/edit/:id | pages/FamilyDetails.vue | Internal link from a family row. |
/family/add | pages/FamilyDetails.vue | Internal link from the family list. |
/product/edit/:id | components/productEdit.vue | Internal link from product-list edit actions; currently resolves to a demo form without product request wiring (see gaps). |
/users | pages/Users.vue | Route-only; the menu entry is commented out. It links internally to user add/edit routes. |
/user/edit/:id | pages/UserEdit.vue | Internal link from the user list. |
/user/add | pages/UserEdit.vue | Internal link from the user list. |
/settings | pages/Settings.vue | Route-only; it also links to attribute add/edit routes. |
/invoice | pages/Invoice.vue | Route-only template page. |
/help | pages/Help.vue | Route-only template page. |
/login | pages/Login.vue | Auth entry; the route guard leaves it reachable without authentication. |
/error | pages/Error.vue | Route-only exception page. |
/notfound | pages/NotFound.vue | Route-only exception page; no catch-all route is declared here. |
/access | pages/Access.vue | Route-only access page. |
Category and menu workflows
| Screen action | Frontend request | Laravel route and handler |
|---|---|---|
| Load the menu category tree | CategoryService.getCategoriesMenu() → POST get-categories-menu | POST /api/get-categories-menu → CatalogCategoryController::getCategoriesMenu |
| Load categories available for administration | AdministrerCategories.vue calls GET get-categories-to-administrate with no channel parameter | GET /api/get-categories-to-administrate → CatalogCategoryController::getCategoriesToAdministrate, which hard-codes channelId = 3 |
| Create a category | POST add-new-category | POST /api/add-new-category → CatalogCategoryController::addNewCategory |
| Change parent or parent-category mode | POST update-parent-category, update-categories-to-use-parent-category, or update-categories-to-stop-using-parent-category | Matching routes → CatalogCategoryController::updateParentCategory, updateCategoriesToUseParentCategory, or updateCategoriesToStopUsingParentCategory |
| Rename a category | POST update-category-name | POST /api/update-category-name → CatalogCategoryController::updateCategoryName |
| Load a store-specific category hierarchy | CategoryService.getCategoriesBuilderMenuStore() → GET categories/{categoryId}/{storeId}/hierarchy with optional deviceType | GET /api/categories/{categoryId}/{storeId}/hierarchy → MenuController::getCategoryHierarchyStore |
| Save menu arrangement, visibility, or attribute positions | CategoryService.saveMenu() → POST menu/save-menu | POST /api/menu/save-menu → MenuController::saveMenu |
| Load menu attributes/defaults | GET menu/get-attributes, GET menu/get-default-attribute-ids-to-show | Matching routes → MenuController::getAttributeIds, getDefaultAttributeIdsToShow |
| Upload a menu category image | Multipart POST menu/upload-category-image | POST /api/menu/upload-category-image → MenuController::uploadCategoryImage |
| Synchroniser for Mosaikasa | GET update-shopify-menu | GET /api/update-shopify-menu → CatalogCategoryController::updateShopifyMenu |
| Synchroniser for Make Up | GET update-make-up-menu | GET /api/update-make-up-menu → MakeUpCatalogCategoryController::updateMakeUpMenu |
| Synchroniser for the default Menzzo/Meuble Promo path | GET menu/export-menu-csv with deviceType when there is no tenant | GET /api/menu/export-menu-csv → MenuController::exportMenuToCSV |
The default export controller writes a CSV and calls Queue::push for menu export jobs; the Mosaikasa handler also calls Queue::push for a Shopify menu update. These calls do not by themselves establish an asynchronous handoff: config/queue.php defaults to the sync connection, and the effective environment may select another connection. With sync, the job executes inline before the controller returns; with a worker-backed connection, the controller may return after dispatch and before worker completion. ManageCategories.vue labels the action “Synchroniser” and reports success when the HTTP response is 200. Because the runtime connection and job result are not exposed uniformly, that response alone does not prove the destination imported or rendered the export. Verify job/worker evidence as applicable, then confirm destination consumption. The separate /api/menu/export-menu-json route exists, but the active Vue screen does not call it directly. The Make Up endpoint differs: MakeUpCatalogCategoryController::updateMakeUpMenu invokes Artisan::call('makeup:update-menu') inline, discards the command's return code, and returns a default-200 JSON response if control returns. The response therefore does not establish the command's exit status or a successful Shopify update.
AdministrerCategories.vue handles category creation, parent changes, rename, hide/show, and category-to-product navigation. These actions use the category routes above. ManageCategories.vue handles the channel/store/device-specific menu hierarchy and menu arrangement. Keep those two views distinct when investigating a category issue.
Product workflows
| Screen action | Frontend request | Laravel route and handler |
|---|---|---|
| Load and filter the product grid | ProductService.getAllProducts() → POST list-all-products | POST /api/list-all-products → CatalogProductController::listAllProducts |
| Load grid attributes, locales, channels, families, and types | list-all-catalog-attributes, list-locales, list-channels/{id}, families, list-all-catalog-attribute-groups, all-type-attributes | Matching routes → CatalogAttributeController, CatalogLocaleController, CatalogChannelController, CatalogFamilyController, and attribute group/type handlers |
| Edit product attributes in the grid | POST bulk-update-products | POST /api/bulk-update-products → CatalogProductController::bulkUpdateProducts |
| Save the Excel-like grid | POST bulk-update-products-excel; the screen first requests data with POST get-products-info-excel | POST /api/bulk-update-products-excel → CatalogProductController::bulkUpdateProductsExcel; POST /api/get-products-info-excel → CatalogProductController::getProductsInfoExcel |
| Edit names/descriptions across locales | POST bulk-update-products-names; translation helper uses POST translate | CatalogProductController::bulkUpdateProductsNames; the translate route is an inline handler in routes/api.php |
| Inspect versions and lock selected product rows | POST getListProductVersion, check-for-locked-products, lock-products, unlock-products | Matching routes → CatalogProductController::listVersionByProduct, checkForLockedProducts, lockProducts, unLockProducts |
| Associate or disassociate products | list-type-association, get-related-product, get-product-by-sku, post-product-association, remove-product-association | Matching routes → CatalogProductController association methods |
| Assign families to selected products | POST save-product-families from ProductFamilyManagement.vue | POST /api/save-product-families → CatalogFamilyController::saveProductFamilies |
| Upload/save product images | Multipart POST upload-images, then POST save-images | UploadProductImagesController::saveTmpImages and ::saveImages |
| Upload/save product files | Multipart POST upload-file, then POST save-files | UploadProductFileController::saveTmpFile and ::saveFiles |
| Download a product image archive | GET products/{productId}/images/download-zip | GET /api/products/{product}/images/download-zip → ProductImageDownloadController::downloadZip |
Image removal clears matching image paths from the product's raw_values; removing the GIF, PDF, or video clears the corresponding product field in raw_values. The save handlers update these product references and do not delete the physical media files. The image-save handler returns HTTP 200 with success: false when per-image work partially fails or an exception is caught; validation failures use HTTP 422. The Vue dialog uses the JSON success flag to choose toast severity, so the response body matters in addition to the status code.
The product grid's “Export” button calls the local PrimeVue table exportCSV() method; that click does not call a Laravel export endpoint. The import control beside it is commented out, so this active screen does not expose a file-import action. “Save” in the Excel-like grid is a bulk API update, not evidence of a CSV/XLSX import.
The current Products2.vue edit action pushes /product/edit/:id, but the router mounts components/productEdit.vue, which contains sample form fields and a submit button without reading the route ID or calling ProductService. Treat that route as a placeholder, not as the persistence path for product edits. Grid edits remain on Products2.vue and use the bulk update endpoints above.
Attributes, families, and users
| Screen action | Frontend request | Laravel route and handler |
|---|---|---|
| List/search attributes | POST list-all-catalog-attributes or POST list-Attributes depending on the screen | Matching routes → CatalogAttributeController::listAllCatalogAttributes or ::listAttributes |
| Load/save/remove an attribute | GET get-attributes/{id}, POST save-attribute, POST to-remove-attribute | Matching routes → CatalogAttributeController::getAttributeById, saveAttributes, removeAttribute |
| Read/edit translated option labels | GET get-option-Translate/{id}, POST edit-option-label | Matching routes → CatalogAttributeController::getOptionTranslateById, editOptionLabel |
| List/save families and family choices for attribute editing | POST families, GET family/{id}, POST save-family, GET getAllFamilyForAttr | Matching routes → CatalogFamilyController::index, show, saveFamily, getAllFamily |
| List/create/edit users | POST list-all-users, POST create-user, PUT update-user, GET get-user/{id}, PUT change-password | Matching routes → UserController::listUsers, creatNewUser, updateUser, getUserBuyId, changePasswordUser |
| Configure default product attributes | GET users/assigned-attributes, POST users/assign-attributes, POST users/assign-attributes-without-position | Matching routes → UserController assignment methods |
The /users list and /settings screens are registered but absent from the current menu. They remain reachable by direct route or internal links; their routes should not be presented as currently visible navigation.
Jobs, ASIR mapping, and Vimeo
| Workflow | Frontend request and user-visible status | Laravel route and handler |
|---|---|---|
| Browse tracked jobs | POST list-jobs-tracked from JobsService; the job row opens /job/show/:id | POST /api/list-jobs-tracked → JobsTrackedController::listAllTrackedJobs; GET /api/job-tracked/{id} → ::getTrackedJobById |
| Check whether a product submission is pending | GET has-job; product grid shows an informational “submission in progress” message | GET /api/has-job → JobsTrackedController::hasJob |
| Review job progress/output | Job detail refreshes GET job-tracked/{id} every 20 seconds, stops polling on finished, and displays queued/failed/finished labels | GET /api/job-tracked/{id} → JobsTrackedController::getTrackedJobById |
| List and maintain ASIR mappings | GET asir-product-attributes, GET asir-product-attributes/{status}, GET asir-product-attributes/{attributeId}/attribute-families, /custom-asir-category, /{attributeId}/sample-product, /{attributeId}/options; GET menu-tree for the category tree; POST asir-product-attributes, POST asir-product-attribute-options; PUT asir-product-attributes, PUT asir-product-attribute-options, PUT asir-product-attribute-families | Matching routes → AsirGroupProductAttributeController::getAllAttributes, getAttributesByStatus, getAttributeFamilies, getCustomAsirCategory, getSampleProductDataByAttributeId, getOptionsByAttribute, saveAttribute, saveAttributeOption, updateAttributes, updateAttributeOptions, updateAttributeFamilies; GET /api/menu-tree → MenuController::getFormattedMenuForTreeSelect |
| Synchronize ASIR attributes | POST asir-product-attributes/synchronize, then poll GET asir-product-attributes/sync-progress every four seconds | Matching routes → AsirGroupProductAttributeController::synchronizeAsirAttributes and ::getSyncProgress |
| List/edit Vimeo Stories | POST vimeo-stories/products, GET vimeo-stories/products/{product}, and POST vimeo-stories/products/{product}/videos | Matching routes → VimeoStoriesController::index, show, and saveVideo |
| Request Vimeo sync | POST vimeo-stories/sync for one or all products | POST /api/vimeo-stories/sync → VimeoStoriesController::sync |
Vimeo sync and ASIR sync have explicit UI progress/status handling; neither UI alone proves a remote system completed its work. The job detail view stops its timer when status is finished, but a finished Meduse job still does not establish downstream acceptance.
The ASIR sync action posts null and the page has no file-upload control. Its error message refers to a CSV being available, so the source does not show the CSV being supplied by this browser workflow.
Source-level gaps and mismatches
| Finding | Evidence and practical effect |
|---|---|
| Direct product-grid tenant reset happens after auth headers are set | The router awaits VERIFY_AUTH before the direct-link branch writes tenant_id = 'null'. VERIFY_AUTH calls ApiService.setHeader(), which conditionally assigns AX-Tenant but has no clearing branch. The old Axios default header can therefore remain through the guard; Products2.vue later updates local state and reloads. Whether a request uses the old header before that reload is unverified. |
| Category administration tree ignores the selected channel | AdministrerCategories.vue calls getCategoriesToAdministrate without a channel value; CatalogCategoryController::getCategoriesToAdministrate hard-codes channelId = 3. Do not assume this tree follows the breadcrumb's selected channel. |
| Product edit route is a demo form | Product-list actions navigate to /product/edit/:id; the registered component has no product service or API call and ignores the ID. Persistence through this route is not implemented in the inspected source. |
| Vimeo menu visibility and guard differ | App.vue shows Vimeo for tenant IDs null, empty string, literal null, or menzzo; router.ts allows the tenantOnly: 'menzzo' route only for null or literal null. With empty or menzzo, the menu can be visible while navigation redirects to the product grid. The deployed channel values and runtime effect are unverified. |
| Old hierarchy helper does not match the API route | CategoryService.getCategoriesBuilderMenu() dispatches a request to categories/{categoryId}/hierarchy, but the backend declares categories/{categoryId}/{storeId}/hierarchy. The active category manager calls the store-aware helper, which matches; the shorter helper has no call site in the inspected frontend. |
| Menu-item save helper has no Vuex handler | CategoryService.saveMenuItem() dispatches SAVE_MENU_ITEM; the action constant and backend route /api/menu/save-menu-item exist, but no corresponding Vuex action handler or active-screen call was found. |
| Attribute add route is declared twice | router.ts registers /attribut/add with the same name and component twice. Both declarations point to the same details view; route behavior was not runtime-tested. |
| Product deletion helper is local-only | Products2.vue delete methods remove rows from the current array and show a success toast without sending a delete request. No product-delete API route is declared in routes/api.php; treat that toast as client feedback, not proof of catalog deletion. |
| Menu export response does not identify execution mode or destination consumption | The default and Shopify handlers call Queue::push, but config/queue.php defaults to sync; the effective connection may be overridden. The Vue screen reports success on HTTP 200. Determine whether execution was inline or worker-backed, then verify destination consumption. The Make Up handler calls its Artisan command inline but discards the return code, so its default-200 response does not prove command success. |
What this map proves
The cited revisions prove the current menu declarations, route-to-view wiring, inspected view actions, request paths, and matching Laravel route/controller declarations. The map does not prove live route access, response schemas in a running environment, tenant configuration, imported file contents, queue completion, connector credentials, external-system receipt, or rendered commerce data. No API, runtime, database, host, or production boundary was accessed for this review.