Commit Graph
53 Commits
Author SHA1 Message Date
Kevin L'Hereec b643077e8d fix: correct orphan references after TR-069 typing refactor
- tests/device.spec.ts: fix 6× organizeParameters() calls passing wrapped
  response object instead of flat ParameterInfoStruct[] (runtime break)
- tests/device.spec.ts: fix setTmpParamValues([{x:1}]) with valid shape
- immediate_command_state_machine.ts: type handleResponse message param as
  CWMPTaskResultData (was any, gap in typing contract)
- configuration_evaluation_state.ts: replace fragile ../../../app/ dynamic
  import paths with proper static imports from ../../protocol/tr069_types.js
- main_state_machine.ts: replace all inline dynamic import() type casts with
  static imports (GetParameterNamesResponse, GetParameterValuesResponse,
  ParameterValueStruct, SetParameterAttribute, DownloadParameter, etc.)
2026-07-20 16:27:38 +02:00
Kevin L'Hereec f3eb8e1650 feat: restore strong typing on TR-069/CWMP protocol layer
- Copy cwmp-1-0..4.ts source classes from cwmp-connector (papaye) into
  app/protocol/ as local files (ts-nocheck, external dependency)
- Add soap_envelope.ts: SoapEnvelope, SoapEnvelopeHeader, CwmpID, NAMESPACES
- Add tr069_types.ts: re-exports all CWMP classes + CwmpMessage discriminated
  union + typed task payload interfaces (CWMPTaskType, CWMPTaskPayload, etc.)
- Rewrite cwmp_message_builder.ts to use class-based builders instead of raw
  XML template strings; add transferCompleteResponse() and soapFault()
- soap.ts: extractCwmpMessage returns CwmpMessage union, adds runtime allowlist
  guard against unknown CWMP method names from CPE
- cwmp_middleware.ts: envelope typed SoapEnvelope|null, message CwmpMessage|null
- cwmp_controller.ts: handleInform(informData: Inform), remove any, migrate
  TransferComplete and fault to new builder path, drop buildSoapEnvelope import
- task_queue.ts: CWMPTask.type → CWMPTaskType literal union, payload →
  CWMPTaskPayload, result → CWMPTaskResultData
- device_action_executor.ts: GPV/GPN/GPA responses typed, no more any
- main_state_machine.ts: DeviceContext.message.data → CWMPTaskResultData,
  organizeParameters receives ParameterInfoStruct[] directly
- device.ts: tmpParamValues typed ParameterValueStruct[], organizeParameters
  signature updated, updateFromValues typed
- device_id.ts: fromInform typed with DeviceIdStruct
- soap_envelope.ts: remove unconditional <cwmp:noMoreRequests> header
  (CPE→ACS only per TR-069 §3.7.1.4)
2026-07-20 15:25:26 +02:00
Kevin L'Hereec 8969355688 feat: improve critical reads, device list and modelPaths bug fix
Build & Deploy / build (push) Successful in 34s
Build & Deploy / docker (push) Successful in 1m4s
Build & Deploy / deploy (push) Successful in 32s
- main_state_machine.ts: add to CriticalReadsState GPV:
  ProvisioningCode (confirm CPE persisted value), UpTime (detect reboots),
  ManagementServer.URL (verify ACS URL), ConnectionRequestUsername/Password
  (ensure wake credentials are always available)
- Home.vue: add Last Seen column (device.updatedAt)
- pages_controller.ts: fix modelPaths bug — was never passed to DeviceDetail,
  now auto-detected from dataModel and passed as predefined TR-181/TR-098 paths
2026-07-17 16:57:08 +02:00
Kevin L'Hereec 7d603da0ca fix: Connection Request fallback to IPv4 when CPE has IPv6-only URL
Build & Deploy / build (push) Successful in 30s
Build & Deploy / docker (push) Successful in 57s
Build & Deploy / deploy (push) Successful in 24s
- device_record.ts: add lastRemoteIp field to store the CPE public IP
  from each Inform (X-Forwarded-For or TCP remote IP)
