{
  "_class" : "hudson.model.FreeStyleBuild",
  "actions" : [
    {
      "_class" : "hudson.model.CauseAction",
      "causes" : [
        {
          "_class" : "hudson.triggers.TimerTrigger$TimerTriggerCause",
          "shortDescription" : "Started by timer"
        }
      ]
    },
    {
      
    },
    {
      "_class" : "hudson.plugins.git.util.BuildData",
      "buildsByBranchName" : {
        "refs/remotes/origin/dev" : {
          "_class" : "hudson.plugins.git.util.Build",
          "buildNumber" : 777,
          "buildResult" : null,
          "marked" : {
            "SHA1" : "378885a48e4f902910fad004ab676b75d48e3466",
            "branch" : [
              {
                "SHA1" : "378885a48e4f902910fad004ab676b75d48e3466",
                "name" : "refs/remotes/origin/dev"
              }
            ]
          },
          "revision" : {
            "SHA1" : "378885a48e4f902910fad004ab676b75d48e3466",
            "branch" : [
              {
                "SHA1" : "378885a48e4f902910fad004ab676b75d48e3466",
                "name" : "refs/remotes/origin/dev"
              }
            ]
          }
        }
      },
      "lastBuiltRevision" : {
        "SHA1" : "378885a48e4f902910fad004ab676b75d48e3466",
        "branch" : [
          {
            "SHA1" : "378885a48e4f902910fad004ab676b75d48e3466",
            "name" : "refs/remotes/origin/dev"
          }
        ]
      },
      "remoteUrls" : [
        "https://github.com/younex1/erp-nuxt-frontend.git"
      ],
      "scmName" : ""
    },
    {
      
    },
    {
      
    },
    {
      "_class" : "org.jenkinsci.plugins.displayurlapi.actions.RunDisplayAction"
    }
  ],
  "artifacts" : [
    
  ],
  "building" : false,
  "description" : null,
  "displayName" : "#777",
  "duration" : 62661,
  "estimatedDuration" : 60620,
  "executor" : null,
  "fullDisplayName" : "build-logship-frontend #777",
  "id" : "777",
  "inProgress" : false,
  "keepLog" : false,
  "number" : 777,
  "queueId" : 5873,
  "result" : "SUCCESS",
  "timestamp" : 1792886460764,
  "url" : "https://jenkins.younex.de/job/build-logship-frontend/777/",
  "builtOn" : "",
  "changeSet" : {
    "_class" : "hudson.plugins.git.GitChangeSetList",
    "items" : [
      {
        "_class" : "hudson.plugins.git.GitChangeSet",
        "affectedPaths" : [
          "app/components/AgGridServer.vue",
          "app/pages/materials/products/index.vue",
          "app/components/materials/ProductThumbnail.vue",
          "app/pages/materials/products-v2/index.vue"
        ],
        "commitId" : "a8c0fc5da44e7a162e204825515022eba07c20fa",
        "timestamp" : 1792846799000,
        "author" : {
          "absoluteUrl" : "https://jenkins.younex.de/user/info",
          "fullName" : "info"
        },
        "authorEmail" : "info@younex.de",
        "comment" : "Products list: larger product thumbnails — ProductThumbnail takes a size via cellRendererParams (default 26 px unchanged elsewhere), picks the first Strapi format ≥ 2× the rendered size for sharp HiDPI output, rounded border + zoom-in cursor + hover enlarge, unscoped styles (AG Grid renderer); AgGridServer gets an optional rowHeight prop; /materials/products and /materials/products-v2 use 48 px thumbnails in a fixed 64 px column with 56 px rows\u000a",
        "date" : "2026-10-24 14:59:59 +0200",
        "id" : "a8c0fc5da44e7a162e204825515022eba07c20fa",
        "msg" : "Products list: larger product thumbnails — ProductThumbnail takes a size via cellRendererParams (default 26 px unchanged elsewhere), picks the first Strapi format ≥ 2× the rendered size for sharp HiDPI output, rounded border + zoom-in cursor + hover enlarge, unscoped styles (AG Grid renderer); AgGridServer gets an optional rowHeight prop; /materials/products and /materials/products-v2 use 48 px thumbnails in a fixed 64 px column with 56 px rows",
        "paths" : [
          {
            "editType" : "edit",
            "file" : "app/pages/materials/products/index.vue"
          },
          {
            "editType" : "edit",
            "file" : "app/components/AgGridServer.vue"
          },
          {
            "editType" : "edit",
            "file" : "app/components/materials/ProductThumbnail.vue"
          },
          {
            "editType" : "edit",
            "file" : "app/pages/materials/products-v2/index.vue"
          }
        ]
      },
      {
        "_class" : "hudson.plugins.git.GitChangeSet",
        "affectedPaths" : [
          "app/components/AgGrid/SalesOrder/AgCustomAttachment.vue",
          "app/components/AgGrid/SalesOrder/AgCustomTrackingNo.vue",
          ".claude/rules/sales/orders-grid.md",
          "server/api/orders/ag-grid/summary.post.ts",
          "app/pages/sales/orders/index.vue",
          "app/components/AgGridServer.vue",
          "app/components/sales/OrderAction.vue"
        ],
        "commitId" : "1f060bd74c0e4b59ff13eceefb3cbc1a1ed1f1c2",
        "timestamp" : 1792849499000,
        "author" : {
          "absoluteUrl" : "https://jenkins.younex.de/user/info",
          "fullName" : "info"
        },
        "authorEmail" : "info@younex.de",
        "comment" : "Sales orders grid: faster initial load and scroll blocks — summary endpoint enriches each 50-row block with one batched m_inout lookup (tracking no, shipment id/status, marketplace confirm log) and one batched Strapi attachments lookup (count + documentId), so the TrackingNo, Attachment and OrderAction cell renderers read row data instead of firing 3 requests per rendered row (105 on first paint, ~180 per two scroll steps); grid-ready latest-order-id now a 40 ms c_order top-1 query instead of an unfiltered summary call that summed all ~40k orders (2.5 s / 5 MB) on every page open; fees/revenue totals only on block 0 (AgGridServer sends withAggregates), $select on the view query (257 → 150 KB per block), debug log removed, organization auto-size once instead of every block, 150 ms block-load debounce; attachment files loaded on click only, per-row fallback kept when the Strapi batch is unavailable; voided check in the attachment tag now reads docStatusId; recipe .claude/rules/sales/orders-grid.md\u000a",
        "date" : "2026-10-24 15:44:59 +0200",
        "id" : "1f060bd74c0e4b59ff13eceefb3cbc1a1ed1f1c2",
        "msg" : "Sales orders grid: faster initial load and scroll blocks — summary endpoint enriches each 50-row block with one batched m_inout lookup (tracking no, shipment id/status, marketplace confirm log) and one batched Strapi attachments lookup (count + documentId), so the TrackingNo, Attachment and OrderAction cell renderers read row data instead of firing 3 requests per rendered row (105 on first paint, ~180 per two scroll steps); grid-ready latest-order-id now a 40 ms c_order top-1 query instead of an unfiltered summary call that summed all ~40k orders (2.5 s / 5 MB) on every page open; fees/revenue totals only on block 0 (AgGridServer sends withAggregates), $select on the view query (257 → 150 KB per block), debug log removed, organization auto-size once instead of every block, 150 ms block-load debounce; attachment files loaded on click only, per-row fallback kept when the Strapi batch is unavailable; voided check in the attachment tag now reads docStatusId; recipe .claude/rules/sales/orders-grid.md",
        "paths" : [
          {
            "editType" : "edit",
            "file" : "app/pages/sales/orders/index.vue"
          },
          {
            "editType" : "edit",
            "file" : "app/components/AgGridServer.vue"
          },
          {
            "editType" : "add",
            "file" : ".claude/rules/sales/orders-grid.md"
          },
          {
            "editType" : "edit",
            "file" : "app/components/AgGrid/SalesOrder/AgCustomTrackingNo.vue"
          },
          {
            "editType" : "edit",
            "file" : "server/api/orders/ag-grid/summary.post.ts"
          },
          {
            "editType" : "edit",
            "file" : "app/components/sales/OrderAction.vue"
          },
          {
            "editType" : "edit",
            "file" : "app/components/AgGrid/SalesOrder/AgCustomAttachment.vue"
          }
        ]
      },
      {
        "_class" : "hudson.plugins.git.GitChangeSet",
        "affectedPaths" : [
          "server/api/orders/ag-grid/so.post.ts",
          "server/api/orders/ag-grid/notfulfilled-5days.post.ts",
          "server/api/orders/ag-grid/notfulfilled-fastlane.post.ts",
          "server/api/orders/ag-grid/notfulfilled.post.ts",
          ".claude/rules/sales/orders-grid.md"
        ],
        "commitId" : "1b0d7dc4c3d37799ace553363f21cc62d6d1fdfb",
        "timestamp" : 1792849644000,
        "author" : {
          "absoluteUrl" : "https://jenkins.younex.de/user/info",
          "fullName" : "info"
        },
        "authorEmail" : "info@younex.de",
        "comment" : "Remove unused legacy orders ag-grid routes (so, notfulfilled, notfulfilled-5days, notfulfilled-fastlane) — no caller since the 2026-06-02 cleanup (page switched to ag-grid/summary), zero hits in 59 days of prod and dev web logs; they expanded c_orderline + m_inout child tables per block and copied the whole country table into every row\u000a",
        "date" : "2026-10-24 15:47:24 +0200",
        "id" : "1b0d7dc4c3d37799ace553363f21cc62d6d1fdfb",
        "msg" : "Remove unused legacy orders ag-grid routes (so, notfulfilled, notfulfilled-5days, notfulfilled-fastlane) — no caller since the 2026-06-02 cleanup (page switched to ag-grid/summary), zero hits in 59 days of prod and dev web logs; they expanded c_orderline + m_inout child tables per block and copied the whole country table into every row",
        "paths" : [
          {
            "editType" : "delete",
            "file" : "server/api/orders/ag-grid/so.post.ts"
          },
          {
            "editType" : "delete",
            "file" : "server/api/orders/ag-grid/notfulfilled-5days.post.ts"
          },
          {
            "editType" : "delete",
            "file" : "server/api/orders/ag-grid/notfulfilled.post.ts"
          },
          {
            "editType" : "delete",
            "file" : "server/api/orders/ag-grid/notfulfilled-fastlane.post.ts"
          },
          {
            "editType" : "edit",
            "file" : ".claude/rules/sales/orders-grid.md"
          }
        ]
      },
      {
        "_class" : "hudson.plugins.git.GitChangeSet",
        "affectedPaths" : [
          "server/api/idempiere-auth/webauthn/register-verify.post.ts",
          "server/api/admin/users/[id]/webauthn/index.get.ts",
          "server/api/idempiere-auth/webauthn/login-verify.post.ts",
          "server/api/idempiere-auth/webauthn/delete.delete.ts",
          "server/api/admin/webauthn/keys.get.ts",
          "server/api/idempiere-auth/webauthn/login-options.post.ts",
          "android/variables.gradle",
          "android/app/src/main/java/com/logship/mobile/WebAuthnPlugin.java",
          "server/utils/webauthnAdmin.ts",
          "app/composables/useWebAuthn.ts",
          "nuxt.config.ts",
          "android/app/src/main/java/com/logship/mobile/MainActivity.java",
          "server/utils/webauthnReplayDb.ts",
          ".claude/rules/auth/webauthn-security-keys.md",
          "app/plugins/00.capacitor-api.client.ts",
          "app/pages/users/security-keys/index.vue",
          "server/utils/webauthnChallengeStore.ts",
          "server/utils/adUserCredentials.ts",
          "app/assets/langs/shared.js",
          "app/pages/signin.vue",
          "app/pages/users/users/[id]/edit.vue",
          "server/api/admin/users/[id]/webauthn/destroy.delete.ts",
          ".env",
          "server/utils/webauthnHelper.ts",
          "app/components/users/SecurityKeys.vue",
          "public/.well-known/assetlinks.json",
          "android/app/build.gradle",
          "server/utils/webauthnIndex.ts",
          "server/api/admin/users/[id]/webauthn/register-options.post.ts",
          "app/composables/menu/admin/users.ts",
          "server/api/admin/users/[id]/webauthn/register-verify.post.ts",
          "server/api/idempiere-auth/webauthn/list.get.ts",
          ".env-prod"
        ],
        "commitId" : "af490f06fc09c720e7b0d3acf48c0554990aa4b4",
        "timestamp" : 1792853248000,
        "author" : {
          "absoluteUrl" : "https://jenkins.younex.de/user/info",
          "fullName" : "info"
        },
        "authorEmail" : "info@younex.de",
        "comment" : "Security-key login: PIN-free YubiKey tap on web + native Android app, admin enrolment and central overview — enrolment now creates non-discoverable, cross-platform credentials with userVerification 'discouraged' (a YubiKey only holds discoverable credentials with a PIN set and Chrome/Windows then prompt for it on every login); login-options sends the credential IDs of all enrolled keys (webauthnIndex.ts: service-token ad_user index, 60 s cache, cap WEBAUTHN_GLOBAL_ALLOWLIST_MAX=150, username-first fallback via needsUserName) and login-verify resolves the user by credential ID (userHandle only as legacy fallback), bumps counter + lastUsedAt; challenge token also returned in the body for cookie-less clients with a better-sqlite3 replay ledger (data/webauthn-replay.db); multiple accepted origins via WEBAUTHN_EXTRA_ORIGINS (Android android:apk-key-hash of the debug-keystore cert, assetlinks.json under public/.well-known); native app: WebAuthnPlugin.java on androidx.credentials (Credential Manager → Play services FIDO over NFC/USB), useWebAuthn routes create/get through it, login-verify delegates to app-auth/login for X-Logship-App requests and the app fetch plugin feeds that response into the session store (+ biometric unlock enrolment after a key login); tenant admins enrol/revoke keys for employees on the user edit page (admin/users/[id]/webauthn/*, isAdminRole gate, password capture with the service token) and on the new overview /users/security-keys (admin/webauthn/keys: all keys, last used, enrolled by, revoke, enrol for a picked employee; menu Users → Security Keys); sign-in page: key button first on devices that used a key before, clear cancel / not-enrolled / throttled messages, per-IP throttle on login-options; de/en/es texts reworded from passkey to security key; recipe .claude/rules/auth/webauthn-security-keys.md\u000a",
        "date" : "2026-10-24 16:47:28 +0200",
        "id" : "af490f06fc09c720e7b0d3acf48c0554990aa4b4",
        "msg" : "Security-key login: PIN-free YubiKey tap on web + native Android app, admin enrolment and central overview — enrolment now creates non-discoverable, cross-platform credentials with userVerification 'discouraged' (a YubiKey only holds discoverable credentials with a PIN set and Chrome/Windows then prompt for it on every login); login-options sends the credential IDs of all enrolled keys (webauthnIndex.ts: service-token ad_user index, 60 s cache, cap WEBAUTHN_GLOBAL_ALLOWLIST_MAX=150, username-first fallback via needsUserName) and login-verify resolves the user by credential ID (userHandle only as legacy fallback), bumps counter + lastUsedAt; challenge token also returned in the body for cookie-less clients with a better-sqlite3 replay ledger (data/webauthn-replay.db); multiple accepted origins via WEBAUTHN_EXTRA_ORIGINS (Android android:apk-key-hash of the debug-keystore cert, assetlinks.json under public/.well-known); native app: WebAuthnPlugin.java on androidx.credentials (Credential Manager → Play services FIDO over NFC/USB), useWebAuthn routes create/get through it, login-verify delegates to app-auth/login for X-Logship-App requests and the app fetch plugin feeds that response into the session store (+ biometric unlock enrolment after a key login); tenant admins enrol/revoke keys for employees on the user edit page (admin/users/[id]/webauthn/*, isAdminRole gate, password capture with the service token) and on the new overview /users/security-keys (admin/webauthn/keys: all keys, last used, enrolled by, revoke, enrol for a picked employee; menu Users → Security Keys); sign-in page: key button first on devices that used a key before, clear cancel / not-enrolled / throttled messages, per-IP throttle on login-options; de/en/es texts reworded from passkey to security key; recipe .claude/rules/auth/webauthn-security-keys.md",
        "paths" : [
          {
            "editType" : "edit",
            "file" : "android/app/src/main/java/com/logship/mobile/MainActivity.java"
          },
          {
            "editType" : "edit",
            "file" : "app/pages/users/users/[id]/edit.vue"
          },
          {
            "editType" : "add",
            "file" : "server/api/admin/users/[id]/webauthn/register-verify.post.ts"
          },
          {
            "editType" : "add",
            "file" : "android/app/src/main/java/com/logship/mobile/WebAuthnPlugin.java"
          },
          {
            "editType" : "edit",
            "file" : "nuxt.config.ts"
          },
          {
            "editType" : "add",
            "file" : "server/api/admin/users/[id]/webauthn/destroy.delete.ts"
          },
          {
            "editType" : "edit",
            "file" : "android/app/build.gradle"
          },
          {
            "editType" : "edit",
            "file" : "android/variables.gradle"
          },
          {
            "editType" : "edit",
            "file" : "server/api/idempiere-auth/webauthn/login-options.post.ts"
          },
          {
            "editType" : "edit",
            "file" : "server/utils/adUserCredentials.ts"
          },
          {
            "editType" : "add",
            "file" : "server/utils/webauthnIndex.ts"
          },
          {
            "editType" : "edit",
            "file" : "app/assets/langs/shared.js"
          },
          {
            "editType" : "add",
            "file" : "server/utils/webauthnAdmin.ts"
          },
          {
            "editType" : "edit",
            "file" : "app/composables/menu/admin/users.ts"
          },
          {
            "editType" : "add",
            "file" : "server/api/admin/users/[id]/webauthn/register-options.post.ts"
          },
          {
            "editType" : "edit",
            "file" : "server/utils/webauthnChallengeStore.ts"
          },
          {
            "editType" : "add",
            "file" : ".claude/rules/auth/webauthn-security-keys.md"
          },
          {
            "editType" : "edit",
            "file" : "server/api/idempiere-auth/webauthn/register-verify.post.ts"
          },
          {
            "editType" : "edit",
            "file" : "server/utils/webauthnHelper.ts"
          },
          {
            "editType" : "edit",
            "file" : "server/api/idempiere-auth/webauthn/list.get.ts"
          },
          {
            "editType" : "edit",
            "file" : "server/api/idempiere-auth/webauthn/login-verify.post.ts"
          },
          {
            "editType" : "add",
            "file" : "app/pages/users/security-keys/index.vue"
          },
          {
            "editType" : "edit",
            "file" : "app/plugins/00.capacitor-api.client.ts"
          },
          {
            "editType" : "edit",
            "file" : "server/api/idempiere-auth/webauthn/delete.delete.ts"
          },
          {
            "editType" : "edit",
            "file" : "app/components/users/SecurityKeys.vue"
          },
          {
            "editType" : "add",
            "file" : "server/utils/webauthnReplayDb.ts"
          },
          {
            "editType" : "edit",
            "file" : "app/pages/signin.vue"
          },
          {
            "editType" : "edit",
            "file" : ".env"
          },
          {
            "editType" : "edit",
            "file" : "app/composables/useWebAuthn.ts"
          },
          {
            "editType" : "add",
            "file" : "public/.well-known/assetlinks.json"
          },
          {
            "editType" : "add",
            "file" : "server/api/admin/webauthn/keys.get.ts"
          },
          {
            "editType" : "add",
            "file" : "server/api/admin/users/[id]/webauthn/index.get.ts"
          },
          {
            "editType" : "edit",
            "file" : ".env-prod"
          }
        ]
      },
      {
        "_class" : "hudson.plugins.git.GitChangeSet",
        "affectedPaths" : [
          "server/utils/webauthnHelper.ts"
        ],
        "commitId" : "94aa23a270d70300b2a4046f5e9c8c2009220e16",
        "timestamp" : 1792854035000,
        "author" : {
          "absoluteUrl" : "https://jenkins.younex.de/user/info",
          "fullName" : "info"
        },
        "authorEmail" : "info@younex.de",
        "comment" : "Security-key login: allow-list always advertises usb + nfc for roaming keys — Android Credential Manager only arms NFC when 'nfc' is hinted, and keys enrolled over USB on a desktop recorded ['usb'] only, so a tap on the phone opened the YubiKey's NDEF page instead of the FIDO ceremony\u000a",
        "date" : "2026-10-24 17:00:35 +0200",
        "id" : "94aa23a270d70300b2a4046f5e9c8c2009220e16",
        "msg" : "Security-key login: allow-list always advertises usb + nfc for roaming keys — Android Credential Manager only arms NFC when 'nfc' is hinted, and keys enrolled over USB on a desktop recorded ['usb'] only, so a tap on the phone opened the YubiKey's NDEF page instead of the FIDO ceremony",
        "paths" : [
          {
            "editType" : "edit",
            "file" : "server/utils/webauthnHelper.ts"
          }
        ]
      },
      {
        "_class" : "hudson.plugins.git.GitChangeSet",
        "affectedPaths" : [
          ".claude/rules/auth/webauthn-security-keys.md",
          "app/pages/signin.vue"
        ],
        "commitId" : "31ec1be9cb1a119633e43662b6c36de51ba55173",
        "timestamp" : 1792854221000,
        "author" : {
          "absoluteUrl" : "https://jenkins.younex.de/user/info",
          "fullName" : "info"
        },
        "authorEmail" : "info@younex.de",
        "comment" : "Security-key login: show the Credential Manager reason behind 'Key not recognised' in the native app (asset-link / provider failures looked like a missed tap); recipe: ISPConfig nginx denies dot paths — /.well-known/assetlinks.json proxy exception added by hand on the app/dev-app vhosts, verification URL, Play-services cache note\u000a",
        "date" : "2026-10-24 17:03:41 +0200",
        "id" : "31ec1be9cb1a119633e43662b6c36de51ba55173",
        "msg" : "Security-key login: show the Credential Manager reason behind 'Key not recognised' in the native app (asset-link / provider failures looked like a missed tap); recipe: ISPConfig nginx denies dot paths — /.well-known/assetlinks.json proxy exception added by hand on the app/dev-app vhosts, verification URL, Play-services cache note",
        "paths" : [
          {
            "editType" : "edit",
            "file" : ".claude/rules/auth/webauthn-security-keys.md"
          },
          {
            "editType" : "edit",
            "file" : "app/pages/signin.vue"
          }
        ]
      },
      {
        "_class" : "hudson.plugins.git.GitChangeSet",
        "affectedPaths" : [
          "app/pages/signin.vue",
          "android/app/src/main/AndroidManifest.xml",
          "android/app/build.gradle",
          ".claude/rules/auth/webauthn-security-keys.md",
          "android/variables.gradle",
          "android/app/src/main/java/com/logship/mobile/WebAuthnPlugin.java",
          "app/composables/useWebAuthn.ts",
          "app/assets/langs/shared.js"
        ],
        "commitId" : "c3ced8b1687b420a7491420a0c67db0716aa3045",
        "timestamp" : 1792859305000,
        "author" : {
          "absoluteUrl" : "https://jenkins.younex.de/user/info",
          "fullName" : "info"
        },
        "authorEmail" : "info@younex.de",
        "comment" : "Security-key login in the native app: own in-app YubiKey ceremony instead of the Android Credential Manager sheet — WebAuthnPlugin.java now runs CTAP2 getAssertion/makeCredential itself on YubiKit 3.1.0 (NFC reader mode with skipNdefCheck + USB discovery, own \"hold the key to the phone\" AlertDialog, raw Ctap2Session so a PIN-protected key is never asked for its PIN, allow-lists longer than maxCredentialCountInList probed in silent up=false chunks, connection loss keeps the dialog open for the next tap); the assertion signs for the web origin (public.apiBase = WEBAUTHN_ORIGIN) so no Play services, no asset links and no apk-key-hash origin are involved any more (mode 'system' keeps the Credential Manager path as fallback); NFC permission + optional nfc/usb-host features in the manifest; useWebAuthn passes origin, localized dialog texts and exposes cancelNative/capabilities, sign-in page cancels an open dialog on unmount; mobile web sign-in (≤768 px, not iOS, not in the app) shows an Android APK download card with the public manifest's version; de/en/es texts; recipe updated\u000a",
        "date" : "2026-10-24 18:28:25 +0200",
        "id" : "c3ced8b1687b420a7491420a0c67db0716aa3045",
        "msg" : "Security-key login in the native app: own in-app YubiKey ceremony instead of the Android Credential Manager sheet — WebAuthnPlugin.java now runs CTAP2 getAssertion/makeCredential itself on YubiKit 3.1.0 (NFC reader mode with skipNdefCheck + USB discovery, own \"hold the key to the phone\" AlertDialog, raw Ctap2Session so a PIN-protected key is never asked for its PIN, allow-lists longer than maxCredentialCountInList probed in silent up=false chunks, connection loss keeps the dialog open for the next tap); the assertion signs for the web origin (public.apiBase = WEBAUTHN_ORIGIN) so no Play services, no asset links and no apk-key-hash origin are involved any more (mode 'system' keeps the Credential Manager path as fallback); NFC permission + optional nfc/usb-host features in the manifest; useWebAuthn passes origin, localized dialog texts and exposes cancelNative/capabilities, sign-in page cancels an open dialog on unmount; mobile web sign-in (≤768 px, not iOS, not in the app) shows an Android APK download card with the public manifest's version; de/en/es texts; recipe updated",
        "paths" : [
          {
            "editType" : "edit",
            "file" : "android/app/src/main/java/com/logship/mobile/WebAuthnPlugin.java"
          },
          {
            "editType" : "edit",
            "file" : ".claude/rules/auth/webauthn-security-keys.md"
          },
          {
            "editType" : "edit",
            "file" : "app/pages/signin.vue"
          },
          {
            "editType" : "edit",
            "file" : "android/app/src/main/AndroidManifest.xml"
          },
          {
            "editType" : "edit",
            "file" : "android/app/build.gradle"
          },
          {
            "editType" : "edit",
            "file" : "app/composables/useWebAuthn.ts"
          },
          {
            "editType" : "edit",
            "file" : "android/variables.gradle"
          },
          {
            "editType" : "edit",
            "file" : "app/assets/langs/shared.js"
          }
        ]
      },
      {
        "_class" : "hudson.plugins.git.GitChangeSet",
        "affectedPaths" : [
          "app/composables/useWebAuthn.ts",
          "android/app/src/main/java/com/logship/mobile/WebAuthnPlugin.java"
        ],
        "commitId" : "8c5b5df7a2a21edbe63c6414c5a30f67e4fc6787",
        "timestamp" : 1792861176000,
        "author" : {
          "absoluteUrl" : "https://jenkins.younex.de/user/info",
          "fullName" : "info"
        },
        "authorEmail" : "info@younex.de",
        "comment" : "Security-key login (native app): never hide the key button — the YubiKit manager is created lazily (a throwing Plugin.load() makes Capacitor drop the whole plugin and the sign-in page silently lost the button), isAvailable() always resolves and reports nfc/usb/yubikit flags plus the init error text, the composable treats a rejected availability call as \"plugin unavailable\" and surfaces that reason on tap instead of hiding the button, dialog.show() guarded\u000a",
        "date" : "2026-10-24 18:59:36 +0200",
        "id" : "8c5b5df7a2a21edbe63c6414c5a30f67e4fc6787",
        "msg" : "Security-key login (native app): never hide the key button — the YubiKit manager is created lazily (a throwing Plugin.load() makes Capacitor drop the whole plugin and the sign-in page silently lost the button), isAvailable() always resolves and reports nfc/usb/yubikit flags plus the init error text, the composable treats a rejected availability call as \"plugin unavailable\" and surfaces that reason on tap instead of hiding the button, dialog.show() guarded",
        "paths" : [
          {
            "editType" : "edit",
            "file" : "app/composables/useWebAuthn.ts"
          },
          {
            "editType" : "edit",
            "file" : "android/app/src/main/java/com/logship/mobile/WebAuthnPlugin.java"
          }
        ]
      },
      {
        "_class" : "hudson.plugins.git.GitChangeSet",
        "affectedPaths" : [
          "app/pages/signin.vue",
          "server/api/mobile/app-download.get.ts"
        ],
        "commitId" : "e63b9d8bf517b17933a3beb7e4eef53d80275198",
        "timestamp" : 1792861753000,
        "author" : {
          "absoluteUrl" : "https://jenkins.younex.de/user/info",
          "fullName" : "info"
        },
        "authorEmail" : "info@younex.de",
        "comment" : "Sign-in Android download card: point at the CURRENT build in the ERP release channel — new public GET /api/mobile/app-download returns version + a 24 h signed download URL (data/mobile-releases via mobileReleases.ts), legacy www.logyou.de manifest only as fallback; the old public web root still served the September build 1.0.45, so the card would have handed out a stale APK\u000a",
        "date" : "2026-10-24 19:09:13 +0200",
        "id" : "e63b9d8bf517b17933a3beb7e4eef53d80275198",
        "msg" : "Sign-in Android download card: point at the CURRENT build in the ERP release channel — new public GET /api/mobile/app-download returns version + a 24 h signed download URL (data/mobile-releases via mobileReleases.ts), legacy www.logyou.de manifest only as fallback; the old public web root still served the September build 1.0.45, so the card would have handed out a stale APK",
        "paths" : [
          {
            "editType" : "edit",
            "file" : "app/pages/signin.vue"
          },
          {
            "editType" : "add",
            "file" : "server/api/mobile/app-download.get.ts"
          }
        ]
      },
      {
        "_class" : "hudson.plugins.git.GitChangeSet",
        "affectedPaths" : [
          "android/update-files/version.json",
          "android/app/build.gradle"
        ],
        "commitId" : "378885a48e4f902910fad004ab676b75d48e3466",
        "timestamp" : 1792861879000,
        "author" : {
          "absoluteUrl" : "https://jenkins.younex.de/user/info",
          "fullName" : "info"
        },
        "authorEmail" : "info@younex.de",
        "comment" : "release app 1.0.67 (code 68): in-app YubiKey security-key ceremony, Android download card\u000a",
        "date" : "2026-10-24 19:11:19 +0200",
        "id" : "378885a48e4f902910fad004ab676b75d48e3466",
        "msg" : "release app 1.0.67 (code 68): in-app YubiKey security-key ceremony, Android download card",
        "paths" : [
          {
            "editType" : "edit",
            "file" : "android/update-files/version.json"
          },
          {
            "editType" : "edit",
            "file" : "android/app/build.gradle"
          }
        ]
      }
    ],
    "kind" : "git"
  },
  "culprits" : [
    {
      "absoluteUrl" : "https://jenkins.younex.de/user/info",
      "fullName" : "info"
    }
  ]
}