Skip to main content

Data Analysis — technical guide

This guide covers the legacy manager dashboard mounted at /company/dashboard-manager, for engineering and support teams. It describes local code contracts, not a verified production deployment. See usage and configuration for audience-specific procedures.

Architecture and responsibilities​

Verified in code: the route uses Symfony controllers, Twig fragments, jQuery requests, Doctrine SQL/ORM, session state, Highcharts, DataTables and Select2. The inspected route does not call an external BI reporting engine.

All paths in the following table are relative to smartmobility-legacy/; bundle-relative paths start at src/Company/ManagerDashboardBundle/.

ComponentResponsibility / symbols
config/routes.yaml, bundle Resources/config/routing.ymlMount and endpoint definitions.
Controller/DefaultController.phpindexAction builds tabs/tree; tab actions calculate population, datasets and rendered fragments.
Services/Helper.phpCurrent user/school, feature checks, legacy permission fallback, administrator test, scale, colors and lexicon.
Controller/PerimeterController.php::indexActionServer-side DataTables response for the session population; getCollaborators applies search/order/pagination.
Controller/OneToOneController.php::progressActionInterview lookup, population membership and progression categories.
Chart/TeamProficiency.phpjobMasteryRatio, averageGapLevelPerJobs, averageGapLevelPerUsers, skillsWithGapLevel, motivationRatio, representationOfJobs.
Chart/SkillsMapCampaign.phpSkills-map campaign chart calculations, invoked by campaignAction.
Resources/views/Default/index.html.twig, Resources/views/Tabs/, Resources/views/Partials/Conditional controls, tab/detail HTML, data tables and translated labels.
Resources/public/js/dashboard.jsinit, onChartElementClick, tableClickableItem, campaignClickable, oneToOne, filterResultsByJobDescription, exportAsCsv.
Resources/public/js/perimeter.jsOpens a server-side DataTables modal and destroys its instance on close.
src/Security/FeatureSwitchVoter.php, src/Service/Configuration/FeatureSwitchService.phpTenant switch evaluation via BaseVoter::hasModuleAccess; stored activation OR tokenizer access.

Requests and responses​

Verified in code: paths below are relative to /company/dashboard-manager. They are browser-session endpoints, not a documented public integration API. AJAX handlers check Request::isXmlHttpRequest; normal direct requests are rejected with HTTP 400. Examples show structure only and contain no credentials or real identifiers.

Method / suffixHandlerInputs / response
Page /DefaultController::indexActionTwig shell, enabled tabs, hierarchy and admin context.
POST /team-activityteamActivityActionForm level[], optional relation[]; HTML, chart definitions, perimeter attributes.
POST /team-proficiencyteamProficiencyActionSame population fields; optional query jid, vw for supported job-restricted fragments.
POST /skill-analysisskillAnalysisActionPopulation fields; query skill, motivation, jid, vw select supported detail/graph branches. q is consumed by the skills retrieval call.
POST /skills-map-campaigncampaignActionPopulation fields; campaignId for progression or campaignIdTable for not-started detail.
POST /1to1oneToOneActionLevels determine population and available interview campaigns.
GET /1to1/progress/{id}OneToOneController::progressActionNumeric interview ID; reads session perimeter; returns detail HTML and chart data.
POST /perimeterPerimeterController::indexActionDataTables draw, start, length, search[value], order; returns draw, recordsTotal, recordsFiltered, data.

A main tab request carries X-Requested-With: XMLHttpRequest with form data such as level[]=1. Typical response shape is:

{
"html": "<rendered tab fragment>",
"highcharts": {},
"attributes": {"perimeterSize": "<formatted perimeter summary>"}
}

highcharts is conditional and can contain donut, bar, stacked, heatmap, bubble or other chart structures. Empty population responses contain an error fragment and perimeter attributes without normal chart data. Detail responses use branch-specific keys such as tableId, userProgression or userNotStarted; consumers must not assume one universal schema.