- cwmp_controller.ts: persist lastRemoteIp on every Inform alongside
  lastPeriodicInformAt (single  operation)
- device_service.ts: sendWakeOnWlan() now tries the original URL first
  (may be IPv6), then falls back to a rebuilt URL using lastRemoteIp
  (IPv4 public IP) if the ACS server has no IPv6 connectivity
2026-07-17 16:45:30 +02:00
Kevin L'Hereec c3bc2902f0 fix: add missing /internal/references routes and clean isGpnAllowed()
Build & Deploy / build (push) Successful in 38s
Build & Deploy / docker (push) Successful in 1m4s
Build & Deploy / deploy (push) Successful in 31s
- start/routes.ts: mirror references routes into /internal group so the
  DeviceDetail.vue resolve buttons work (were returning 404)
- device.ts: isGpnAllowed() now clears cooldownUntil when transitioning
  open→half-open, avoiding stale date in persisted snapshots
2026-07-17 16:36:43 +02:00
Kevin L'Hereec 19caa1a06f feat: read PeriodicInformInterval and PeriodicInformEnable in critical reads
Build & Deploy / build (push) Successful in 33s
Build & Deploy / docker (push) Successful in 1m4s
Build & Deploy / deploy (push) Successful in 24s
Add Device.ManagementServer.PeriodicInformInterval and
Device.ManagementServer.PeriodicInformEnable to the GPV performed
during CriticalReadsState (applies to both TR-181 and TR-098).
2026-07-17 16:31:33 +02:00
Kevin L'Hereec 26ffcbea6b fix: avoid GPN on root path Device. which returns the full parameter tree
Build & Deploy / build (push) Successful in 33s
Build & Deploy / docker (push) Successful in 57s
Build & Deploy / deploy (push) Successful in 33s
Two complementary fixes:
- IdleState: skip root-level parent paths (Device., InternetGatewayDevice.)
  when building the GPN queue. Params like Device.RootDataModelVersion have
  Device. as parent but sending GPN on Device. with NextLevel=0 returns the
  entire TR-181 tree in one response (potentially several MB).
  These root-level params are classified via deeper subtree GPN or catalog.
- task_queue: use NextLevel=1 for root paths (1 segment) as a safety net,
  NextLevel=0 for deeper paths to get all leaves of that subtree.
2026-07-17 16:29:29 +02:00
Kevin L'Hereec 61bfb4e762 fix: rebind CWMP session when CPE sends empty POST on new TCP port
Build & Deploy / build (push) Successful in 33s
Build & Deploy / docker (push) Successful in 1m1s
Build & Deploy / deploy (push) Successful in 33s
TR-069 CPEs routinely open a new TCP connection (new port) for the empty
POST that follows InformResponse. ensureSessionForRemote() only did an
exact remoteKey match, so hasSession() returned false and the state
machine was never continued — GPN discovery was never triggered.

Add IP-only fallback in ensureSessionForRemote(): when the exact
remoteKey is not found, scan RUNNING machines for a unique IP match,
rebind the new remoteKey, and remap sessionMachines to the new sessionId.
Ambiguous cases (NAT/CGNAT with multiple active devices on same IP)
return false safely.
2026-07-17 16:14:38 +02:00
Kevin L'Hereec 7835f99657 fix: correct CWMP session management side effects
Build & Deploy / build (push) Successful in 29s
Build & Deploy / docker (push) Successful in 1m0s
Build & Deploy / deploy (push) Successful in 34s
- state_machine_manager: add deviceToRemotes reverse index (Map<deviceKeyJson, Set<remoteKey>>)
  so completeMachine/failMachine clean up remoteToDevice in O(1) — fixes unbounded memory leak
