@opencxh/domain 1.182.0 → 1.183.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ export * from './source';
2
+ export * from './types';
@@ -0,0 +1,147 @@
1
+ import { LocaleBundle } from '../analytics/dashboard';
2
+ /**
3
+ * Role group of an app that declares its own setup steps.
4
+ *
5
+ * A constant and not a literal at both ends: `Bridge.providers.list` answers an unknown group
6
+ * with an empty list, so a typo would read as "no app has setup steps". Same reason
7
+ * `SYNC_SOURCE_PROVIDER_GROUP` is a constant.
8
+ */
9
+ export declare const ONBOARDING_SOURCE_PROVIDER_GROUP = "onboarding-source";
10
+ /**
11
+ * Text the hub renders without knowing what it says: an i18n key from the declaring app's own
12
+ * bundle, plus values for `{name}` placeholders.
13
+ *
14
+ * Not a plain string, because a describe is cached across users and the source cannot know the
15
+ * reader's language. Not a bare key either: half of these lines carry data ("1.284 contacts
16
+ * imported") and a key per count does not exist.
17
+ */
18
+ export interface OnboardingText {
19
+ key: string;
20
+ vars?: Record<string, string | number>;
21
+ }
22
+ /**
23
+ * How urgent this step is. Three values, because the board has three kinds of urgency and two
24
+ * cannot express the middle one.
25
+ *
26
+ * - `live` — the organisation cannot help a customer until this is done. Counts in the live gate,
27
+ * and the only tier that carries "needed to go live".
28
+ * - `soon` — real setup work, but nothing is blocked by it: seed the knowledge base, confirm what
29
+ * the assistant may do. Sits with the rest of your work, outside the gate.
30
+ * - `improve` — polish that may sit for months (per-topic routing rules, SSO, own greetings).
31
+ * Lands under "later, no hurry" on its own, without the admin having to push it there.
32
+ *
33
+ * App-declared, because only the owning app knows that an inbox without an enabled channel is not
34
+ * a working inbox. Nothing caps how many `live` items an app may claim — worth re-reading whenever
35
+ * a new source is added, because the gate stops meaning anything at thirty of them.
36
+ */
37
+ export type OnboardingTier = "live" | "soon" | "improve";
38
+ /**
39
+ * What the declaring app can know by itself. Three values, not five.
40
+ *
41
+ * `waiting` means the app is waiting on a third party (a number port, DNS propagation, a vendor
42
+ * approval) and the admin must do nothing. The two hub-owned states — delegated and pushed to
43
+ * later — are absent on purpose: an app cannot know you handed its step to a colleague, and the
44
+ * hub cannot know a port request is pending.
45
+ */
46
+ export type OnboardingItemState = "done" | "todo" | "waiting";
47
+ /** Where an action takes you. Two shapes, because the shell has exactly two surfaces. */
48
+ export type OnboardingLink =
49
+ /**
50
+ * An app route, app-relative (`/callflows/abc`). Followed with `sdk.router.navigate`.
51
+ *
52
+ * `app` only when the target is *another* app — the declaring app is the default, so an item
53
+ * pointing into its own screens cannot name the wrong one.
54
+ */
55
+ {
56
+ kind: "route";
57
+ path: string;
58
+ app?: string;
59
+ }
60
+ /**
61
+ * A settings page. Panels have no URL, so this is the registry key rather than a path.
62
+ *
63
+ * `<app>:<page>` (`communication:channels`); a bare `channels` is read as this app's own page.
64
+ */
65
+ | {
66
+ kind: "settings";
67
+ pageId: string;
68
+ };
69
+ /**
70
+ * - `apply` — "set it up this way": the hub posts to the owner's `/provider/onboarding/apply`
71
+ * - `open` — follow `link` into the app that owns the step
72
+ * - `review` — same mechanics as `open`, different copy and weight ("check the drafts")
73
+ * - `delegate` — the hub's own panel; the declaring app knows nothing about it
74
+ * - `status` — read-only, for `waiting`: a line, not a button
75
+ */
76
+ export interface OnboardingAction {
77
+ kind: "apply" | "open" | "review" | "delegate" | "status";
78
+ /** Required for `open` and `review`. */
79
+ link?: OnboardingLink;
80
+ /** Overrides the hub's house copy for this verb. Usually absent. */
81
+ label?: OnboardingText;
82
+ }
83
+ export interface OnboardingItem {
84
+ /**
85
+ * App-namespaced and stable: `communication.servicedesk-inbox`, `eylo-voip.dialplan`.
86
+ *
87
+ * A stored reference — hub state and delegated tasks key on it — so renaming an id orphans a
88
+ * delegation. The prefix is convention for readability, never routing: `apply` is dispatched to
89
+ * the provider whose describe declared the id.
90
+ */
91
+ id: string;
92
+ tier: OnboardingTier;
93
+ state: OnboardingItemState;
94
+ title: OnboardingText;
95
+ /**
96
+ * The card's body, and therefore the proposal itself. There is no preview endpoint: the describe
97
+ * already computed what would happen, which is what makes the card readable.
98
+ */
99
+ description?: OnboardingText;
100
+ /** The line under the app label: "needed to go live". */
101
+ reason?: OnboardingText;
102
+ /** Minutes, not a rendered string — a later guided flow sums them into "about 20 min to go". */
103
+ estimateMinutes?: number;
104
+ actions: OnboardingAction[];
105
+ /** The small-caps chip (TELEPHONY, KNOWLEDGE BASE). Absent = the app's display name. */
106
+ group?: OnboardingText;
107
+ /** Absent = true. `false` for a step nobody else could take over. */
108
+ delegatable?: boolean;
109
+ /**
110
+ * Can this app observe completion by itself?
111
+ *
112
+ * `true` — "a team exists", "three colleagues can reply": the next describe returns `done` on
113
+ * its own, and a finished task proves nothing extra.
114
+ * `false` — no server state to read (DNS records at a registrar we have no credentials for, a
115
+ * vendor authorisation without an API). Only then does a completed delegation count as done.
116
+ *
117
+ * This boolean is the seam between "the app knows" and "someone said so". Declaring it per item
118
+ * keeps the trust window per step instead of making it global policy.
119
+ */
120
+ verifiable: boolean;
121
+ /** Sort hint within a tier. Ties break on app name, then id, so the order stays stable. */
122
+ order?: number;
123
+ }
124
+ /**
125
+ * Payload of `GET /provider/onboarding/describe`.
126
+ *
127
+ * Bare, not wrapped in `ResponseFactory` — that is how the fan-out reads it, same as
128
+ * `analytics-source` and `memory-source`.
129
+ */
130
+ export interface OnboardingSourceDescribe {
131
+ /** The declaring app (== manifest name == `req.source.app`). */
132
+ source: string;
133
+ items: OnboardingItem[];
134
+ /** Texts for every key above, in every language this app ships. `flattenLocales()` helps. */
135
+ locales?: LocaleBundle;
136
+ }
137
+ /** Body of `POST /provider/onboarding/apply`. The only thing that crosses the app boundary. */
138
+ export interface OnboardingApplyRequest {
139
+ itemId: string;
140
+ }
141
+ /** Result of an apply, wrapped in `ResponseFactory` by the provider. */
142
+ export interface OnboardingApplyResult {
143
+ /** What was created, in the app's own words. Shown as a toast. */
144
+ message?: OnboardingText;
145
+ /** Where to look at the result, when there is something to look at. */
146
+ link?: OnboardingLink;
147
+ }
@@ -0,0 +1,82 @@
1
+ import { LocaleBundle } from '../analytics/dashboard';
2
+ import { OrganizationProfile } from '../organization/profile';
3
+ import { OnboardingApplyResult, OnboardingItem } from './source';
4
+ /**
5
+ * The five groups from the design, grouped by who has to act. Composed by the hub; no app and no
6
+ * table stores it.
7
+ *
8
+ * | value | owner | source |
9
+ * |----------------|-------|--------------------------------------------------------------|
10
+ * | done | app | state `done`, or a finished task on a `verifiable: false` item |
11
+ * | with-you | app | state `todo` with no hub overlay |
12
+ * | with-colleague | hub | an open delegation row |
13
+ * | waiting-on-us | app | state `waiting` |
14
+ * | later | hub | the admin pushed it down |
15
+ */
16
+ export type OnboardingStatus = "done" | "with-you" | "with-colleague" | "waiting-on-us" | "later";
17
+ export interface OnboardingDelegation {
18
+ taskId: string;
19
+ assigneeId: string;
20
+ /** Resolved by the hub. Absent means draw no name and no avatar rather than an id. */
21
+ assigneeName?: string;
22
+ delegatedAt: number;
23
+ }
24
+ /** An item as the page receives it: the app's declaration plus the hub's overlay. */
25
+ export interface OnboardingViewItem extends OnboardingItem {
26
+ /** Stamped from `OnboardingSourceDescribe.source`, never read off the item itself. */
27
+ app: string;
28
+ status: OnboardingStatus;
29
+ delegation?: OnboardingDelegation;
30
+ }
31
+ /** The live gate ("3 of 4"). Derived from the composed items, never stored. */
32
+ export interface OnboardingLiveGate {
33
+ /** Every `tier: "live"` item, in order — these are the checklist lines. */
34
+ itemIds: string[];
35
+ total: number;
36
+ done: number;
37
+ /** Set only when exactly one live item is left, so the band can name it. */
38
+ nextItemId?: string;
39
+ }
40
+ export interface OnboardingCounts {
41
+ all: number;
42
+ withYou: number;
43
+ withColleagues: number;
44
+ waitingOnUs: number;
45
+ later: number;
46
+ done: number;
47
+ }
48
+ /** An installable app this organisation does not use yet. */
49
+ export interface OnboardingSuggestedApp {
50
+ name: string;
51
+ displayName: string;
52
+ shortDescription?: string;
53
+ icon?: string;
54
+ }
55
+ /**
56
+ * Payload of `POST organization/onboarding/apply`.
57
+ *
58
+ * The recomputed board travels with the result, and that is a contract rather than a convenience:
59
+ * applying one step can flip the live gate, move an item between groups and change every count, so
60
+ * a response carrying only the changed step would leave the page showing numbers that no longer
61
+ * hold — and a follow-up GET would show them for the length of a round trip.
62
+ */
63
+ export interface OnboardingApplyResponse {
64
+ result: OnboardingApplyResult;
65
+ view: OnboardingView;
66
+ }
67
+ /** Payload of `GET organization/onboarding/`. */
68
+ export interface OnboardingView {
69
+ items: OnboardingViewItem[];
70
+ gate: OnboardingLiveGate;
71
+ counts: OnboardingCounts;
72
+ /** Merged from every source's describe; handed straight to `registerBundle`. */
73
+ locales: LocaleBundle;
74
+ suggestedApps: OnboardingSuggestedApp[];
75
+ /**
76
+ * Apps whose describe did not answer, so the page can say what is missing instead of lying by
77
+ * omission. Always present — `[]` when every source answered — so the client never has to tell
78
+ * "all fine" apart from "this field is old".
79
+ */
80
+ degradedApps: string[];
81
+ profile?: OrganizationProfile;
82
+ }
@@ -1,2 +1,3 @@
1
1
  export * from './billing';