The client records the active tab in the URL hash. Tab changes and applying global filters POST to the selected endpoint. Job selection sends jid and vw and replaces its associated graph/detail. Interview campaign selection performs the GET detail request. CSV export is generated locally with Blob, a UTF-8 BOM and semicolon separators from DataTables rows matching the current filter; no background export job is involved.

Population and session lifecycle​

DefaultController::tree, iterate, extractLevel and getManagerIds build and select manager-school IDs. Selecting level 1 also includes level 0 in extractLevel. For restricted non-root managers without all_collaborators, that method invokes applyVisibilityRules and the shared VisibilityFilter.

setHierarchicalUsers resolves enabled users linked to the current manager by selected tenant relationships, gated by dashboard_filter_user_relation. Main activity, proficiency, skill and skills-map handlers call it. Their population queries can combine manager-school membership OR relationship-user membership. This is not a blanket claim that every detail query applies identical visibility rules.

getPerimeterSize excludes disabled users and the current user, counts distinct employees and writes perimeter = {managerIds, hierarchicalUsers, total} to session. setFilters writes level/relationship keys to filters. The modal reads this stored perimeter, rather than accepting an independent population specification.

cacheTree stores treeStructure keyed for normal levels or entire company, with current user and expiration time() + 600; isCacheExpired checks identity and time. This cache concerns hierarchy, not BI datasets or chart refresh timing.

Verified inconsistencies: oneToOneAction reads levels without calling setHierarchicalUsers; relationship-only selection can pass the generic filter-presence check yet resolve an empty population. Dashboard.campaignClickable serializes level inputs only for campaign details, omitting relationships. Do not promise overview/detail population equality in those cases. Session-dependent details should be opened after the intended tab population has loaded.

Data and metric contracts​

Domain data includes User, School, Customer, Setting, jobs and skill levels/requirements, hierarchical relationships, login records, interviews and assessment progress. Analysis reads these sources and stores transient selection context in session; no dedicated persistent dashboard report model is established on this path.

  • getProfileCompletionLevel and teamActivityAction build profile-completion bands and an aggregate completion measure.
  • getLoginStats(managerIds, nbOfWeeks = 4) groups login records by user/week; teamActivityAction calls it with 6, so the activity tab requests six weeks. Weekly series increment per returned user/week record; accumulated user logins sums events. Its collaborators value counts returned records, so it must not be assumed to be a distinct-user total across weeks.
  • TeamProficiency compares job requirements with employee skill data. Motivation is separate; teamProficiencyAction passes a fixed 4 to motivationRatio, while the skill scale elsewhere comes from tenant settings.
  • TeamProficiency::THRESHOLD_PERCENTAGE_FOR_GROUPED_JOBS is 2; showJobRepresentations groups percentages at or below that threshold. The client can expand the representation without changing source assignments.
  • campaignAction invokes SkillsMapCampaign; OneToOneController::progressAction checks campaign users against session manager-school IDs or relationship-user IDs and computes interview categories. Those are different campaign data flows.

No refresh SLA, historical snapshot guarantee or universal denominator across panels was verified. The commented-out unmastered-skills branch in teamProficiencyAction must not be treated as a working feature.

Configuration and authorization​

Helper::hasAccess requires all supplied switches; hasAccessToAny requires one. indexAction rejects the page when neither any tab switch nor isManagerDashboardActive succeeds, but adds tabs only for switches granted individually. Consequently the legacy permission fallback can permit the shell without creating visible tabs.

Main tab handlers generally allow their switch or the legacy dashboard fallback. Interview progress requires dashboard_team_1to1 directly. The perimeter handler has its own compound access condition including isAdmin; do not flatten these checks into one permission rule. Helper::isAdmin considers root school, visibility and all_managers_filter. See the configuration guide for the activation inventory and limits.

