Merge release/delivery (IAM single sign-on) into the triage work

Brings the four release/delivery commits (IAM SSO for the admin panel,
both apps and the API; IAM env in docker-compose) onto fix/issues-triage.

Conflicts:
- customer-auth.service.ts imports: both kept.
- both apps' api/client.ts: both kept (AccountingBalance/WageQuote, and
  iamAppUrl).
- all build output (admin-panel, user-app, user-app-v2 dist, and the api
  release bundle): rebuilt from the merged source instead of picking a
  side.

Fixed while verifying:
- The IAM change calls iam.browserBootstrapUrl after every login, but
  the identity-service stand-ins in three test files lacked it. 15 tests
  failed on release/delivery itself.
- SMS relay: SMS_RELAY_PLATFORM was read but never sent, so the gateway
  never got `platform` (documented body: phone, host, text, platform).
  relayConfig() now returns it ("default" → null) and the request carries
  it. sms.service.spec now passes.

All 249 API tests pass; the three front-ends type-check and build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
s.esmaeili
2026-10-10 09:03:53 +03:30
co-authored by Claude Opus 5.5
315 changed files with 82919 additions and 7020 deletions
+23 -1
View File
@@ -297,6 +297,12 @@ export interface WageQuote {
finalPercent: string
}
function iamAppUrl(path: string) {
const base = import.meta.env.BASE_URL || '/'
const prefix = base.endsWith('/') ? base : `${base}/`
return `${window.location.origin}${prefix}${path.replace(/^\//, '')}`
}
export const api = {
listProducts: () => request<ProductSummary[]>('/catalog/products'),
/**
@@ -316,11 +322,27 @@ export const api = {
* already-used code is a 401.
*/
verifyOtp: (username: string, password: string) =>
request<{ token: string; customer: { id: string; mobile: string } }>(
request<{ token: string; customer: { id: string; mobile: string }; iamBootstrapUrl?: string }>(
'/customer/auth/verify-otp',
{ method: 'POST', body: JSON.stringify({ username, password }) },
),
ssoStart: () =>
request<{ enabled: boolean; authorize_url: string | null }>(
`/customer/auth/sso/start?redirect_uri=${encodeURIComponent(iamAppUrl('auth/iam/callback'))}`,
),
ssoCallback: (code: string, state: string) =>
request<{ token: string; customer: { id: string; mobile: string } }>('/customer/auth/sso/callback', {
method: 'POST',
body: JSON.stringify({ code, state }),
}),
ssoLogoutUrl: () =>
request<{ logout_url: string | null }>(
`/customer/auth/sso/logout-url?return_url=${encodeURIComponent(iamAppUrl(''))}`,
),
// The three reads below identify the customer by TOKEN. They replaced
// /customers/:id, /:id/orders and /:id/ledger-entries, which took the id from
// the URL and let anyone read anyone (SEC-08).