Issue Tracker
Overview
Issue Tracker is BigLedger’s own work-tracking applet: projects, issue types, sprints, labelled
issues with comments, worklogs, attachments and sub-tasks, a drag-and-drop kanban board and an
issues report. It is a TNT-USER applet, so it runs inside a tenant, but it is built for a
support desk that tracks issues on behalf of several customer tenants: every issue carries the
customer tenant it belongs to, a Tenants switcher at the top of the menu filters the list to one
of them, and a platform-level table decides which customer tenants each login may see. An optional
two-way sync mirrors issues into GitHub Issues and a GitHub Projects V2 board.
Nothing here posts a journal, moves stock or creates a financial document. Issue Tracker is the
back-office face of the same bl_wf_issue_hdr table that the
Unified Contact Center’s Issue Tracker panel
writes to, and the two applets share the same Application Settings → Issue Category screen.
Measured 2026-09-16: 13 active catalogue links across 7 tenants; 2 logins hold a user-tenant link; no GitHub repository link exists yet.
bl_applet_hdr.property_json.es_module_url for
IssueTrackerApplet points at …/issue-tracker-applet/staging/staging/…-elements-staging.js.gz,
the path the repository’s staging publish script writes to; the production script publishes to
…/issue-tracker-applet/production/. Every production tenant therefore loads whatever was last
pushed to staging. Recorded in the registry-hygiene findings (LA4-P-14a).Where it fits
| Direction | What | Why |
|---|---|---|
| Same table | Unified Contact Center — Issue Tracker panel | An agent raising an issue from a conversation writes the same bl_wf_issue_hdr row; the eleven category-group slots are configured once and read by both applets. |
| Platform data | Platform SysAdmin / Tenants V2 | The Tenants switcher lists rows from app_tenant_hdr; the user-tenant and repository-tenant links live in akaun_master. |
| Scheduling | Scheduler | The GitHub reconciliation job is a bl_sch_crontab_hdr row in the tenant with queue code GITHUB_TO_ISSUE_HDR_SYNC_CRON_PROCESSOR. |
| External | GitHub Issues and Projects V2 | Outbound push from a dedicated queue table; inbound by signed webhook plus the reconciliation job. |
Screens and menus
The application title bar reads Issue Tracker Applet; the registry name is Issue Tracker.
app.routing.ts L45 sets the main path to applets/akaun/issue-tracker-applet, matching the
registry routerLink. On open the applet redirects to Issues (L262–L266).
Start-up gate. Before any screen is useful the applet loads the login’s user-tenant links from
akaun_master (tenant.effects.ts L140–L172). A login with no ACTIVE link gets a dialog that
cannot be closed — “You do not have permission to access any tenants. Please contact your
administrator.” — and re-opens itself if dismissed (app.component.ts L104–L121). With exactly
one link the tenant is auto-selected; with several, the is_default row wins, then the most recent
last_access_date, else a tenant-selection dialog (tenant.effects.ts L177–L219). Selecting a
tenant writes last_access_date on the link row (L72–L107).
Main menu (menu-items.ts)
| Menu item | Route | What it shows |
|---|---|---|
| Tenants | — (drop-down with a search box) | The customer tenants this login is linked to, from app_tenant_hdr filtered by the link table. Selecting one filters the Issues list to that tenant and stamps new issues with it. |
| Dashboard → Main-Dashboard | dashboard/main-dashboard | KPI strip (Total / To Do / In Progress / Pending / Done), filters (date from/to, assignee — default current user, sprint, status), three tabs: Board (kanban, cdkDropList columns), Worklogs, Analytics. New Issue opens the quick-create dialog and is disabled with the tooltip Please select a tenant first until a tenant is selected. |
| Dashboard → Issues Report | dashboard/dashboard-issues-report | A tree grid of issues with their worklogs as child rows; filters date from/to (both required before Reload enables), assignee, status, sprint; New Issue and Sync selected to GitHub. Columns: Issue Title, Issue Status, Assignee, Project, Sprint, Issue Key, Reporter, Issue Type, Create Date, Update Date, plus one column per issue category group. |
| Projects | projects | Project listing, create and edit (tabs Details, People, Issue Types, Notifications). The create page’s title reads Add Project 2. |
| Issues | issues | Server-side issue listing with Sync selected to GitHub; Add and row-click both open the issue detail page. |
| Categories | category-listing | Issue categories (bl_wf_issue_label_hdr), with a tree parent picker. |
| Category Groups | group-category-listing | Category groups (bl_wf_issue_label_list_hdr, namespace WF_CATEGORY), with a Categories tab listing the group’s children. |
Issue detail page
issues/:tenantCode/:issueGuid (app.routing.ts L73–L85) is the only issue create/edit screen.
:issueGuid = new is create mode. The older Issue Create and Issue Edit view columns were
removed from the page stack (issue-pages.service.ts L50–L52) and are unreachable; the quick-create
dialog survives on the two dashboards.
The page is GitHub-shaped: click-to-edit title, a rich-text description, attachments in the main
pane, a Details card in the sidebar (Assignee, Reporter, GitHub Repository, Project, Sprint,
Label 1–3), a More Details block of custom fields, and three tabs — Comments, History
(bl_wf_issue_event rows) and Worklogs (description, hours 0–24 in 0.5 steps, date). Buttons:
New Issue, Sync with GitHub, Create Issue / Cancel in create mode, Save Changes / Cancel
when the sidebar has unsaved edits.
Status is shown only as a read-only badge (issue-detail.component.html L66–L68); there is no
control on this page for status, priority or issue type — the handlers exist
(issue-detail.component.ts L1214, L1240, L1671) but nothing in the template calls them. Status
changes are made by dragging a card between kanban columns; issue type is set only by the
quick-create dialog.
Settings (gear)
The vendored shared settings navigation (shared-utilities/modules/settings/settings.component.html)
hard-codes an Issue Tracker Settings group — Projects, Issue Types, Project Categories, Users,
Teams, Sprint, User Tenant, Tenant Repository Link, Custom Fields Placement, Kanban Board — above
the System Configuration group from settingItems (Application Settings, Field Settings, Default
Selection), the shared Applet Access, the four server-side permission listings, Triggers
(webhooks), and two Developer Tools links (Applet Log, Reset Applet State) that route to
404.
The Kanban Board link is behind *ngIf="isKanbanBoardAdmin". settings-container.component.ts
L49 sets that flag with (result?.totalRecords || 0) >= 0, which is always true, so the link shows
to everyone; the dashboard’s own copy of the same check (main-dashboard.effects.ts L162) uses
> 0 and is the one that actually gates board administration.
The Projects screen under Settings is a second copy of the Projects screen: its edit page has only Details and Notifications (People and Issue Types are commented out, the Delete button too), and its create page drops the Project Key on save. Use the main-menu Projects screen.
Personalization
Field Settings (routes to the same unbound stub as Settings), Default Selection, Sidebar; the
Preset Themes, Color Assist and Easy Navigation links route to 404. Profiles → My Profile
is routed but linked from nowhere (its menu entry is commented out); it shows a read-only About Me
tab. A Plans component tree exists in the repository with no route, no module import and empty
templates.
Configuration
Before you can use it
| Prerequisite | Where | Without it |
|---|---|---|
An ACTIVE row in bl_module_wf_issue_user_tenant_link (akaun_master) for the login and each customer tenant it may see | Settings → User Tenant in this applet (platform endpoint core2/platform/dm/wf/issue-user-tenant-links/backoffice-ep) | The non-closeable no tenants dialog at start-up; the issue query also returns empty (WFIssueHdrController.java L243–L250). |
MST_API_TNT_MGT_TENANT_READ on the tenant rows the login is linked to | Platform permission tables | GET core2/platform/dm/tenants/query replaces each row the caller may not read with a stub carrying only the guid and status PERMISSION_DENIED (TenantController.java L85–L93, L402–L424), so the Tenants switcher has entries with no code or name and the selected tenant code is blank. |
| Server-side WF permissions for the login’s role | Settings → Server Side Permissions | Every endpoint in the table under Feature visibility / permissions returns not authorised. |
| At least one Project (with a Key) and one Issue Type | Projects; Settings → Issue Types | The quick-create dialog requires both; the detail page requires a project. The issue number is a per-project sequence, so a project with no key shares one counter bucket (WFIssueHdrUow.java L48–L57). |
Issue category groups in namespace WF_CATEGORY | Category Groups | Application Settings → Issue Category has nothing to select; the Issues Report has no category columns. |
For GitHub sync: app_cfg_main rows GITHUB_LOGIN_CREDENTIAL (property_json.access_token, github_project_name) and GITHUB_PROJECT_CONFIG in akaun_master; one bl_module_wf_issue_github_repo_tenant_link row per repository with a webhook_secret and a wf_project_guid; a GitHub webhook pointed at core2/tnt/dm/wf/issues/github-webhook; a bl_sch_crontab_hdr row for GITHUB_TO_ISSUE_HDR_SYNC_CRON_PROCESSOR | SQL for app_cfg_main (no screen; GitHubConfig.java L47–L53), Settings → Tenant Repository Link, GitHub repository settings, the Scheduler | Outbound sync fails with GitHub token is not configured in app_cfg_main; inbound deliveries are answered IGNORED for an unmapped repository and 401 for a missing secret; missed webhooks are never caught up. |
For issue e-mail: a bl_wf_project_notification_subscription_config row per project and event (ISSUE_CREATED, ISSUE_UPDATED, ISSUE_DELETED) pointing at a UCC e-mail endpoint | Projects → edit → Notifications | No e-mail is queued (WFIssueService.java L207–L226). |
Note that the GitHub token is platform-global: one GITHUB_LOGIN_CREDENTIAL row in
akaun_master serves every tenant (GitHubConfig.java L47–L50).
Applet settings
Settings live in three applet-local screens; none uses the shared FieldConfigurationComponent
from blg-shared-utilities (this repository vendors its own copy of shared-utilities under
micro-fe/projects/shared-utilities and has no .gitmodules). Anyone who can open Settings can
change them; there is no per-setting authority.
Settings → Application Settings (application-settings.component.ts, saved with
saveMasterSettingsInit, tenant-wide):
| Setting | What it controls | Default | Effect when changed |
|---|---|---|---|
Issue Category → Category Group 0…10, each with a Mandatory checkbox (ISSUE_CATEGORY_CATEGORY_GROUP_SETTINGS_LIST) | Which category groups appear as pick-lists on an issue and which must be filled | Eleven empty slots (L57–L63) | Read by the issue category tab (issue-edit-category.component.ts L100–L101, required at the template’s L8) and by the Issues Report, which adds one column per selected group (dashboard-issue-report.component.ts L182–L196). The same list drives the UCC applet’s Issue Tracker panel. |
Two more keys sit in the same form and are written on every SAVE but have no control and no
consumer: ISSUE_CODE_FORMAT (initial value <running_no>) and
RUNNING_NUMBER_GENERATION_METHOD (initial RANDOM_NUMBER_GENERATOR) — application-settings.component.ts
L45–L46; the template renders only the category slots, nothing in the applet reads either key, and
the backend numbers issues from a database sequence with no format option (see Lifecycle). Do not
plan an issue-code scheme around them.
Settings → Default Selection (default-settings.component.ts, saved with
saveMasterSettingsInit):
| Setting | What it controls | Default | Effect when changed |
|---|---|---|---|
Default Kanban Board (DEFAULT_KANBAN_BOARD) | Which board (bl_wf_issue_dashboard) the Main Dashboard loads its column order from | -- None -- (null) | The dashboard waits for a non-empty value before loading board links (dashboard-container.component.ts L246–L259); with none set, cards fall back to unsorted columns and same-column drag has no board to record the order against. |
Default Branch and Default Location on the same screen are saved (DEFAULT_BRANCH,
DEFAULT_LOCATION) but read by nothing in this applet — they are the document-applet template.
Settings → Field Settings renders eight mat-slide-toggles (Unit Discount, SST/VAT/GST, WHT,
Blanket Order, Segment, G/L Dimension, Profit Center, Project) with no form binding and a SAVE
button with no handler (field-configuration.component.html). Nothing is persisted.
Personalization → Default Selection is routed directly while written as a child component:
@Input() appletSettings$ is never bound, the subscription that would populate it is commented out
(personal-default-settings.component.ts L31–L39), and the first change to either drop-down throws
on this.appletContainer.bl_applet_exts (L41). SAVE emits to no listener. Nothing is persisted.
Settings in other applets that control this applet
| Setting | Where it is set | Effect here |
|---|---|---|
GITHUB_LOGIN_CREDENTIAL, GITHUB_PROJECT_CONFIG (app_cfg_main, akaun_master) | SQL; POST …/issues/sync-github/sync-config/backoffice-ep refreshes the project schema | Token, target project and the Projects V2 field map for every tenant. |
bl_sch_crontab_hdr.event_properties for the reconciliation job (limit, maxIssues ≤ 1000, defaultLookbackHours 24, overlapMinutes 5, migrationTenants, migrateAllLinkTenants) | Scheduler | How far back the catch-up reads and which repository links it processes (GithubToIssueHdrSyncCronProperties.java L52–L56). |
| Project notification configs | Projects → Notifications | Who receives the issue e-mails. |
Feature visibility / permissions
bl_applet_client_side_perm_dfn holds no rows for IssueTrackerApplet (2026-09-16), so
Applet Access has nothing to grant and no screen can be hidden per role.
Server-side permissions are checked per endpoint in the backend with the pattern OWNER or ADMIN, else the verb. The families the applet’s screens hit:
| Screen | Permission family (verbs OWNER, ADMIN, MEMBER, CREATE, UPDATE, DELETE, READ unless noted) | Where enforced |
|---|---|---|
| Issues, sprints, GitHub sync | TNT_API_DM_WF_ISSUE_* — sprints reuse the issue family; the sync endpoint needs UPDATE, the config refresh ADMIN | WFIssueHdrController.java L56–L184, WFIssueSprintHdrController.java L46–L118, WFIssueSyncGithubController.java L71–L141 |
| Comments, worklogs, attachments, linked issues, issue-user links | TNT_API_DM_WF_ISSUE_COMMENT_*, …_ISSUE_WORKLOG_*, …_ATTACHMENT_*, …_ISSUE_TO_ISSUE_LINK_*, …_ISSUE_USER_LINK_* | the matching controllers under controller/tenant/dm/wf/issue/ |
| Kanban boards and card order | TNT_API_DM_WF_ISSUE_DASHBOARD_*, …_ISSUE_DASHBOARD_LINK_* (no MEMBER) | WFIssueDashboardController.java L44–L60, WFIssueDashboardLinkController.java L45–L115 |
| Dashboard reports | TNT_API_WF_DASHBOARD_ISSUE_PER_{PROJECT,ASSIGNEE,STATUS}_{OWNER,ADMIN,READ} | DashboardController.java L42–L102 |
| Projects, project categories, issue types | TNT_API_DM_WF_PROJECTS_*, …_PROJECT_CATEGORIES_*, …_ISSUE_TYPE_* | ProjectController.java L83–L172 and siblings |
| Categories, category groups | TNT_API_WF_ISSUE_LABEL_*, TNT_API_DM_WF_ISSUE_LABEL_LIST_* | IssueLabelController.java L134–L182, IssueLabelListController.java L119–L223 |
| User Tenant links | BL_MODULE_WF_ISSUE_USER_TENANT_LINK_* (platform endpoint) | WFIssueUserTenantLinkController.java L47–L123 |
| Tenant Repository links | MST_API_DM_APP_GITHUB_ISSUE_REPO_TENANT_LINK_* (akaun_master permission) | WFIssueGithubRepoTenantLinkController.java L68–L69 |
Four naming prefixes coexist (TNT_API_DM_WF_, TNT_API_WF_, BL_MODULE_WF_, MST_API_DM_APP_);
a permission set built from the first prefix alone leaves the reports, categories and both link
screens unauthorised.
Fields
Issue (detail page, create mode)
| Field | Meaning | Required | Notes / validation |
|---|---|---|---|
| Title | title | Yes — toast Title is required to create an issue (issue-detail.component.ts L1432–L1435) | Plain input; no length limit in the UI. |
| Description | description | No | Textarea on create, rich-text editor on edit. |
| Assignee | main_assignee | No | User pick-list (bl_wf_user_hdr). |
| Reporter | main_reporter | — | Read-only; the current login (L1480). |
| GitHub Repository | github_repo_full_name, and rewrites guid_tenant / tenant_code to the repository’s tenant (L1391–L1399) | No | Built from the repository-tenant links of the tenants this login may see; auto-selects the first when the issue has none (L1359–L1385). |
| Project | wf_project_guid | Yes — toast Project is required to create an issue (L1449–L1451) | No Not Selected option. |
| Sprint | sprint_hdr_guid | No | |
| Label 1–3 | label_hdr_0_guid … label_hdr_2_guid | No | The header has eleven label slots; the page exposes three. |
| Custom fields | custom_field_json | Per placement — <field> is required | One control per ACTIVE, visible placement for bl_wf_issue_hdr, in display_order; renderers for text, textarea, dropdown, date and numeric. On Save Changes the JSON is rebuilt from the placements, so keys with no placement are dropped (L1531–L1545). |
| Status, Priority, Issue type | issue_status, priority, issue_type_guid | — | Not editable here. Create sends status: 'ACTIVE' and priority: 'medium' (L1474–L1493) and no issue type. |
Issue (quick-create dialog, dashboards)
| Field | Required | Notes |
|---|---|---|
| Title | Yes | |
| Description | No | |
| Attachments | No | Up to 20 MB each; larger files are skipped with a toast. |
| Issue Type | Yes | |
| Project | Yes | |
| Priority | No | Default MAJOR |
| Status | No | Default TO DO |
| Sprint, Assignee | No | |
| Tenant | — | Separate selector; sets github_repo_full_name from the tenant’s repository link. |
The dialog and the detail page default priority differently (MAJOR vs medium) and neither
value is validated by the backend — priority and issue_status are free text on
bl_wf_issue_hdr (L44, L63).
Project (main-menu Projects)
| Field | Required | Notes |
|---|---|---|
| Project Name | Yes, ≤255 | |
| Project Code | Yes, ≤255 | Read-only after save. |
| Project Key | No | The prefix bucket for the issue sequence; only the main-menu copy saves it. |
| Project Type | No | Public / Private |
| Project Category | Yes (create) | |
| Lead | Yes (create) | |
| Default Assignee | No | |
| Description | No |
Sub-tabs: People (e-mail, verified against existing logins, rank default MEMBER), Issue
Types (multi-select), Notifications (event name, single user, current assignee / reporter / user
/ project lead checkboxes, single e-mail address, team).
Sprint, Issue Type, Project Category, Kanban Board
| Screen | Fields | Required | Immutable after save |
|---|---|---|---|
| Sprint | Name, Code, Period, Start Date, End Date | Name (≤255), Code (≤100 on edit) | — |
| Issue Type | Name, Code, Description | Name (≤255), Code | Code |
| Project Category | Name, Code, Description | Name (≤255), Code | Code |
| Kanban Board | Code, Name, Description | Code, Name (≤255) | Code; Description is collected and never saved (kanban-board-create.component.ts onSubmit) |
Issue Type and Project Category creates check for a duplicate code client-side (Issue type code already exists!).
Custom Fields Placement
| Field | Required | Default | Notes |
|---|---|---|---|
| Custom Field | Yes | — | From bl_tnt_custom_field_definition |
| Target Table | Yes | bl_wf_issue_hdr | The only option |
| Display Order | Yes | 0 | |
| Status | Yes | ACTIVE | |
| Visible / Required / Read Only / Searchable / List Column | No | Visible on; others off | Required is what makes the field mandatory on the issue page. Booleans are stored as the strings true / false. |
User Tenant link, Tenant Repository link
| Screen | Fields | Required | Notes |
|---|---|---|---|
| User Tenant | Email Address (with Verify and Send Invite), Tenant, Tenant Code (derived), Is Default; Status on edit | Email, Tenant | The login subject is resolved from the verified e-mail; SAVE stays disabled until verification succeeds (user-tenant-link-create.component.ts L189–L203). |
| Tenant Repository Link | Tenant, Tenant Code (derived), GitHub Repository (owner/repository), GitHub Project (owner/projectNumber), Webhook Secret (masked; blank on edit keeps the stored value), Sync Bot Login, Create missing issues (on), Import attachments (off), Sync project fields (off), Status | Tenant, GitHub Repository, Status | Two client-side rules re-checked against the server before save: a tenant cannot link the same repository twice, and a repository can belong to only one tenant (github-repo-tenant-link-validation.services.ts L18–L79; case-insensitive). |
Users, Teams, Category Groups
| Screen | Fields | Required | Immutable after save |
|---|---|---|---|
| User | Username, Name, User Type, GitHub Username, Email Address (verify / invite), Description; Status on edit | Username, Name (≤255), Email | Username |
| Team | Detail: Team Name, Team Code, Website, Description; Address: Address 1–2, Postal Code (5 chars), City, State, Country; Users tab on edit (users multi-select, rank default MEMBER) | Name (≤255), Code | Team Code |
| Category Group | Code, Name, Type, Param Code, Param Name, Status | Code, Name, Param Code, Param Name | Code |
| Category | Category Group, Category Code, Category Name, Description, Parent (tree) | Code, Name | — |
bl_wf_user_hdr.github_username is what the inbound sync matches a GitHub assignee against.
Lifecycle and effects
Issue Tracker writes only workflow tables — bl_wf_issue_hdr, bl_wf_issue_comment_hdr,
bl_wf_attachment_hdr, bl_wf_issue_worklog, bl_wf_issue_event, bl_wf_issue_dashboard(_link),
bl_wf_issue_sprint_hdr, bl_wf_project_hdr and their links — plus two akaun_master link tables.
No *DataConsistencyObject signum, no JournalPostingTypeHandler entry, no stock processor; grep of
the wf packages for journal, generic-document and stock services finds only unused imports.
Statuses
bl_wf_issue_hdr carries two independent status columns. status is the platform row status
(ACTIVE / INACTIVE / DELETED); issue_status is the workflow status shown on the board and is
free text with no enum, no default and no backend transition rule — the quick-create dialog
seeds TO DO, the detail page seeds nothing, and a kanban drop writes whatever the target column
is named (dashboard-container.component.ts, onKanbanDrop). The inbound GitHub sync maps GitHub
closed to status = INACTIVE and open to ACTIVE, never DELETED
(WFIssueInboundGithubService.java L486–L490).
Create and update
The detail page posts to core2/tnt/dm/wf/issue-hdrs/backoffice-ep (wf-issue-hdr.service.ts
L12; WFIssueHdrController.java L67–L92). That controller checks TNT_API_DM_WF_ISSUE_CREATE and
calls WFIssueHdrUow.create directly — it does not run WfIssueDataConsistencyObject (L78).
The title, project and issue-type rules in that validator apply only to the older
core2/tnt/dm/wf/issues endpoints used by the quick-create dialog and by UCC
(WFIssueService.java L47, L89). On the detail page the only guards are the client-side toasts.
The issue number comes from AppSequenceCounterUow.incrementAndGet("bl_wf_issue_hdr", "ISSUE_TRACKER", [project key]) and is written to both issue_key and issue_number (WFIssueHdrUow.java L46–L59).
Only the first container of a batch is numbered. There is no configurable prefix or format in the
backend; the PROJ-n style shown in the UI is the project key concatenated client-side.
After a successful create or update the controller writes a bl_wf_issue_event row
(ISSUE_CREATED / ISSUE_UPDATED; L80–L86, L131) and, when the issue has a
github_repo_full_name, enqueues it on bl_wf_issue_sync_to_github_queue (L90, L135;
WFIssueGithubSyncQueueService.java L52–L107 — never throws, so a slow GitHub cannot fail a save).
Delete writes no event row (ISSUE_DELETED exists in WFIssueEventConstants but is never
persisted), and event writes are wrapped in a swallowed try (WFIssueService.java L61–L63), so
History is best-effort.
E-mail: an ISSUE_EMAIL_NOTIFICATION job is queued only when the project has a notification
config row for the event; recipients are the union of assignee, reporter, creator, the configured
single user and the last updater (IssueEmailNotificationProcessor.java L94–L121). The config’s
property_json keys single_email_address, single_user, current_assignee, current_reporter,
current_user are cast directly — a missing key throws.
Tenant scoping — what the Tenants switcher does and does not do
All issues live in the login tenant’s database; the API visa is built from
sessionStorage.tenantCode (shared-utilities/visa.ts L6) and never changes when a tenant is
selected. Selecting a customer tenant only adds tenant_guids = <guid> to the issue query, which
the backend turns into guid_tenant IN (:tenant_guids) (WFIssueHdrUow.java L220). On
GET …/issue-hdrs/backoffice-ep/query the backend fills that filter from the login’s user-tenant
links only when the caller sent none (WFIssueHdrController.java L252–L254); a caller who
supplies tenant_guids explicitly is not intersected with the link table, and the sibling
GET /backoffice-ep, GET /backoffice-ep/{guid} and GET /backoffice-ep/query/count apply no
tenant filter at all (L180–L223, L275–L290). Treat the user-tenant link as a UI convenience — which
tenants appear in the picker — not as a security boundary between the customer tenants tracked in
one database.
GitHub sync
| Direction | Trigger | What it does | Where |
|---|---|---|---|
| Outbound | Every create/update of an issue with a repository, and Sync selected to GitHub on the Issues list and Issues Report (POST …/issues/sync-github/backoffice-ep) | Creates or updates the GitHub issue (title, body, labels by bl_wf_issue_label_hdr.code, assignees by github_username, open/closed from status), uploads attachments, sets Projects V2 fields (priority, dates, sprint by date overlap then by exact iteration title, custom fields from GITHUB_PROJECT_CONFIG). A pending event for the same issue is not queued twice. | IssueHdrToGithubSyncProcesor.java (queue ISSUE_HDR_TO_GITHUB_SYNC, its own table), WFIssueSyncGithubService.java |
| Inbound, real time | GitHub webhook issues and issue_comment events to POST core2/tnt/dm/wf/issues/github-webhook | Verifies X-Hub-Signature-256 with the repository link’s webhook_secret (fails closed on a blank secret), drops events sent by sync_bot_login, answers 202 ACCEPTED and applies the change on a background thread after re-fetching the issue from GitHub so a delayed delivery cannot overwrite newer edits. Rows it creates are attributed to the anonymous login subject. | WFIssueGithubWebhookController.java L124–L225, GitHubWebhookSignature.java L44–L74 |
| Inbound, catch-up | bl_sch_crontab_hdr job GITHUB_TO_ISSUE_HDR_SYNC_CRON_PROCESSOR, or POST …/issues/sync-github/reconcile-github/backoffice-ep | Re-reads everything GitHub updated since the link’s last_sync_time minus overlapMinutes (first run: defaultLookbackHours), applies it idempotently via github_last_inbound_hash, then advances last_sync_time to the run start. A repository whose link row is unusable is skipped and logged, not failed. | GithubToIssueHdrSyncCronProcessor.java L176–L262 |
Loop safety: inbound writes go through WFIssueInboundGithubService, never through the controller,
so they do not enqueue an outbound push (IssueHdrToGithubSyncProcesor.java L46–L50).
The webhook worker is an in-process bounded pool (2–4 threads, queue 500); a restart discards what
is queued and the reconciliation job is the recovery (WFIssueGithubWebhookController.java
L60–L72, L107–L114).
What VOID / delete reverses
There is no VOID. Delete on an issue, sprint, board or link sets the row’s status to DELETED
through the ordinary delete endpoint; nothing downstream is reversed because nothing downstream is
posted. Deleting a GitHub-linked issue locally does not close it in GitHub (delete does not enqueue
an outbound event).
Related applets
- Unified Contact Center — its Issue Tracker
panel writes to the same issue table through the
…/issues/ucc/backoffice-ependpoints and reads the same eleven category-group slots. - Platform SysAdmin and Tenants V2 — the tenant rows the Tenants switcher lists and the platform permission that lets a login read them.
- Scheduler — hosts the GitHub reconciliation job.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| A non-closeable dialog You do not have permission to access any tenants on every open | The login has no ACTIVE bl_module_wf_issue_user_tenant_link row (app.component.ts L80–L83). Measured 2026-09-16, two logins on the platform have one. | An administrator adds the login under Settings → User Tenant (verify the e-mail, pick the tenant, tick Is Default for the usual one). |
| The Tenants drop-down shows entries with no name, or Switched to tenant: undefined | GET core2/platform/dm/tenants/query returns a PERMISSION_DENIED stub for tenants the login cannot read (TenantController.java L85–L93, L402–L424). | Grant MST_API_TNT_MGT_TENANT_READ on those tenant rows in the platform permission tables. |
| The Issues list is empty although issues exist | The login’s user-tenant links point at other tenants; the query is filtered to the linked guid_tenant values (WFIssueHdrController.java L243–L254). Or the issues were created with a different GitHub Repository selection, which rewrites guid_tenant. | Link the login to the right tenant; check the repository selection on the affected issues. |
| Sync with GitHub on the issue detail page always fails | The button posts to …/issues/sync-github/two-way/backoffice-ep (wf-issue-sync-github-backoffice-ep.service.ts L94, L139–L151), and the backend at d332871 maps only /backoffice-ep, /sync-config/backoffice-ep and /reconcile-github/backoffice-ep (WFIssueSyncGithubController.java L82, L135, L195). | Use Sync selected to GitHub on the Issues list or the Issues Report, which post to the existing /backoffice-ep. Recorded as a product defect. |
| Outbound sync rows fail with GitHub token is not configured in app_cfg_main | No GITHUB_LOGIN_CREDENTIAL row, or its property_json.access_token is blank (GitHubConfig.java L64–L84). | Insert the row in akaun_master with a token carrying repo, read:org, read:project; then call the sync-config endpoint. |
| Sync-config returns Could not find GitHub project for ‘ | Token lacks read:org / read:project, or github_project_name is not owner/number (GitHubConfigSyncService.java L44–L49). | Fix the token scopes or the value. |
GitHub shows the webhook delivery as 401 | The repository link’s webhook_secret is blank or differs from the one configured in GitHub; a blank secret rejects everything (GitHubWebhookSignature.java L47–L51). | Set the same secret on both sides; on the edit screen a blank field keeps the stored secret, so re-enter it to change it. |
GitHub shows 200 IGNORED — Repository … is not mapped to a tenant | No ACTIVE link row for that owner/repo (WFIssueGithubWebhookController.java L161–L162). | Create the link under Settings → Tenant Repository Link. |
Inbound issues are skipped, reconciliation reports SKIPPED | The link row has no wf_project_guid — the sequence needs a project — or create_missing_issues is off. | Set the project on the link row. |
| Changes made in GitHub while the service was down never arrive | Webhooks are not retried indefinitely and the in-process queue is lost on restart. | Schedule the reconciliation job every 10–15 minutes with a lookback larger than the interval (ucc#401). |
| A GitHub assignee shows as the anonymous user | No bl_wf_user_hdr row has that github_username (WFIssueInboundGithubService.java L497–L508). | Set GitHub Username on the user under Settings → Users. |
| Issue e-mails never go out | No notification config row for the project and event, or a config whose property_json lacks one of the five keys (IssueEmailNotificationProcessor.java L94–L100). | Create the row under Projects → Notifications with the checkboxes set. |
| Application Settings SAVE appears to save an issue code format | ISSUE_CODE_FORMAT and RUNNING_NUMBER_GENERATION_METHOD are persisted but read by nothing. | Nothing to fix; issue numbers are a per-project sequence. |
| Field Settings toggles or Personalization defaults do not persist | Unbound stub / unbound routed component (see Configuration). | Nothing to fix in the applet; recorded as product findings. |
Related documentation
- Platform applets — the hub this page belongs to.
- Unified Contact Center — the other writer of the same issue table.
- Scheduler — where the reconciliation job is defined.