FeatureSwitchService::isSwitchActive accepts stored value 1 or tokenizer module access. That establishes evaluation behavior, not the effective configuration of a tenant. There is no verified nextgen override or independent migration contract.

Failures, observability and runtime​

ConditionCode behavior / support implication
Non-AJAX handler requestHTTP 400.
Missing level and relation inputsMain tab handlers return HTTP 400 through hasFiltersApplied.
Access check failsHTTP 403 or access-denied exception, depending on handler.
Interview ID absent from storageprogressAction raises not found.
Empty populationJSON contains the error Twig fragment and count, rather than normal charts.
Slow responseClient shows a delayed message after 15 seconds. This is not a timeout or polling interval.
Detail request failsSeveral detail callbacks have empty error handlers; visible feedback can be limited. Inspect status and session context through approved support tooling.

Runtime requires the Symfony service graph, relational database, Doctrine, sessions, translations/lexicon and the scripts loaded by the Twig shell. No scheduled analytics worker, aihub call or external BI account is established by this route. No production requests, credentials or personal payloads were collected for this guide.

Privacy, extension points and coexistence​

Perimeter and detail responses contain employee data, including names, email addresses, profile links, skills and progression. Local CSV export inherits the loaded/filtered table contents; handle it under the same access rules as the source data. A client-side selector is not a security boundary. Any extension must preserve server-side authorization and population checks.

A new tab requires coordinated switch registration, indexAction/getEndpointForTab, routing, controller output, Twig and client chart initialization. New metrics belong in the relevant query/chart implementation and require explicit units and population semantics. Avoid relying on commented features as supported extension contracts.

Targeted searches for this route and its dashboard keys in nextgen-front, nextgen-back and aihub did not establish a redesigned replacement, proxy or AI dependency. Local source cannot prove production routing, deployment or absence of other analytics products. Superset/Sisense reporting and the Import/Export Center are distinct paths.

Evidence and limitations​

Verified in code: all paths and symbols in this guide were inspected on 22 October 2026. Resources/config/routing.yml establishes methods and suffixes; controller and helper symbols establish access/population/session behavior; chart classes and JavaScript establish calculation and client interactions. Source versions were not mapped to a production release.

Documented in Confluence: team matrix FAQ, v1, 24 September 2026, supports team-level intent only. Supplied KBCT entry 2136702980 is the FAQ folder. The PS methodology page (2104033292, v7, 30 December 2025) and onboarding page (2104983553, v9, 18 February 2026) contain no route-level technical contract. The BI general-information page (988512264, v2, 19 March 2024) returned macro-only/lossy content, so no behavior was inferred from it.

Not verified: deployed version, tenant activation, complete external service behavior, live payloads, end-to-end calculations and population consistency across every branch. The functional guide records authenticated UI checks in English and French: population changes, profile completion, chart selection, empty skill/campaign states and employee navigation (Observed in application). Those observations do not establish all endpoint contracts or calculations. This technical page intentionally contains no application screenshots.

Functional-guide evidence​

These implementation and product references support the functional guide. Local source behavior does not establish which revision or optional features are deployed. Application observations remain distinct from code and documentary evidence.

Verified in code: smartmobility-legacy/src/Company/ManagerDashboardBundle/Controller/{DefaultController,PerimeterController,OneToOneController}.php, Services/Helper.php, Resources/views/Default/index.html.twig, Resources/views/Tabs/, Resources/public/js/{dashboard,perimeter}.js, and Chart/TeamProficiency.php. See the technical guide for exact symbols and contracts.

Documented in Confluence: the matrix FAQ cited above, under KBCT → Dashboard Manager. The supplied KBCT FAQ entry is a folder. PS entry pages “1. Delivery Philosophy & Project Methodology” (v7, 30 December 2025) and “2. Onboarding/learning and partner certification” (v9, 18 February 2026) were reviewed but provide no dashboard-specific configuration contract. External BI/Sisense material is a separate scope.

Last updated on 3 November 2026