@tolinax/ayoune-interfaces 2026.64.0 → 2026.66.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.
package/data/index.d.ts CHANGED
@@ -3,3 +3,4 @@ export * from "./modelsAndRights";
3
3
  export * from "./modules";
4
4
  export * from "./services";
5
5
  export * from "./pageConfig";
6
+ export * from "./iotCapabilities";
package/data/index.js CHANGED
@@ -19,3 +19,4 @@ __exportStar(require("./modelsAndRights"), exports);
19
19
  __exportStar(require("./modules"), exports);
20
20
  __exportStar(require("./services"), exports);
21
21
  __exportStar(require("./pageConfig"), exports);
22
+ __exportStar(require("./iotCapabilities"), exports);
@@ -0,0 +1,27 @@
1
+ /**
2
+ * IoT device taxonomy — single source of truth for `IIoTDevice.deviceType` and
3
+ * `IIoTDevice.capabilities[]`.
4
+ *
5
+ * Why string-literal sets instead of TS enums:
6
+ * - they survive npm publish without runtime overhead
7
+ * - new values can be added in a feature-branch without breaking older consumers
8
+ * - easier to hand to non-TS clients (ESP32 firmware, shell scripts, admin UI lookups)
9
+ *
10
+ * Discriminator: `deviceType` (mostly fixed shape per class).
11
+ * Behaviour switch: `capabilities[]` (multi-value, drives action endpoints + UI tabs).
12
+ */
13
+ export declare const IOT_DEVICE_TYPES: readonly ["wallboard", "control-panel", "production-terminal", "display", "ad-display", "status-light", "access-terminal", "sensor-node", "custom"];
14
+ export type IoTDeviceType = (typeof IOT_DEVICE_TYPES)[number];
15
+ /**
16
+ * Capabilities a device can advertise. Action endpoints in `api-iot` are
17
+ * gated on these, the admin-v2 detail view derives its tabs from them, and
18
+ * the notifier only routes events to subscribers whose capability set
19
+ * includes the matching channel.
20
+ */
21
+ export declare const IOT_CAPABILITIES: readonly ["kiosk", "monitoring", "cast-receiver", "welcome-screen", "dashboard", "sensor-temp", "sensor-humidity", "sensor-power", "sensor-presence", "badge-reader", "nfc", "gpio-relay", "gpio-led", "screen-share", "remote-control", "remote-commands", "process-mgmt", "log-collection", "reload", "telemetry", "cli-runner"];
22
+ export type IoTCapability = (typeof IOT_CAPABILITIES)[number];
23
+ /**
24
+ * Convenience map: which action endpoints in `api-iot` does each capability
25
+ * unlock. Read by the action-router to 412 unsupported actions early.
26
+ */
27
+ export declare const IOT_CAPABILITY_ACTIONS: Record<string, string[]>;
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ /**
3
+ * IoT device taxonomy — single source of truth for `IIoTDevice.deviceType` and
4
+ * `IIoTDevice.capabilities[]`.
5
+ *
6
+ * Why string-literal sets instead of TS enums:
7
+ * - they survive npm publish without runtime overhead
8
+ * - new values can be added in a feature-branch without breaking older consumers
9
+ * - easier to hand to non-TS clients (ESP32 firmware, shell scripts, admin UI lookups)
10
+ *
11
+ * Discriminator: `deviceType` (mostly fixed shape per class).
12
+ * Behaviour switch: `capabilities[]` (multi-value, drives action endpoints + UI tabs).
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.IOT_CAPABILITY_ACTIONS = exports.IOT_CAPABILITIES = exports.IOT_DEVICE_TYPES = void 0;
16
+ exports.IOT_DEVICE_TYPES = [
17
+ /** Pi-/PC-Kiosk großes Display (e.g. company-wallboard kiosks). */
18
+ 'wallboard',
19
+ /** Pi/PC-Touchpanel an einem Standort (door, lobby, conference room). */
20
+ 'control-panel',
21
+ /** Pi/PC am WorkCenter/Machine in der Produktion. */
22
+ 'production-terminal',
23
+ /** Einfaches Anzeige-Gerät — Info-Screen, Warteschlange, Speisekarte. */
24
+ 'display',
25
+ /** Werbedisplay — eigenes Inventory-/Schedule-Modell, kein Dashboard-Inhalt. */
26
+ 'ad-display',
27
+ /** Status-Leuchte / Ampel — heute typischerweise ESP32 mit GPIO-LEDs. */
28
+ 'status-light',
29
+ /** Badge-Reader / NFC-Terminal an einer Tür oder Zeiterfassung. */
30
+ 'access-terminal',
31
+ /** Headless Sensor-Knoten (Temp/Humidity/Power/Presence). */
32
+ 'sensor-node',
33
+ /** Escape-Hatch für noch-nicht-modellierte Custom-Devices. */
34
+ 'custom',
35
+ ];
36
+ /**
37
+ * Capabilities a device can advertise. Action endpoints in `api-iot` are
38
+ * gated on these, the admin-v2 detail view derives its tabs from them, and
39
+ * the notifier only routes events to subscribers whose capability set
40
+ * includes the matching channel.
41
+ */
42
+ exports.IOT_CAPABILITIES = [
43
+ // Display / kiosk content
44
+ 'kiosk',
45
+ 'monitoring',
46
+ 'cast-receiver',
47
+ 'welcome-screen',
48
+ 'dashboard',
49
+ // Sensors
50
+ 'sensor-temp',
51
+ 'sensor-humidity',
52
+ 'sensor-power',
53
+ 'sensor-presence',
54
+ // Identity / credential I/O
55
+ 'badge-reader',
56
+ 'nfc',
57
+ // GPIO actuators
58
+ 'gpio-relay',
59
+ 'gpio-led',
60
+ // Remote-control surfaces (used today by desktop-client)
61
+ 'screen-share',
62
+ 'remote-control',
63
+ 'remote-commands',
64
+ 'process-mgmt',
65
+ 'log-collection',
66
+ // Generic agent capabilities
67
+ 'reload',
68
+ 'telemetry',
69
+ 'cli-runner',
70
+ ];
71
+ /**
72
+ * Convenience map: which action endpoints in `api-iot` does each capability
73
+ * unlock. Read by the action-router to 412 unsupported actions early.
74
+ */
75
+ exports.IOT_CAPABILITY_ACTIONS = {
76
+ reload: ['reload'],
77
+ 'cast-receiver': ['cast-start', 'cast-stop'],
78
+ 'welcome-screen': ['welcome-on', 'welcome-off'],
79
+ 'gpio-relay': ['relay-toggle', 'relay-on', 'relay-off'],
80
+ 'gpio-led': ['led-set'],
81
+ 'cli-runner': ['cli-exec'],
82
+ 'remote-commands': ['remote-exec'],
83
+ };
@@ -384,6 +384,7 @@ export declare enum aMN {
384
384
  KPITemplates = "KPITemplates",
385
385
  Leads = "Leads",
386
386
  LinkPortalClicks = "LinkPortalClicks",
387
+ LinkPortals = "LinkPortals",
387
388
  LinkPortalViews = "LinkPortalViews",
388
389
  LoadingLists = "LoadingLists",
389
390
  Localizations = "Localizations",
@@ -388,6 +388,7 @@ var aMN;
388
388
  aMN["KPITemplates"] = "KPITemplates";
389
389
  aMN["Leads"] = "Leads";
390
390
  aMN["LinkPortalClicks"] = "LinkPortalClicks";
391
+ aMN["LinkPortals"] = "LinkPortals";
391
392
  aMN["LinkPortalViews"] = "LinkPortalViews";
392
393
  aMN["LoadingLists"] = "LoadingLists";
393
394
  aMN["Localizations"] = "Localizations";
@@ -4699,6 +4699,30 @@ const modelsAndRights = [
4699
4699
  updateBy: "_id",
4700
4700
  availableInSDK: false,
4701
4701
  },
4702
+ {
4703
+ plural: "LinkPortals",
4704
+ singular: "LinkPortal",
4705
+ module: "marketing",
4706
+ right: "marketing.linkportals",
4707
+ readOnly: false,
4708
+ importable: false,
4709
+ allowDuplicate: true,
4710
+ updateBy: "_id",
4711
+ availableInSDK: true,
4712
+ sdkOperations: ["find", "findOne", "insert", "update"],
4713
+ searchable: true,
4714
+ searchableFields: ["slug", "title", "customDomain"],
4715
+ labelKey: "marketing.linkportal.label",
4716
+ labelPluralKey: "marketing.linkportals.label",
4717
+ descriptionKey: "marketing.linkportals.description",
4718
+ piiLevel: "none",
4719
+ events: ["created", "updated", "deleted"],
4720
+ entityActions: [
4721
+ { name: "publish", verb: "POST", emits: "published", icon: "publish", labelKey: "marketing.linkportals.actions.publish" },
4722
+ { name: "unpublish", verb: "POST", emits: "unpublished", icon: "unpublished", labelKey: "marketing.linkportals.actions.unpublish" },
4723
+ { name: "duplicate", verb: "POST", emits: "duplicated", icon: "content_copy", labelKey: "marketing.linkportals.actions.duplicate" },
4724
+ ],
4725
+ },
4702
4726
  {
4703
4727
  plural: "LinkPortalViews",
4704
4728
  singular: "LinkPortalView",
@@ -58,12 +58,18 @@ export interface IIoTDevice extends IDefaultFields {
58
58
  department?: ObjectId;
59
59
  workCenter?: ObjectId;
60
60
  machine?: ObjectId;
61
+ /** FK to the WallBoard this device renders, only set when `deviceType === 'wallboard'`. */
62
+ _wallboardID?: ObjectId;
61
63
  active?: boolean;
62
64
  hostName?: string;
63
65
  deviceID?: string;
64
66
  deviceName?: string;
67
+ /** One of `IOT_DEVICE_TYPES` — kept as plain string for migration tolerance. */
65
68
  deviceType?: string;
69
+ /** Legacy comma-separated list. Superseded by `capabilities[]` — both fields stay populated for one release. */
66
70
  deviceFunctions?: string;
71
+ /** New form (subset of `IOT_CAPABILITIES`). Drives action gating in `api-iot` and tab rendering in admin-v2. */
72
+ capabilities?: string[];
67
73
  topic?: string;
68
74
  ip?: string;
69
75
  hostname?: string;
@@ -0,0 +1,197 @@
1
+ import { IDefaultFields } from "./IDefaultFields";
2
+ /**
3
+ * Discriminator for polymorphic ILinkPortalBlock.data shape.
4
+ *
5
+ * Phase 1 (Migration-Compat) — Pflicht-Set, deckt das gesamte Legacy
6
+ * `Settings.linkPortal`-Universum (groups/links/persons/customArea/headers/social) ab.
7
+ * Phase 2 — Schema-Slots, Renderer kommt on-demand. Der link-portal-Service
8
+ * rendert Phase-2-Blöcke heute mit `mixin-unsupported` (silent-skip + Logger-Warn),
9
+ * damit ein eingestellter Block keinen Render-Crash auslöst.
10
+ */
11
+ export type LinkPortalBlockType = "header" | "link" | "group" | "person" | "customHtml" | "vcard" | "qr" | "social" | "text" | "image" | "gallery" | "video" | "audio" | "pdf" | "map" | "faq" | "embed" | "newsletter" | "contactForm" | "booking" | "tipJar" | "product" | "countdown" | "divider" | "spacer";
12
+ export interface ILinkPortalVisibility {
13
+ devices?: ("mobile" | "tablet" | "desktop")[];
14
+ geo?: {
15
+ include?: string[];
16
+ exclude?: string[];
17
+ };
18
+ schedule?: {
19
+ from?: Date;
20
+ to?: Date;
21
+ };
22
+ abTest?: {
23
+ variant: string;
24
+ weight: number;
25
+ };
26
+ }
27
+ export interface ILinkPortalGating {
28
+ type: "password" | "email" | "age" | "login" | "paywall";
29
+ config: Record<string, any>;
30
+ }
31
+ /**
32
+ * Polymorpher Page-Block. `type` ist der Discriminator, `data` die
33
+ * type-spezifische Payload (siehe LinkPortalBlockData* unten).
34
+ *
35
+ * `translations[lang]` shadowed Felder aus `data` für die jeweilige Sprache.
36
+ * Nicht übersetzte Felder fallen auf `data` zurück (Default-Locale-Pfad in
37
+ * `clients/link-portal/src/lib/i18nBlock.ts` → `pickLocalized`).
38
+ */
39
+ export interface ILinkPortalBlock {
40
+ _id: ObjectId;
41
+ type: LinkPortalBlockType;
42
+ position: number;
43
+ visibility?: ILinkPortalVisibility;
44
+ gating?: ILinkPortalGating;
45
+ data: Record<string, any>;
46
+ translations?: {
47
+ [lang: string]: {
48
+ [field: string]: any;
49
+ };
50
+ };
51
+ metadata?: {
52
+ og?: {
53
+ title?: string;
54
+ description?: string;
55
+ image?: string;
56
+ };
57
+ };
58
+ isDraft?: boolean;
59
+ }
60
+ export interface LinkPortalBlockDataHeader {
61
+ title: string;
62
+ description?: string;
63
+ }
64
+ export interface LinkPortalBlockDataLink {
65
+ title: string;
66
+ tagLine?: string;
67
+ icon?: string;
68
+ link: string;
69
+ adult?: boolean;
70
+ }
71
+ export interface LinkPortalBlockDataGroup {
72
+ headerText?: string;
73
+ description?: string;
74
+ /** Children werden im selben Block-Array über `parentId` referenziert
75
+ * (flach für DB-Indizierbarkeit). Falls echtes Nesting gewünscht wird,
76
+ * kann der Adapter es in `children: ILinkPortalBlock[]` materialisieren. */
77
+ childIds?: ObjectId[];
78
+ }
79
+ export interface LinkPortalBlockDataPerson {
80
+ personRef: ObjectId;
81
+ description?: string;
82
+ tagLine?: string;
83
+ role?: string;
84
+ }
85
+ export interface LinkPortalBlockDataCustomHtml {
86
+ title?: string;
87
+ content: string;
88
+ }
89
+ export interface LinkPortalBlockDataVcard {
90
+ headerText?: string;
91
+ }
92
+ export interface LinkPortalBlockDataQr {
93
+ headerText?: string;
94
+ target?: string;
95
+ }
96
+ export interface LinkPortalBlockDataSocial {
97
+ headerText?: string;
98
+ links: {
99
+ provider: string;
100
+ url: string;
101
+ }[];
102
+ }
103
+ export interface ILinkPortalTheme {
104
+ backgroundMode: "gradient" | "image" | "video" | "solid";
105
+ color1: string;
106
+ color2: string;
107
+ fontColor: string;
108
+ backgroundImage?: string;
109
+ backgroundVideo?: string;
110
+ buttonColor1: string;
111
+ buttonColor2: string;
112
+ buttonFontColor: string;
113
+ buttonStyle?: "fill" | "outline" | "soft" | "gradient" | "glass";
114
+ buttonRadius?: number;
115
+ avatarShape?: "circle" | "square" | "rounded";
116
+ fontFamily?: string;
117
+ /** Premium-Slot. Wird nur bei publizierten Portals mit erlaubtem Right gerendert. */
118
+ customCss?: string;
119
+ }
120
+ export interface ILinkPortalBranding {
121
+ logo?: string;
122
+ logoLight?: string;
123
+ favicon?: string;
124
+ showLogo?: boolean;
125
+ showClaim?: boolean;
126
+ /** Sprach-Map: { de: '…', en: '…' } */
127
+ claimText?: {
128
+ [lang: string]: string;
129
+ };
130
+ }
131
+ export interface ILinkPortalMetadata {
132
+ /** Pro-Sprache OG-Tags. Fallback: `defaultLanguage`. */
133
+ og?: {
134
+ [lang: string]: {
135
+ title?: string;
136
+ description?: string;
137
+ image?: string;
138
+ };
139
+ };
140
+ schemaOrg?: Record<string, any>;
141
+ sitemap?: {
142
+ include: boolean;
143
+ priority?: number;
144
+ };
145
+ }
146
+ export interface ILinkPortalAnalyticsPixel {
147
+ provider: "meta" | "tiktok" | "ga4" | "google-ads" | "pinterest" | "snap";
148
+ id: string;
149
+ }
150
+ export interface ILinkPortalAnalyticsWebhook {
151
+ event: "view" | "click" | "gate-pass";
152
+ url: string;
153
+ }
154
+ export interface ILinkPortalAnalytics {
155
+ pixels?: ILinkPortalAnalyticsPixel[];
156
+ utmInherit?: boolean;
157
+ webhooks?: ILinkPortalAnalyticsWebhook[];
158
+ }
159
+ /**
160
+ * Optionale Migrations-Audit-Spur. Wird vom Renderer ignoriert, dient
161
+ * Stichproben + Hard-Remove-Phase G als verifizierbare Quelle.
162
+ */
163
+ export interface ILinkPortalLegacyTrace {
164
+ sourceSettingsId?: ObjectId;
165
+ migratedAt?: Date;
166
+ /** Verbatim Backup des originalen Settings.linkPortal-Sub-Docs. NIE löschen vor Phase G. */
167
+ raw?: Record<string, any>;
168
+ }
169
+ export interface ILinkPortal extends IDefaultFields {
170
+ _customerID: ObjectId;
171
+ _clientID?: ObjectId[];
172
+ _subID?: ObjectId[];
173
+ /** Globally unique Identifier (URL-Segment unter link.sb/<slug>/...). */
174
+ slug: string;
175
+ /** Optionaler Custom-Domain (FQDN). Unique sparse. */
176
+ customDomain?: string;
177
+ /** Interner Anzeigename in der Admin-Liste (nicht öffentlich gerendert). */
178
+ title: string;
179
+ /** Beschreibung (intern). */
180
+ description?: string;
181
+ status: "draft" | "published" | "scheduled";
182
+ publishAt?: Date;
183
+ unpublishAt?: Date;
184
+ /** ISO 639-1 (z.B. "de"). Fallback für Block-Translations. */
185
+ defaultLanguage: string;
186
+ /** Liste aller in diesem Portal aktivierten Sprachen. */
187
+ supportedLanguages: string[];
188
+ theme: ILinkPortalTheme;
189
+ branding: ILinkPortalBranding;
190
+ metadata: ILinkPortalMetadata;
191
+ analytics: ILinkPortalAnalytics;
192
+ /** Optionales Page-Level-Gate (vor jedem Block). */
193
+ pageGating?: ILinkPortalGating;
194
+ /** Polymorpher Block-Stream. Reihenfolge ergibt sich aus block.position. */
195
+ blocks: ILinkPortalBlock[];
196
+ legacy?: ILinkPortalLegacyTrace;
197
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -8,4 +8,10 @@ export interface ILinkPortalClick extends IaYOUneTrackingParams, IGeoIPLocationT
8
8
  _subID?: ObjectId[];
9
9
  _linkID?: ObjectId;
10
10
  channel?: string;
11
+ /** Reference to the LinkPortal entity (chapter 1.72). Sparse — pre-migration clicks lack this. */
12
+ _linkPortalID?: ObjectId;
13
+ /** Reference to the specific block clicked (chapter 1.72). Replaces legacy `_linkID`. */
14
+ _blockID?: ObjectId;
15
+ /** Resolved render-language at click time (ISO 639-1). Sparse — pre-i18n clicks lack this. */
16
+ lang?: string;
11
17
  }
@@ -7,4 +7,8 @@ export interface ILinkPortalView extends IaYOUneTrackingParams, IGeoIPLocationTr
7
7
  _clientID: ObjectId[];
8
8
  _subID: ObjectId[];
9
9
  channel: string;
10
+ /** Reference to the LinkPortal entity (chapter 1.72). Sparse — pre-migration views lack this. */
11
+ _linkPortalID?: ObjectId;
12
+ /** Resolved render-language for the visit (ISO 639-1). Sparse — pre-i18n views lack this. */
13
+ lang?: string;
10
14
  }
@@ -1005,7 +1005,18 @@ interface ISupportPortal {
1005
1005
  roadMapProjects: ObjectId[];
1006
1006
  seo: SEOAttributes;
1007
1007
  }
1008
- interface ILinkPortal {
1008
+ /**
1009
+ * @deprecated Use the standalone `LinkPortals` collection (see `ILinkPortal`).
1010
+ *
1011
+ * Lives only as `ISetting.linkPortal` for the dual-read window described in
1012
+ * `docs/migration/concept/migration-concept.md` chapter 1.72. The link-portal
1013
+ * service auto-migrates customers reading this sub-doc into a fresh
1014
+ * `LinkPortals` document on first request, then continues to serve from the
1015
+ * new collection. Hard-removal happens in Phase G after a 30+ day cool-down.
1016
+ *
1017
+ * Renamed from `ILinkPortal` to free that name for the new entity interface.
1018
+ */
1019
+ interface ILinkPortalLegacy {
1009
1020
  title: string;
1010
1021
  description: string;
1011
1022
  style: LinkPortalStyle;
@@ -1065,7 +1076,8 @@ export interface ISetting extends IDefaultFields {
1065
1076
  products: ProductsSettings;
1066
1077
  slides: SlidesSettings;
1067
1078
  customerportal: ISettingCustomerPortal;
1068
- linkPortal: ILinkPortal;
1079
+ /** @deprecated Migrated to standalone `LinkPortals` collection in chapter 1.72. */
1080
+ linkPortal: ILinkPortalLegacy;
1069
1081
  supportPortal: ISupportPortal;
1070
1082
  warehouse?: IWarehouseSettings;
1071
1083
  [x: string]: any;
@@ -404,6 +404,7 @@ export * from "./IKPINewsletterType";
404
404
  export * from "./IKPITemplate";
405
405
  export * from "./ILabel";
406
406
  export * from "./ILead";
407
+ export * from "./ILinkPortal";
407
408
  export * from "./ILinkPortalClick";
408
409
  export * from "./ILinkPortalView";
409
410
  export * from "./ILoadingList";
@@ -420,6 +420,7 @@ __exportStar(require("./IKPINewsletterType"), exports);
420
420
  __exportStar(require("./IKPITemplate"), exports);
421
421
  __exportStar(require("./ILabel"), exports);
422
422
  __exportStar(require("./ILead"), exports);
423
+ __exportStar(require("./ILinkPortal"), exports);
423
424
  __exportStar(require("./ILinkPortalClick"), exports);
424
425
  __exportStar(require("./ILinkPortalView"), exports);
425
426
  __exportStar(require("./ILoadingList"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tolinax/ayoune-interfaces",
3
- "version": "2026.64.0",
3
+ "version": "2026.66.0",
4
4
  "description": "Houses TypeScript interfaces for aYOUne",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",