@7365admin1/core 3.64.5-staging.308 → 3.64.5-staging.310

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/CHANGELOG.md CHANGED
@@ -1,5 +1,220 @@
1
1
  # @iservice365/core
2
2
 
3
+ ## 3.68.3
4
+
5
+ ### Patch Changes
6
+
7
+ - 1d5050b: Re-inviting the same person to the same app, organisation and site now re-sends the pending invitation instead of adding a duplicate; invite request logs no longer record the invitee's e-mail address.
8
+
9
+ ## 3.68.2
10
+
11
+ ### Patch Changes
12
+
13
+ - d9e0ded: A duplicate membership insert now returns 400 "The user is already a member of this organization." instead of a 500.
14
+
15
+ ## 3.68.1
16
+
17
+ ### Patch Changes
18
+
19
+ - 689b152: POST /api/people: count cross-client person creation (gate ships switched off)
20
+
21
+ The signed-in branch of `POST /api/people` checked only that somebody was signed
22
+ in. The site and organisation came straight from the request body, and where that
23
+ body carries an e-mail, a password and a resident/tenant type, the service goes on
24
+ to create a **user account** and an **active membership** as well as the person row.
25
+
26
+ `site.people` is the collection every site-reach decision on the platform reads its
27
+ verdict from, so a row written there is not an ordinary record — it manufactures
28
+ reach into another client's estate.
29
+
30
+ This adds the site-reach check the camera, HID and people-list paths already use,
31
+ behind `PEOPLE_CREATE_REACH_MODE`, and **ships it in `log` mode**: it records what
32
+ it would refuse and refuses nothing. `enforce` refuses; `off` does not look. Any
33
+ unexpected error allows the request — this must never be why a real registration
34
+ fails.
35
+
36
+ It ships off because of RP-5. A person row carries no `createdBy`, so who created
37
+ the existing rows cannot be established retrospectively and the true refusal count
38
+ is only knowable from live traffic. Measured read-only on staging: 372
39
+ `site.people` rows, of which exactly **1** is self-signup shaped (`platform:
40
+ "mobile"`, `status: "pending"`) and 371 were written by a signed-in caller, across
41
+ 3 of 256 sites.
42
+
43
+ Pre-login self-signup is untouched in every mode: a request with no session takes
44
+ the other branch of `add` before this runs, and that route is already constrained
45
+ by its own allow-list schema with `status` and `platform` pinned server-side.
46
+
47
+ ## 3.68.0
48
+
49
+ ### Minor Changes
50
+
51
+ - d7e9298: Manpower live status: an authenticated namespace beside the open one
52
+
53
+ `/manpower` streams every client site's live staffing level — how many guards are
54
+ actually on shift against how many were promised — to anyone who connects, with no
55
+ credential of any kind.
56
+
57
+ This adds `/manpower-live`, carrying exactly the same `manpower-status-update`
58
+ events, which admits a socket only when the handshake presents a session id that
59
+ resolves to a live session. Every refusal is an identical `Unauthorized`, and a
60
+ session store that is down refuses rather than letting everyone in.
61
+
62
+ `/manpower` itself is deliberately unchanged: the Capacitor guard app installed on
63
+ phones today and the Nuxt security screen both connect to it with no credential and
64
+ would be cut off the moment it were tightened. Every update is emitted to both, so
65
+ the two feeds can never disagree, and both namespaces share one connection handler,
66
+ so a client on the authenticated feed still starts the poll and still gets an
67
+ immediate snapshot.
68
+
69
+ A live session is the whole check, deliberately. Scoping the feed to the caller's
70
+ own sites is not possible today: manpower lives in HRM Labs' vendor id space, none
71
+ of those site ids match ours, and no field links the two — a site check would empty
72
+ the screen for the one customer using it. That mapping is a schema change and
73
+ belongs to the leads.
74
+
75
+ ### Patch Changes
76
+
77
+ - 87c8679: Module gate: the kill switch now stops the 409, and the check stops reading when there is nothing to decide
78
+
79
+ Two follow-ups from the module-gate server review, both behaviour-neutral for
80
+ anybody who is not using the kill switch.
81
+
82
+ **`MODULE_LIST_GATE=off` now means off.** Every other part of the gate checked the
83
+ master switch; `mustAcknowledge` did not. So with the gate switched off, a save that
84
+ narrowed a client's module list was still refused with a 409 "acknowledge the impact
85
+ first" — the one lever a lead would reach for in an emergency, not working for the
86
+ one path that blocks a save from going through. Both the organisation and the site
87
+ save paths go through that function, so both are fixed. With the switch at its
88
+ default the 409 behaves exactly as before, and that is asserted.
89
+
90
+ **`moduleDeniedForCaller` no longer reads memberships when no list is enforced.** It
91
+ runs on every governed request and read the caller's memberships before finding out
92
+ whether there was anything to decide — and `members.user` has no index to use. It now
93
+ returns early unless the site or its organisation has an enforced list, which is what
94
+ the notification filter already did. No verdict changes: a client that really has an
95
+ enforced list is still measured exactly as before, and that is asserted too.
96
+
97
+ Also corrects the 3.65.0 changelog, which claimed `MODULE_LIST_GATE` switched all of
98
+ the gate off at once. It did not, for the reason above.
99
+
100
+ ## 3.67.0
101
+
102
+ ### Minor Changes
103
+
104
+ - 7b9ea2f: Notifications: stop sending alerts for modules a client was never given
105
+
106
+ `NOTIFY_ACCESS_FILTER` now defaults to `on` instead of `log`, so the module-based
107
+ drop is real: a recipient no longer gets a notification when every membership they
108
+ hold at the site denies every module the notification's category is about.
109
+
110
+ Only the module drop acts. The role-based check is still computed and logged and
111
+ never drops anybody, because most apps do not enforce their role gates yet and a
112
+ role-based drop would hide alerts for screens people can still open.
113
+
114
+ Unchanged: residents, anyone with no membership at the site, Seven365 staff, sends
115
+ with no site, and categories the catalogue does not govern are all exempt; any
116
+ error sends to everyone; and `MODULE_LIST_GATE=off` still disables it entirely.
117
+ `NOTIFY_ACCESS_FILTER=log` or `off` overrides this default with no deploy.
118
+
119
+ This is inert until a client's module list is enforced — measured read-only on
120
+ staging at the time of the flip, no organisation (0 of 199) and no site (0 of 256)
121
+ had a stored list and there were no acknowledged-save markers, so nothing is
122
+ dropped for anybody until a Super Admin saves a module list with the acknowledged
123
+ preview.
124
+
125
+ ## 3.66.0
126
+
127
+ ### Minor Changes
128
+
129
+ - b7f6302: Add a staff-only handler that repairs an organisation's missing owner membership.
130
+
131
+ An organisation created before 3.60.0 can exist with no `members` row at all, so
132
+ `GET /api/members/user/:id/app/organization` answers 404 and every console
133
+ landing page tells the real owner that no organisation exists. The new
134
+ `orgOwnerRepairHandlers` writes the one membership the onboarding path already
135
+ writes, for one organisation at a time, and only when that organisation is
136
+ active, holds exactly zero `organization` memberships, and has an account
137
+ registered under its own e-mail address. Staff-only (`organizations` console
138
+ permission), idempotent under a one-writer claim, audited, and behind the
139
+ `ORG_OWNER_REPAIR` switch. No schema change and no migration.
140
+
141
+ ## 3.65.2
142
+
143
+ ### Patch Changes
144
+
145
+ - fcd2f1e: `GET /api/members/users/:id` no longer shows anybody's memberships to any signed-in account. The person and Seven365 staff still get the full list; anyone else gets only the memberships in organisations they belong to, were invited to or own (an empty list, not an error, when there are none).
146
+
147
+ ## 3.65.1
148
+
149
+ ### Patch Changes
150
+
151
+ - 69714b4: Role writes: a site's own module list narrows a role only when the site belongs to the role's organisation. A service provider's role at a client's site is no longer refused modules the client switched off for that site — matching what the role editor now offers.
152
+
153
+ ## 3.65.0
154
+
155
+ ### Minor Changes
156
+
157
+ - c4dc50b: Module gate, server step: the deny-list endpoint, the impact preview, and
158
+ acknowledge-before-save. Everything ships inert and fails open.
159
+
160
+ - `useMemberController().getModulesByUserIdType` (for
161
+ `GET /api/members/user/:id/app/:type/modules?org=&site=`) answers
162
+ `{ denied: string[] }` for the membership `getByUserIdType` answers with. It
163
+ is the same self-or-staff guard. It answers `[]` for no list, an empty list,
164
+ a resident, Seven365 staff, a site of another organisation, any lookup
165
+ error, and `MODULE_LIST_GATE=off`. `ALWAYS_ALLOWED` is never denied.
166
+ - A saved list is enforced only once it has been saved through the
167
+ acknowledged preview. The marker is the save's own append-only console-audit
168
+ row (`gateListHash`). A list saved earlier, or changed any other way, behaves
169
+ as absent. No field is added to any organisation or site.
170
+ - `useOrgController().previewOrgModules` and
171
+ `useSiteController().previewSiteModules` (for
172
+ `POST /api/organizations/:id/modules/preview` and
173
+ `POST /api/sites/:id/modules/preview`) return who would lose what. They are
174
+ read-only and never go through `GET /api/roles`.
175
+ - `updateModules` and `updateSiteModules` accept `acknowledgeImpact`. A save
176
+ that takes a module away from somebody is refused with 409 until it is
177
+ acknowledged. An empty list restores everything and never needs it. Site
178
+ saves are now recorded in the console audit (`site.modules-changed`).
179
+ - `filterByAccess` (Q7) runs at the top of the notification `send()`. It is
180
+ `NOTIFY_ACCESS_FILTER=log` by default: it logs who would be filtered and
181
+ still sends to everyone. It is exported so API-core's own sender can call it.
182
+ - `moduleDeniedForCaller` (Q3) is the server-refusal primitive. It is
183
+ `MODULE_GATE_MODE=log` by default and never refuses. `enforce` refuses only
184
+ the keys in `MODULE_GATE_ENFORCE_KEYS`. Work stamped (`at`) before the
185
+ acknowledged save is accepted.
186
+ - `MODULE_LIST_GATE` (code default `on`) switches all of the above off at
187
+ once. CORRECTION (3.68.0): it did not. `mustAcknowledge` never read it, so
188
+ with the gate off a narrowing save was still refused with a 409. Fixed in
189
+ 3.68.0; every other path did check it.
190
+
191
+ ### Patch Changes
192
+
193
+ - c993ee4: POST /api/members/direct refuses (400) a role that belongs to a different organisation, unless the caller already holds that role in the organisation being joined.
194
+ - 74f228f: POST /api/members/direct: adding yourself now needs a role you may give yourself - Seven365 staff, the organisation's owner, a role you already hold there, or the role your own invitation offers. Enrolling somebody else is unchanged.
195
+ - ae42c1c: GET /api/organizations/id/:id returns the whole organisation record only to a caller with a relationship to it (member, invitee, owner, Seven365 staff, an active resident of one of its sites, or an engaged service provider). Everyone else gets the name-only record the anonymous lookup already returns. It never answers 401/403.
196
+ - 7363b8d: Site Settings saves are no longer refused because the client has one resident-app
197
+ switch turned off. A save is refused only when it would turn ON a resident-app
198
+ switch that the site has stored as off and the client has switched off.
199
+ - 9d1a0f0: PATCH /api/users/field/:id (and v2): on your own account you may change only name, contact, nric, dateOfBirth, profile and gender, and defaultOrg to an organisation you reach. status, email and plateNumber are staff-only.
200
+
201
+ ## 3.64.5
202
+
203
+ ### Patch Changes
204
+
205
+ - 49e1aef: A person's role now follows the site they are on.
206
+
207
+ `GET /api/members/user/:id/app/:type` accepts an optional `?site=` (a 24-hex
208
+ site id, like `?org=`). When it is sent, the answer is the person's live
209
+ membership of that app type pinned to that site (inside `?org=` when it is also
210
+ sent); failing that, their organisation-wide membership in `?org=`; failing
211
+ that, any live membership in `?org=`. When none of these exists the route
212
+ answers exactly as before. A removed membership never wins, and a site never
213
+ turns a found membership into "not found". Callers that do not send `site`
214
+ see no change. Login, auth-v2 and verification are unchanged.
215
+
216
+ The rule is the pure `pickSiteMembership` in `utils/member-lookup.util.ts`.
217
+
3
218
  ## 3.64.4
4
219
 
5
220
  ### Patch Changes
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@7365admin1/core",
3
3
  "license": "MIT",
4
- "version": "3.64.5-staging.308",
4
+ "version": "3.64.5-staging.310",
5
5
  "author": "7365admin1",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.mjs",
@@ -1,5 +0,0 @@
1
- ---
2
- "@7365admin1/core": patch
3
- ---
4
-
5
- A duplicate membership insert now returns 400 "The user is already a member of this organization." instead of a 500.