2
+ export * from './profile';
2
3
  export * from './types';
@@ -0,0 +1,57 @@
1
+ import { ChannelKind } from '../../platform/communication';
2
+ /** Keys and not free text: an app has to be able to branch on this. */
3
+ export type WorkArea = "support" | "billing" | "availability" | "sales" | "onboarding";
4
+ /** A tool the organisation runs today, and whether it stays or gets replaced. */
5
+ export interface ProfileTool {
6
+ /** Lowercased vendor name: "outlook", "zendesk", "hubspot". */
7
+ name: string;
8
+ disposition: "keep" | "replace";
9
+ }
10
+ /**
11
+ * One window, because that is the intake answer ("Mon-Fri 08:30-17:30"). Per-day windows and
12
+ * holidays belong to the dialplan that enforces them, not here.
13
+ */
14
+ export interface ProfileOpeningHours {
15
+ /** ISO weekdays, 1 = Monday. */
16
+ days: number[];
17
+ /** "08:30", local to the organisation. */
18
+ from: string;
19
+ to: string;
20
+ }
21
+ /**
22
+ * What the company said about itself. Input to every app's setup proposal, and the reason the
23
+ * setup centre can promise that changing this changes the proposals.
24
+ *
25
+ * Flat and small on purpose: a form has to fill it in one sitting and an app has to branch on it
26
+ * with an `includes`. Anything richer (which team, which number, which mailbox) is real
27
+ * configuration and belongs to the app that owns it.
28
+ */
29
+ export interface OrganizationProfile {
30
+ workAreas?: WorkArea[];
31
+ channels?: ChannelKind[];
32
+ /** Intended headcount. A proposal needs the target, not today's count. */
33
+ teamSize?: number;
34
+ toolsInUse?: ProfileTool[];
35
+ /** "Within 4 hours on business days". */
36
+ responseTime?: {
37
+ hours: number;
38
+ businessHoursOnly: boolean;
39
+ };
40
+ openingHours?: ProfileOpeningHours;
41
+ tone?: {
42
+ formality: "informal" | "formal";
43
+ length: "short" | "normal";
44
+ /** ISO codes, primary first. */
45
+ languages: string[];
46
+ };
47
+ /** `posture` shares its vocabulary with playbook autonomy deliberately. */
48
+ ai?: {
49
+ posture: "off" | "suggest" | "auto";
50
+ region?: "eu" | "us";
51
+ ownKey?: boolean;
52
+ };
53
+ /** Epoch ms of the last intake edit. */
54
+ updatedAt?: number;
55
+ }
56
+ export declare const WORK_AREAS: WorkArea[];
57
+ export declare const PROFILE_TOOL_DISPOSITIONS: ProfileTool["disposition"][];
@@ -1,3 +1,4 @@
1
+ import { OrganizationProfile } from './profile';
1
2
  export interface OrganizationAddress {
2
3
  street?: string;
3
4
  houseNumber?: string;
@@ -34,6 +35,11 @@ export interface Organization {
34
35
  description?: string;
35
36
  address?: OrganizationAddress;
36
37
  billing?: OrganizationBilling;
38
+ /**
39
+ * What this organisation does, from the setup intake. Read by every onboarding source to decide
40
+ * which steps apply and what to propose. See `profile.ts`.
41
+ */
42
+ profile?: OrganizationProfile;
37
43
  /** Small company logo stored inline as a base64 data-URI. */
38
44
  logo?: string;
39
45
  /**