- state_machine_manager: getHashIdForRemoteIp() now only matches RUNNING sessions and
  returns undefined when multiple candidates exist (NAT/CGNAT safety)
- state_machine_manager: IPv6 bracket normalization in IP comparison
- cwmp_controller: apply IP fallback to TransferComplete and generic response handler
  (same new-TCP-port scenario as empty POST after firmware reboot)
- cwmp_logger_middleware: reuse request.cwmp.sessionId instead of recomputing
  from socket to avoid formula drift
2026-07-17 15:39:41 +02:00
Kevin L'Hereec d44d896556 fix: persist empty POST in TR-069 trace when CPE uses a new TCP port
Build & Deploy / build (push) Successful in 38s
Build & Deploy / docker (push) Successful in 1m5s
Build & Deploy / deploy (push) Successful in 23s
When a CPE sends an empty POST (polling) on a new TCP connection, the
remoteKey (IP:port) differs from the one registered during Inform.
Add StateMachineManager.getHashIdForRemoteIp() to find the device by
IP alone as a fallback, so cwmpDeviceId is resolved and the exchange
is properly stored in the trace (cwmpMethod: Empty, dashed arrow).
2026-07-17 14:24:44 +02:00
Kevin L'Hereec 3bb85d9031 fix: support alias-based IPv6 interface names and add engine reset utility
Build & Deploy / build (push) Successful in 30s
Build & Deploy / docker (push) Successful in 1m4s
Build & Deploy / deploy (push) Successful in 35s
- Home.vue: extend RE_IPV4/RE_IPV6 to match alias-based interface names
  like Device.IP.Interface.[BR_LAN].IPv6Address.[GUA_LAN].IPAddress
  (used by Sagemcom Livebox 4 with AliasBasedAddressing=1)
- reference_engine.ts: add resetReferenceEngine() to allow config reload
  without restart (wassup provider disabled via config/references.json)
2026-07-17 14:21:02 +02:00
kevin.lhereec b12141792f fix: supprimer import logger inutilise dans cwmp_middleware (TS6133)
Build & Deploy / build (push) Successful in 40s
Build & Deploy / docker (push) Successful in 1m6s
Build & Deploy / deploy (push) Successful in 25s
2026-07-17 10:39:48 +02:00
kevin.lhereec 5ea25d462e feat: logs debug sur les echanges XML CWMP
Build & Deploy / build (push) Failing after 36s
Build & Deploy / docker (push) Skipped
Build & Deploy / deploy (push) Skipped
- cwmp_middleware: log XML brut recu (bodyPreview 500 chars), contentType,
  bodyLength, et message extrait (type, cwmpVersion, cwmpId, messageKeys)
  + log body vide (CPE polling)
- cwmp_logger_middleware: log XML pretty-print complet CPE->ACS et ACS->CPE
  en debug, independamment du statut trace
- cwmp_controller: log routage message (messageType), InformResponse,
  TransferCompleteResponse, reponses state machine avec longueur
