Skip to content

Changes

Started by timer
Started 6 days 14 hr ago
Took 1 min 8 sec on built-in

Summary

  1. Generate shipments: shipper filter (queue-driven, same semantics as the qty-1 option) — openso-generation-queue accepts shipperIds + returns shipperId/shipperName; new 'Only selected shippers' option card with a logo multi-select (useShipperLogo composable centralises the carrier→logo mapping, fallback badge for unknown carriers), select all/clear + counter, submit gated until a shipper is picked, shipper shown in progress + result labels; options block restyled into 'Order filters' / 'Process options' groups with subtitle + ⓘ hover tooltip per option, previously hardcoded English options translated (en/de/es/ne) (details)
  2. Click-to-dial via FreePBX/Asterisk AMI + AD_User.SIP_Extension CRUD — new <DialButton> next to every phone field (user/lead/contact forms + views, partner contacts/locations, order ship-to phone, commission modal, search results, phone columns of the user/lead lists via AgDialPhone), visible only for system users with a SIP_Extension (server-authoritative gate via JWT + models/ad_user, 10-min cache); click opens a popover with the PBX extension chooser (DeviceStateList with live state joined with ERP user names, own extension preselected, free entry, remembered per browser) and dials: POST /api/telephony/dial originates PJSIP/<ext> (Local/<ext>@from-internal for dialplan-routed extensions) with the target as caller-id, returns right after the originate is accepted (1.5 s fast-fail window for an unreachable phone); a detached per-call AMI tracker follows OriginateResponse/DialBegin/DialEnd/Hangup via the inherited __LOGSHIP_CALL_ID channel var and writes a C_ContactActivity (type PC, reached/not reached + duration, German cause texts) on the called AD_User (or the partner's contact user) with the service token — fail-soft, unref'd timers, 3 h cap, per-process; new runtimeConfig.asterisk + CLICK_TO_DIAL_ENABLED/ASTERISK_* env keys; user pages: admin-only SIP extension field (internal tab, system users only, greyed for non-admins), retrieve/save wiring, view row, 'SIP Ext.' grid column, update/store routes gate the key on isAdminVerified; FreePBX: [logship] manager user (manager_custom.conf, LAN ACL, originate/call/reporting) + channelvars=LOGSHIP_CALL_ID in manager.conf (details)
  3. Lead activities: rich rendering of activity notes — new app/utils/activityFormat.ts (escape → linkify → decorate; safe for v-html) renders line-initial / '·'-separated 'Label:' as bold, 'Label (…): https://…' lines as a labelled link chip (e.g. the online confirmation / signing link) instead of the raw token URL, URLs and e-mail addresses as links, file names (.pdf/.docx/…) as badges, **bold**/_italic_ markers, blank lines as paragraph gaps; notes written as simple HTML (<b>, <i>, <u>, <a>, lists, <br>) are sanitised to a tag whitelist with http(s)/mailto hrefs only; LeadDetailRecordActivity.vue binds the formatter, adds a formatting hint + live preview in the note modal and the :deep styles (details)
  4. SEPA-Lastschriftmandat: opt-in contract annex + standalone send/fill/sign flow — new pdf-lib mandate (server/utils/offers/sepaPdf.ts: A4, branded, native fillable AcroForm fields for company/account holder/address/IBAN/BIC/bank/place-date, signed variant sets values, draws the signature, adds a protocol line and flattens), DE/EN mandate wording per DK/EPC (sepaTexts.ts: CORE with 8-week refund notice / B2B without, pre-notification line, 36-month lapse), IBAN validation in app/utils/iban.ts (ISO 13616 per-country lengths, MOD 97-10, SEPA country set, BIC check) used live in the portals and re-checked server-side; (1) contract package: 'Anlage 4 — SEPA-Lastschriftmandat' checkbox in ContractModal (default off, scheme B2B/CORE + payment type + pre-notification days), assembled by contractPackage.ts, mandate stored on the signing row, /sign portal gets step 1b (account holder, IBAN, BIC, bank) + two mandate declarations, finalizeSignature renders the filled+signed mandate, attaches it to the record and patches offer_conditions.sepa (masked IBAN); (2) standalone: SepaMandateModal ('SEPA' button on the partner and lead pages, DE default/EN, prefill from partner contacts + location, preview) → POST /api/offers/sepa/send (signing kind 'sepa', mail with /sepa/<token>, blank mandate attached to the record, activity) → public /sepa/<token> portal + routes (fill, validate, sign) → finalizeSepaMandate attaches the signed PDF to the sending C_BPartner / lead user, logs an activity, mails customer + info@; signing-status + SigningLinksPanel know kind 'sepa' (panel now also on the partner page); runtimeConfig.sepa + SEPA_CREDITOR_ID/SEPA_PRENOTIFICATION_DAYS env keys (creditor id still to be filled in) (details)
  5. Recipes: click-to-dial (FreePBX AMI, <DialButton>, PBX gotchas) and SEPA mandate (contract annex + standalone portal, IBAN check, creditor id) (details)
  6. Profile: system users can set their own SIP extension (click-to-dial) on /users/profile → Contact tab — field shown only for IsSystemUser records, saved via the profile's existing PUT; update.put.ts accepts sipExtension for the caller's own record (JWT AD_User_ID = body.id) in addition to verified admins (details)
  7. Top bar quick dial (admins with a SIP extension): number input left of the user menu — Enter dials with the own extension, the dial button opens the extension chooser; hidden for non-admins and users who cannot dial; error-boundaried like the chat badge (details)
  8. Dashboard 'Letzte Anrufe' card (admin roles) + quick dial placed in the top bar — new GET /api/telephony/recent-calls reads the FreePBX CDR via a read-only MariaDB user (mysql2, PBX_CDR_* env) and reduces the many per-leg cdr rows to ONE entry per call (grouped by linkedid; inbound/outbound by trunk channel, answered = ANSWERED Dial leg with billsec>0 to a device), showing the last 20 missed inbound + successful outbound calls (all/in/out filter, missed badge, extension + duration, auto-refresh 60 s, 30 s server cache); numbers are clickable (click-to-dial with the own extension) plus a chooser button per row; QuickDial moved into the TopMegaBar user-menu container (the app layout uses TopMegaBar, not NewNavBar) so it renders left of the user menu; caller-id names stripped of the PBX 'LogYou:' / 'Anruf:' prefixes; recipe note (details)
  9. Dashboard: first row now Open Orders (0.9fr, ≈−10 %) · tickets (0.6fr, ≈−40 %) · recent-calls card (0.7fr) side by side; tickets fullscreen button commented out for now; recent-calls card limited to the last 10 calls, clicking a number opens the dial popover (own extension from the profile preselected, call starts only after 'Anrufen') instead of dialing immediately, and phone numbers are matched to ERP contacts asynchronously after render via new POST /api/telephony/match-contacts (Elasticsearch ad_user index, regexp on the keyword phone/phone2 fields, fail-soft) — matched names shown with a contact icon and passed as the activity target; DialButton gains a default slot to use custom trigger content (the number text) (details)
  10. Demo screens for the Stücklisten/Set feature (app/pages/demo) (details)
  11. Dashboard call card + first row: uniform column starts (the slot-trigger DialButton was stretched/centered by the flex column → left-aligned, fixed 96px meta column with right-aligned duration/missed), slim low headers on the whole first row (title only, icon 30px; the subtitles move into a header tooltip — calls card tooltip = title / blank line / subtitle / missed count), tickets card header now just 'Tickets', call date shown as Heute / Gestern / dd.MM.yy without time (full weekday + date + time as hover tooltip), matched contact name is now a button opening a teleported menu 'Als Lead öffnen / Als Benutzer öffnen' (+ 'Partner bearbeiten / ansehen' when a C_BPartner is linked) — match-contacts enriches the ES hit with IsSalesLead/IsVendorLead + C_BPartner_ID name from iDempiere (fail-soft) so the known record kind is listed first (details)
  12. Lead page 'Aufnahmen': call recordings + whisper transcription — new components/telephony/CallRecordingsModal.vue (button + CTA on /edit/lead-<id>): step 1 lists every FreePBX recording matched by the lead's phone numbers (all pre-selected, single rows can be unticked, in-app audio player + download per row, language select DE/EN/ES/auto), 'Transkribieren' runs the selected ones one after the other through the server whisper.cpp pipeline with real progress, step 2 shows the transcripts to read (optional timestamps), copy and download (single / all as one .txt). Server: server/utils/telephony/recordings.ts (CDR lookup recordingfile<>'' + src/dst suffix match, one row per file, stat on the PBX drops missing/44-byte never-answered files, transcript cache data/call-transcripts/<file>.json, serial whisper queue, timeout 3× audio length), routes telephony/recordings/{index.get,transcribe.post,audio.get} gated by gateFromEvent (staff), chatTranscribe.ts gains transcribeAudioDetailed() (text + timestamped segments, timeout/extra-args options; transcribeAudio() is the wrapper) and no longer converts a .wav onto itself (ffmpeg refused in-place edits); PBX side: /opt/logship-ivr/recordings.js on 192.168.12.73 (systemd logship-recordings, port 8096, LAN allow-list + X-IVR-Secret = IVR_SHARED_SECRET, POST /recordings/stat because Node 8 caps headers at 8 KB, GET /recordings/file/<name>, read-only); runtimeConfig.pbxRecordings + PBX_RECORDINGS_URL env; lead page now defines t (useTranslation) which the SEPA title already referenced; rec_* translations en/de; recipe (details)
Commit f263d5555ef9086194f5d605f8dd33374754d72b by info
Generate shipments: shipper filter (queue-driven, same semantics as the qty-1 option) — openso-generation-queue accepts shipperIds + returns shipperId/shipperName; new 'Only selected shippers' option card with a logo multi-select (useShipperLogo composable centralises the carrier→logo mapping, fallback badge for unknown carriers), select all/clear + counter, submit gated until a shipper is picked, shipper shown in progress + result labels; options block restyled into 'Order filters' / 'Process options' groups with subtitle + ⓘ hover tooltip per option, previously hardcoded English options translated (en/de/es/ne)
The file was modifiedapp/pages/generate-shipments.vue (diff)
The file was modifiedserver/api/orders/openso-generation-queue.get.ts (diff)
The file was addedapp/composables/useShipperLogo.ts
The file was modifiedapp/assets/langs/shared.js (diff)
Commit bd0aee220aeaa8e0f4543e7a844a66569e7a0f32 by info
Click-to-dial via FreePBX/Asterisk AMI + AD_User.SIP_Extension CRUD — new <DialButton> next to every phone field (user/lead/contact forms + views, partner contacts/locations, order ship-to phone, commission modal, search results, phone columns of the user/lead lists via AgDialPhone), visible only for system users with a SIP_Extension (server-authoritative gate via JWT + models/ad_user, 10-min cache); click opens a popover with the PBX extension chooser (DeviceStateList with live state joined with ERP user names, own extension preselected, free entry, remembered per browser) and dials: POST /api/telephony/dial originates PJSIP/<ext> (Local/<ext>@from-internal for dialplan-routed extensions) with the target as caller-id, returns right after the originate is accepted (1.5 s fast-fail window for an unreachable phone); a detached per-call AMI tracker follows OriginateResponse/DialBegin/DialEnd/Hangup via the inherited __LOGSHIP_CALL_ID channel var and writes a C_ContactActivity (type PC, reached/not reached + duration, German cause texts) on the called AD_User (or the partner's contact user) with the service token — fail-soft, unref'd timers, 3 h cap, per-process; new runtimeConfig.asterisk + CLICK_TO_DIAL_ENABLED/ASTERISK_* env keys; user pages: admin-only SIP extension field (internal tab, system users only, greyed for non-admins), retrieve/save wiring, view row, 'SIP Ext.' grid column, update/store routes gate the key on isAdminVerified; FreePBX: [logship] manager user (manager_custom.conf, LAN ACL, originate/call/reporting) + channelvars=LOGSHIP_CALL_ID in manager.conf
The file was modifiedapp/pages/users/users/[id]/duplicate.vue (diff)
The file was modifiedapp/pages/users/users/[id]/edit.vue (diff)
The file was addedserver/utils/telephony/phoneActivity.ts
The file was addedapp/composables/useClickToDial.ts
The file was modifiedapp/pages/users/leads/index.vue (diff)
The file was addedserver/utils/telephony/extensions.ts
The file was addedapp/components/DialButton.vue
The file was modifiedapp/components/admin/LeadForm.vue (diff)
The file was modifiedapp/pages/users/external-users/[id]/duplicate.vue (diff)
The file was modifiedserver/api/admin/users/store.post.ts (diff)
The file was modifiedapp/pages/users/leads/[id]/view.vue (diff)
The file was modified.env-dev (diff)
The file was modifiedapp/pages/users/users/create.vue (diff)
The file was modifiedapp/components/SearchModal.vue (diff)
The file was addedserver/api/telephony/extensions.get.ts
The file was modifiedapp/pages/users/external-users/[id]/edit.vue (diff)
The file was modified.env-prod (diff)
The file was modifiedapp/components/integrations/CommissionModal.vue (diff)
The file was modifiedapp/pages/users/leads/[id]/edit.vue (diff)
The file was modifiedapp/pages/users/users/[id]/view.vue (diff)
The file was modifiedapp/assets/langs/shared.js (diff)
The file was modified.env (diff)
The file was modifiedapp/pages/users/external-users/index.vue (diff)
The file was addedserver/utils/telephony/callTracker.ts
The file was addedapp/components/AgGrid/AgDialPhone.vue
The file was modifiedapp/components/admin/UserForm.vue (diff)
The file was modifiedapp/components/partners/PartnerDetailRecordUser.vue (diff)
The file was modifiedapp/pages/users/external-users/[id]/view.vue (diff)
The file was addedserver/api/telephony/dial.post.ts
The file was addedserver/api/telephony/me.get.ts
The file was modifiedapp/components/sales/OrderForm.vue (diff)
The file was addedserver/utils/telephony/amiClient.ts
The file was modifiedapp/components/partners/PartnerDetailRecordLocation.vue (diff)
The file was modifiedapp/pages/users/external-users/create.vue (diff)
The file was modifiednuxt.config.ts (diff)
The file was modifiedserver/api/admin/users/update.put.ts (diff)
The file was modifiedapp/pages/users/users/index.vue (diff)
The file was addedserver/utils/telephony/dialAccess.ts
Commit 9a43b22bbf9db5090902c079f1d6bcf0c76fca38 by info
Lead activities: rich rendering of activity notes — new app/utils/activityFormat.ts (escape → linkify → decorate; safe for v-html) renders line-initial / '·'-separated 'Label:' as bold, 'Label (…): https://…' lines as a labelled link chip (e.g. the online confirmation / signing link) instead of the raw token URL, URLs and e-mail addresses as links, file names (.pdf/.docx/…) as badges, **bold**/_italic_ markers, blank lines as paragraph gaps; notes written as simple HTML (<b>, <i>, <u>, <a>, lists, <br>) are sanitised to a tag whitelist with http(s)/mailto hrefs only; LeadDetailRecordActivity.vue binds the formatter, adds a formatting hint + live preview in the note modal and the :deep styles
The file was modifiedapp/components/admin/LeadDetailRecordActivity.vue (diff)
The file was addedapp/utils/activityFormat.ts
Commit 0a58e7b9aa9f7f3a6ab93112d2d85788ab0b62e4 by info
SEPA-Lastschriftmandat: opt-in contract annex + standalone send/fill/sign flow — new pdf-lib mandate (server/utils/offers/sepaPdf.ts: A4, branded, native fillable AcroForm fields for company/account holder/address/IBAN/BIC/bank/place-date, signed variant sets values, draws the signature, adds a protocol line and flattens), DE/EN mandate wording per DK/EPC (sepaTexts.ts: CORE with 8-week refund notice / B2B without, pre-notification line, 36-month lapse), IBAN validation in app/utils/iban.ts (ISO 13616 per-country lengths, MOD 97-10, SEPA country set, BIC check) used live in the portals and re-checked server-side; (1) contract package: 'Anlage 4 — SEPA-Lastschriftmandat' checkbox in ContractModal (default off, scheme B2B/CORE + payment type + pre-notification days), assembled by contractPackage.ts, mandate stored on the signing row, /sign portal gets step 1b (account holder, IBAN, BIC, bank) + two mandate declarations, finalizeSignature renders the filled+signed mandate, attaches it to the record and patches offer_conditions.sepa (masked IBAN); (2) standalone: SepaMandateModal ('SEPA' button on the partner and lead pages, DE default/EN, prefill from partner contacts + location, preview) → POST /api/offers/sepa/send (signing kind 'sepa', mail with /sepa/<token>, blank mandate attached to the record, activity) → public /sepa/<token> portal + routes (fill, validate, sign) → finalizeSepaMandate attaches the signed PDF to the sending C_BPartner / lead user, logs an activity, mails customer + info@; signing-status + SigningLinksPanel know kind 'sepa' (panel now also on the partner page); runtimeConfig.sepa + SEPA_CREDITOR_ID/SEPA_PRENOTIFICATION_DAYS env keys (creditor id still to be filled in)
The file was addedapp/components/offers/SepaMandateModal.vue
The file was addedserver/api/offers/sepa/preview.post.ts
The file was modifiedapp/pages/sign/[token].vue (diff)
The file was modifiedserver/utils/offers/contractPackage.ts (diff)
The file was modified.env-dev (diff)
The file was modifiedapp/pages/partners/partners/[id]/edit.vue (diff)
The file was addedserver/utils/offers/sepaTexts.ts
The file was modifiedserver/api/offers/contract/send.post.ts (diff)
The file was modifiedserver/api/public/sign/[token]/index.get.ts (diff)
The file was addedserver/api/offers/sepa/send.post.ts
The file was modifiedapp/components/offers/SigningLinksPanel.vue (diff)
The file was modifiedapp/components/offers/ContractModal.vue (diff)
The file was modifiedserver/utils/offers/contractSigning.ts (diff)
The file was addedserver/utils/offers/sepaPdf.ts
The file was modifiedserver/utils/offers/contractSigningDb.ts (diff)
The file was addedserver/utils/offers/sepaMandate.ts
The file was modified.env (diff)
The file was modifiedapp/pages/users/leads/[id]/edit.vue (diff)
The file was modifiedapp/composables/useOfferContract.ts (diff)
The file was modifiedserver/api/offers/contract/signing-status.get.ts (diff)
The file was addedapp/utils/iban.ts
The file was addedserver/api/public/sepa/[token]/index.get.ts
The file was addedapp/pages/sepa/[token].vue
The file was modifiednuxt.config.ts (diff)
The file was addedserver/api/public/sepa/[token]/request-renewal.post.ts
The file was modifiedapp/assets/langs/shared.js (diff)
The file was addedserver/api/public/sepa/[token]/index.post.ts
The file was addedserver/api/public/sepa/[token]/document/[key].get.ts
The file was modified.env-prod (diff)
The file was modifiedserver/api/public/sign/[token]/index.post.ts (diff)
Commit 1cb4bf0a8ddba51fba801514f9cb3269bbca259c by info
Recipes: click-to-dial (FreePBX AMI, <DialButton>, PBX gotchas) and SEPA mandate (contract annex + standalone portal, IBAN check, creditor id)
The file was modifiedreference/recipes.md (diff)
Commit a419d4d00e539ecd68e844a02e2fcbf3944828b9 by info
Profile: system users can set their own SIP extension (click-to-dial) on /users/profile → Contact tab — field shown only for IsSystemUser records, saved via the profile's existing PUT; update.put.ts accepts sipExtension for the caller's own record (JWT AD_User_ID = body.id) in addition to verified admins
The file was modifiedserver/api/admin/users/update.put.ts (diff)
The file was modifiedapp/components/dashboard/ProfileForm.vue (diff)
The file was modifiedapp/pages/users/profile/index.vue (diff)
Commit 9e9dac38e431a6bed27c32b76c6319179633d87d by info
Top bar quick dial (admins with a SIP extension): number input left of the user menu — Enter dials with the own extension, the dial button opens the extension chooser; hidden for non-admins and users who cannot dial; error-boundaried like the chat badge
The file was addedapp/components/QuickDial.vue
The file was modifiedapp/components/NewNavBar.vue (diff)
The file was modifiedapp/assets/langs/shared.js (diff)
Commit 591fe6109509809117dc5b97cb1136ef33ba8472 by info
Dashboard 'Letzte Anrufe' card (admin roles) + quick dial placed in the top bar — new GET /api/telephony/recent-calls reads the FreePBX CDR via a read-only MariaDB user (mysql2, PBX_CDR_* env) and reduces the many per-leg cdr rows to ONE entry per call (grouped by linkedid; inbound/outbound by trunk channel, answered = ANSWERED Dial leg with billsec>0 to a device), showing the last 20 missed inbound + successful outbound calls (all/in/out filter, missed badge, extension + duration, auto-refresh 60 s, 30 s server cache); numbers are clickable (click-to-dial with the own extension) plus a chooser button per row; QuickDial moved into the TopMegaBar user-menu container (the app layout uses TopMegaBar, not NewNavBar) so it renders left of the user menu; caller-id names stripped of the PBX 'LogYou:' / 'Anruf:' prefixes; recipe note
The file was modifiednuxt.config.ts (diff)
The file was addedapp/components/dashboard/RecentCallsCard.vue
The file was modified.env (diff)
The file was modified.env-dev (diff)
The file was modifiedapp/pages/index.vue (diff)
The file was addedserver/api/telephony/recent-calls.get.ts
The file was modified.env-prod (diff)
The file was modifiedpackage.json (diff)
The file was modifiedpackage-lock.json (diff)
The file was addedserver/utils/telephony/cdr.ts
The file was modifiedapp/assets/langs/shared.js (diff)
The file was modifiedreference/recipes.md (diff)
The file was modifiedapp/components/TopMegaBar.vue (diff)
Commit 2f23a38d108cdab644854df9215c2bc74095ea38 by info
Dashboard: first row now Open Orders (0.9fr, ≈−10 %) · tickets (0.6fr, ≈−40 %) · recent-calls card (0.7fr) side by side; tickets fullscreen button commented out for now; recent-calls card limited to the last 10 calls, clicking a number opens the dial popover (own extension from the profile preselected, call starts only after 'Anrufen') instead of dialing immediately, and phone numbers are matched to ERP contacts asynchronously after render via new POST /api/telephony/match-contacts (Elasticsearch ad_user index, regexp on the keyword phone/phone2 fields, fail-soft) — matched names shown with a contact icon and passed as the activity target; DialButton gains a default slot to use custom trigger content (the number text)
The file was modifiedapp/components/dashboard/RecentCallsCard.vue (diff)
The file was modifiedapp/pages/index.vue (diff)
The file was addedserver/api/telephony/match-contacts.post.ts
The file was modifiedapp/components/DialButton.vue (diff)
Commit 57d1db967c449a684860b40699282d50920ca919 by info
Demo screens for the Stücklisten/Set feature (app/pages/demo)

/demo hub lists real IsBOM articles; /demo/set-builder is a Set-Builder template in quick-order positions style with real product search, component quantities and stock, set image proposals from component photos, and an order-import preview. Public route, no backend writes. Used for logyou.de/leistungen/stuecklisten-bom.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CdyiVTWYfCkMzH8rJyc5Pq
The file was addedapp/pages/demo/index.vue
The file was addedapp/pages/demo/set-builder.vue
Commit 75a8a5218182d36766c28dd6046e1320a158e6f1 by info
Dashboard call card + first row: uniform column starts (the slot-trigger DialButton was stretched/centered by the flex column → left-aligned, fixed 96px meta column with right-aligned duration/missed), slim low headers on the whole first row (title only, icon 30px; the subtitles move into a header tooltip — calls card tooltip = title / blank line / subtitle / missed count), tickets card header now just 'Tickets', call date shown as Heute / Gestern / dd.MM.yy without time (full weekday + date + time as hover tooltip), matched contact name is now a button opening a teleported menu 'Als Lead öffnen / Als Benutzer öffnen' (+ 'Partner bearbeiten / ansehen' when a C_BPartner is linked) — match-contacts enriches the ES hit with IsSalesLead/IsVendorLead + C_BPartner_ID name from iDempiere (fail-soft) so the known record kind is listed first
The file was modifiedserver/api/telephony/match-contacts.post.ts (diff)
The file was modifiedapp/pages/index.vue (diff)
The file was modifiedapp/components/dashboard/RecentCallsCard.vue (diff)
Commit d626e2ef330acc638feb470c8d8c8d79fe8c6845 by info
Lead page 'Aufnahmen': call recordings + whisper transcription — new components/telephony/CallRecordingsModal.vue (button + CTA on /edit/lead-<id>): step 1 lists every FreePBX recording matched by the lead's phone numbers (all pre-selected, single rows can be unticked, in-app audio player + download per row, language select DE/EN/ES/auto), 'Transkribieren' runs the selected ones one after the other through the server whisper.cpp pipeline with real progress, step 2 shows the transcripts to read (optional timestamps), copy and download (single / all as one .txt). Server: server/utils/telephony/recordings.ts (CDR lookup recordingfile<>'' + src/dst suffix match, one row per file, stat on the PBX drops missing/44-byte never-answered files, transcript cache data/call-transcripts/<file>.json, serial whisper queue, timeout 3× audio length), routes telephony/recordings/{index.get,transcribe.post,audio.get} gated by gateFromEvent (staff), chatTranscribe.ts gains transcribeAudioDetailed() (text + timestamped segments, timeout/extra-args options; transcribeAudio() is the wrapper) and no longer converts a .wav onto itself (ffmpeg refused in-place edits); PBX side: /opt/logship-ivr/recordings.js on 192.168.12.73 (systemd logship-recordings, port 8096, LAN allow-list + X-IVR-Secret = IVR_SHARED_SECRET, POST /recordings/stat because Node 8 caps headers at 8 KB, GET /recordings/file/<name>, read-only); runtimeConfig.pbxRecordings + PBX_RECORDINGS_URL env; lead page now defines t (useTranslation) which the SEPA title already referenced; rec_* translations en/de; recipe
The file was addedserver/api/telephony/recordings/audio.get.ts
The file was addedserver/api/telephony/recordings/transcribe.post.ts
The file was modifiedserver/utils/chatTranscribe.ts (diff)
The file was modifiedapp/pages/users/leads/[id]/edit.vue (diff)
The file was addedapp/components/telephony/CallRecordingsModal.vue
The file was modified.env-prod (diff)
The file was modified.env (diff)
The file was modifiedreference/recipes.md (diff)
The file was addedserver/api/telephony/recordings/index.get.ts
The file was modifiedserver/utils/telephony/cdr.ts (diff)
The file was modified.env-dev (diff)
The file was modifiednuxt.config.ts (diff)
The file was addedserver/utils/telephony/recordings.ts
The file was modified.gitignore (diff)
The file was modifiedapp/assets/langs/shared.js (diff)