2026-07-17 10:36:57 +02:00
kevin.lhereec b00c0c94a8 feat: suppression des commandes PENDING depuis /commands
Build & Deploy / build (push) Successful in 40s
Build & Deploy / docker (push) Successful in 1m4s
Build & Deploy / deploy (push) Successful in 26s
- Ajout de destroy() dans CommandsController (DELETE /commands/:id)
- Routes DELETE /commands/:id dans les groupes /api/v1 et /internal
- Bouton supprimer dans Commands.vue visible uniquement sur les commandes PENDING
- Utilise fetchWithCsrf pour la protection CSRF
2026-07-17 10:31:56 +02:00
Kevin L'Hereec 991173aa05 feat(auth): add session login page, API key guard, and remove orphan SQL migrations
- Add session-based authentication for web-UI (Login.vue, AuthController)
- Add AuthSessionMiddleware: redirects unauthenticated users to /login
- Add ApiKeyMiddleware: validates X-Api-Key header on all /api/v1 routes
- Add BasicAuthMiddleware: registered for future M2M use
- Use timingSafeEqual for all credential comparisons (timing attack prevention)
- Regenerate session ID on login (session fixation prevention)
- Validate redirect target after login (open redirect prevention)
- Require WEBUI_USERNAME, WEBUI_PASSWORD, API_KEY as mandatory env vars
- Share auth.username/authenticated via Inertia shared props
- Add user dropdown in navbar (avatar icon + username + logout)
- Add login i18n keys in fr.json and en.json
- Remove orphan SQL migrations (users, auth_access_tokens) and @adonisjs/lucid
2026-07-03 13:59:05 +02:00
ATX Bot a9c7bcf643 Fix: persist catalog classification to DB after GPN failure. Previously, reclassifyDeviceFromCatalog was called but the result was not saved (first persist happened before catalog call). Now: setUnsupported → recordFailure → reclassify via catalog → persist (single createOrUpdate with full snapshot including classified params). All 811 tests pass. Build status: Success 2026-06-09 09:33:16 +02:00
ATX Bot f522e184b1 Fix: call reclassifyDeviceFromCatalog in DiscoveringParametersState when GPN fails. This ensures params like PeriodicInformInterval are correctly classified as writable (parameter) based on the catalog when GPN is unsupported. All 811 tests pass. Build status: Success 2026-06-09 09:31:09 +02:00
ATX Bot adab94657b Implement incremental classification logic in IdleState. Classification is now per-param: gpnStatus=unknown → all tmpParams unclassified (first session). gpnStatus=supported/unsupported → only NEW params not in _parameters/_properties need classification. Removed reclassify from CriticalReadsState and OperationalState. All 811 tests pass. Build status: Success 2026-06-09 08:54:29 +02:00
ATX Bot 25d69bd03f Add two-session scenario test demonstrating the full flow. Fix OperationalState to also skip reclassify when already classified. Session 1: GPN test → classify → critical reads → inventory GPN→GPV→SPV → ProvCode. Session 2: skip GPN + skip all (1 GPV only). All 811 tests pass. Build status: Success 2026-06-08 17:30:21 +02:00
ATX Bot ffbed94dcc Skip GPN test and catalog reclassification when device is already classified. IdleState skips GPN if gpnStatus=supported AND parameters exist. CriticalReadsState skips reclassifyDeviceFromCatalog if parameters already classified. Avoids unnecessary RPCs on subsequent sessions. All 809 tests pass. Build status: Success 2026-06-08 17:26:44 +02:00
ATX Bot 2cdb11ce25 IdleState now extracts parent paths from Inform parameters for GPN test. This classifies Inform params (writable vs read-only) and tests GPN support in one step. Falls back to data model root path if no Inform params available. All 791 tests pass. Build status: Success 2026-06-08 17:19:31 +02:00
ATX Bot 59fe7f1022 Fix session flow: 1) IdleState sends single GPN test (ManagementServer. only), 2) ConfigEval processes GPN/GPV responses inline (not via task callbacks) ensuring correct order: GPN→GPV→SPV. Updated all affected tests. All 785 tests pass. Build status: Success 2026-06-08 17:16:00 +02:00
Kevin L'Hereec ec7e66555d fix 2026-06-08 16:54:37 +02:00
Kevin L'Hereec 44f7d9acfc fix 2026-06-08 16:46:38 +02:00
Kevin L'Hereec dae82eeff2 fix 2026-06-08 16:35:33 +02:00
Kevin L'HereecandContinue 08c620ee68 fix: drain task queue on session completion to stop orphan CWMP requests
After OperationalState, the state machine was marked completed but leftover
tasks in the CWMPTaskQueue (queued by ConfigurationEvaluationState callbacks)
were being served to the CPE on subsequent empty POSTs via the continue()
task fallback path, causing spurious GetParameterNames + SetParameterValues
exchanges after the session officially ended.

Fix: call taskQueue.clearPendingTasksForDevice() in completeMachine() so no
tasks bleed into the next session.

Generated with [Continue](https://continue.dev)

Co-Authored-By: Continue <noreply@continue.dev>
2026-06-08 14:20:59 +00:00
Kevin L'HereecandContinue 7540327689 fix: process GPN response in DiscoveringParametersState
The GPN response (ParameterInfoStruct list) was received but never
processed — organizeParameters() was never called, so discovered
parameters were lost and gpnStatus was never set to 'supported'.

Now on each successful GPN response:
- device.organizeParameters() is called to store leaf params/props
- device.setGpnStatus('supported') marks the device as GPN-capable

This fixes: parameters not showing in UI, wrong dataModel detection,
and PeriodicInformInterval not appearing after SPV.

Generated with [Continue](https://continue.dev)

Co-Authored-By: Continue <noreply@continue.dev>
2026-06-08 14:13:09 +00:00
Kevin L'HereecandContinue ca24b469d3 fix: allow uppercase letters in configuration identifier regex
Previously /^[a-z0-9]+(-[a-z0-9]+)*$/ rejected identifiers like 'BM632w-standard'.
Updated to /^[a-zA-Z0-9]+(-[a-zA-Z0-9]+)*$/ to allow mixed case.

Generated with [Continue](https://continue.dev)

Co-Authored-By: Continue <noreply@continue.dev>
2026-06-08 13:14:04 +00:00
ATX Bot 23b5e33a6b Implement DeviceModel.distinctCriteriaValues() — fixes 500 on /api/v1/devices/criteria-values. Uses MongoDB distinct() to get unique manufacturers, OUIs, productClasses from devices collection. Build status: Success 2026-06-08 13:01:19 +00:00
Kevin L'HereecandContinue aad93911e4 feat: TR-069 CWMP state machine hardening + exchange viewer improvements
- TR-069 CWMP state machine hardening (14 phases): shared event utility,
  multi-event routing, GPN circuit breaker, IdleState GPN guard, expanded
  GPN fault codes, CriticalReadsState, ConfigEval GPN guard, task queue
  race condition fix, explicit error handling, terminal states
  (OperationalState/PartialOperationalState), consolidated reclassify,
  crash pattern detection, removed enqueueImmediate, state flow wiring
- Fix SOAP Fault not processed by state machine (soap-env:Fault detection)
- Fix GPN circuit breaker not persisting after session drops
- Fix CriticalReadsState GPV response parsing (xsi:type normalization)
- Fix CriticalReadsState not processing GPV response values
- Skip SPV when device is already compliant (ProvisioningCode check)
- Add Device.DeviceInfo.ModelName to critical reads GPV
- Fix TypeError on DeviceDetail parameters view (null guards)
- Log empty 204 responses in exchange trace UI
- TR-181 catalog: type corrections and new entries (+6640 lines)
- SequenceViewer: replace session-nav buttons with compact dropdown select
- SequenceViewer: fix CPE/ACS lifeline headers wrapping to 2 lines
- Add 20 unit tests for state machine fixes (SOAP Fault, GPN circuit
  breaker, CriticalReads, stale session, ConfigEval/ComplianceUpdate skips)

Generated with [Continue](https://continue.dev)

Co-Authored-By: Continue <noreply@continue.dev>
2026-06-08 12:49:00 +00:00
Kevin L'Hereec dabe15839d fix: handle GPN Fault in DiscoveringParametersState
When the CPE responds with a CWMP Fault to GetParameterNames,
mark gpnStatus as 'unsupported' and continue to ConfigurationEvaluationState
instead of hanging the session.
2026-06-03 15:56:33 +02:00
Kevin L'Hereec 0c83a4ccb2 feat: TR-069 Exchange Viewer - structured MongoDB storage with SSE streaming and sequence diagram UI
- MongoDB storage: cwmp_exchanges collection with indexes (deviceId+timestamp, deviceId+sequenceNumber unique, TTL 24h)
- ExchangeStoreService: CWMP method extraction, per-device queue for ordering, retry logic, message cap (5000/device)
- Exchange API: GET/DELETE/SSE stream endpoints with Last-Event-ID reconnection
- CwmpLoggerMiddleware: dual-write (MongoDB + legacy files) with fire-and-forget
- Frontend: SequenceViewer (CPE↔ACS lifelines, arrows, auto-scroll, virtual scroll) + InspectorPanel (formatted XML, copy, syntax highlighting)
- Tr069Trace page: integrated new viewer with col-6/col-6 layout
- DeviceDetail page: collapsible exchange section when device is traced
- 14 property-based tests, 40+ unit tests, 5 integration tests
- Health check includes index verification
- Config: feature flags, SSE timeouts, retry policy
2026-06-03 15:52:44 +02:00
Kevin L'Hereec 478439783d feat: catalog type enrichment + typed compliance comparison
- Add type field to all 7727 entries in tr181-catalog.json (xsd:string/unsignedInt/boolean/int)
- reclassifyDeviceFromCatalog applies catalog type when device type is UNKNOWN
- Export getCatalogType() utility
- Compliance comparison: numeric types compared as Number, boolean as bool, fallback to String
- Handle NaN gracefully (fallback to string comparison)
2026-06-03 08:53:31 +02:00
Kevin L'Hereec ce4a857bb1 fix: compliance comparison uses String() to handle number vs string mismatch 2026-06-02 18:29:10 +02:00
Kevin L'Hereec 670ed860aa feat: initialize lastPeriodicInformAt on BOOTSTRAP too 2026-06-02 18:16:16 +02:00
Kevin L'Hereec f0670224f3 feat: periodic inform utility + 3 dates on same line
- Extract computeNextPeriodicInform to app/utils/periodic_inform.ts
- 11 unit tests for the periodic computation logic
- DeviceDetail: 3 date columns on same row (created, last seen, next estimated)
2026-06-02 18:06:18 +02:00
Kevin L'Hereec 75436ad2f4 style: formatting fixes (prettier compliance) 2026-06-02 18:03:19 +02:00
Kevin L'Hereec 7882a49d71 refactor: move dynamic imports to file headers
- getReferenceEngine import moved to top of cwmp_controller
- Fix makeContext type in configuration_evaluation_state tests
2026-06-02 17:58:07 +02:00
Kevin L'Hereec 31578e368f feat: estimated next connection + fix build errors
- Store lastPeriodicInformAt on device when PERIODIC Inform received
- Display 'Prochaine connexion' in DeviceDetail identity card
- Fix tsconfig exclude (tests, inertia, coverage) for Docker build
- Fix TS errors in tests (CommandResult type, unused imports)
- Fix distinctCriteriaValues typing in controller
2026-06-02 17:56:17 +02:00
Kevin L'Hereec e1e8ae5097 refactor: move validator imports to file header 2026-06-02 17:12:24 +02:00
Kevin L'Hereec 0cb8e12466 refactor: wire validators into controllers
- configurations_v1_controller: use createConfigurationValidator/updateConfigurationValidator
- firmware_catalog_controller: use createFirmwareEntryValidator/updateFirmwareEntryValidator/createMigrationRouteValidator
- Remove dead isModeType/parseMode from mode.ts
- Remove dead NAMESPACES from soap.ts
2026-06-02 17:09:15 +02:00
Kevin L'Hereec 823427cdbe refactor: remove dead code
- Remove unused NAMESPACES export from soap.ts
- Remove unused isModeType/parseMode from mode.ts (device_service does inline parsing)
- Remove flaky model unit tests (covered by integration tests)
- Keep validators (to be wired into controllers later)
2026-06-02 17:05:58 +02:00
Kevin L'Hereec e857b4fbe7 feat: reference providers system with Wassup integration
- Pluggable multi-provider architecture (ReferenceEngine)
- Wassup provider implementation (HTTP GET + X_WASSUP_USER_IP)
- Auto-resolve references on Inform (BOOT/BOOTSTRAP events)
- References displayed in device Identity card
- REST API: GET/POST references per device
- Config via config/references.json
- Fix event extraction for single EventStruct and numeric EventCodes
- Mock Wassup provisioned by home-device-simulator on device creation
2026-06-02 15:52:16 +02:00
Kevin L'Hereec 4eb3f0795a feat: immediate mode (I) commands via Connection Request
- Hide Refresh button when ConnectionRequestURL is unavailable
- Fix ImmediateCommandStateMachine session lifecycle (mark complete when no commands)
- Fix preemption: new CONNECTION REQUEST replaces stale immediate session
- Protect ensureSessionForRemote from rebinding to completed machines
- Normalize numeric event codes from simulators (6 -> 6 CONNECTION REQUEST)
- Extract updatePendingCommandsStatus for clarity
2026-06-02 14:00:31 +02:00
Kevin L'Hereec bc9ac4f125 fix: state machine timing + reclassification tests
- Fix state machine start timing: don't call start() in startStateMachine,
  let the CPE's first empty body trigger the state machine via continue().
  This ensures GPN is sent at the correct point in the TR-069 session.
- Add unit tests for reclassifyDeviceFromCatalog (10 tests)
- Add unit tests for MainStateMachine transitions and GPN callbacks (11 tests)
- Test both scenarios: Huawei (GPN supported) and Livebox (GPN unsupported + fallback)
- Fix tr069_trace_service test path assertion (config/ → data/)
- Update steering doc with Livebox bootstrap command
2026-06-01 17:31:33 +02:00
Kevin L'Hereec a5b3135396 ok maybe 2026-06-01 16:58:52 +02:00
Kevin L'Hereec ea73e91aa4 trace + backup propertie 2026-06-01 16:20:58 +02:00
Kevin L'Hereec b3b1edec17 ok 2026-06-01 15:49:09 +02:00
Kevin L'HereecandCopilot 6082a0e610 feat: TR-069 per-device SOAP trace logging + log viewer UI
- Remove SOAP from Docker stdout; route to per-device trace files only
- Fix trace service paths using process.cwd() (/app/data/, /app/logs/tr069/)
- Fix Docker volume permissions: dedicated /app/data & /app/logs/tr069 dirs
- Add GET /api/v1/tr069-trace/:id/log endpoint (tail N lines)
- Rewrite Tr069Trace.vue: clickable rows, dark log viewer, 3s auto-refresh
- Add simulator-ui-env.js to public/ (remove from config/)
- TR-181/InternetGatewayDevice dataModel auto-detection
- Parameter writability config with W/R fallback default
- Fix device_action_executor for GetParameterNames detection flow

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-01 14:33:44 +02:00
Kevin L'HereecandCopilot 847da1cdf5 feat: per-device TR-069 SOAP trace logging
- Tr069TraceService: in-memory Map O(1) lookup, Promise-queue per device
  for sequential file writes, 10MB rotation (5 files kept)
- config/tr069-trace.json: persisted list of traced devices (atomic write)
- CwmpLoggerMiddleware: buffers request+response, writes to device log file
  after next() once ctx.cwmpDeviceId is set by controller
- CwmpController: sets ctx.cwmpDeviceId on all code paths (Inform + others)
- StateMachineManager: getHashIdForRemote() for non-Inform messages
- REST API: GET/POST/DELETE /api/v1/tr069-trace
- UI: Tr069Trace Vue page with device search, add/remove tracing
- 8 new unit tests (192 total, all passing)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-01 12:07:07 +02:00