toga-ai 1.0.201 → 1.0.202
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/knowledge/1.0/apps/library/INDEX.md +1 -0
- package/knowledge/1.0/apps/library/features/mvc-page-pattern-and-app-skeleton.md +113 -0
- package/knowledge/2.0/apps/saml/INDEX.md +1 -0
- package/knowledge/2.0/apps/saml/architecture.md +4 -2
- package/knowledge/2.0/apps/saml/features/downstream-integration-contract.md +81 -0
- package/knowledge/INDEX.md +3 -2
- package/knowledge/clients/true/INDEX.md +6 -0
- package/knowledge/clients/true/features/users-personas-data-model.md +45 -0
- package/knowledge/clients/true/profile.md +26 -0
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
| [Diagnostic Dialog — View Recommended Services Routing](features/diagnostic-dialog-view-recommended-services.md) | `App_Model_Toga_Diagnostic::initializeDiagnosticDialog()` renders the device modal used across all TOGa service request views. | library/app/model/toga/diagnostic.php |
|
|
7
7
|
| [Elite Freshservice Sync (library)](features/elite-freshservice-sync.md) | `App_Api_Toga2` in `library/app/api/toga2.php` orchestrates bidirectional sync between TOGA 2 and TOGaDesk. | library/app/api/toga2.php |
|
|
8
8
|
| [Branded HTML Email Templates (App_Email_Template)](features/email-templates.md) | `App_Email_Template` (`app/email/template.php`) is the base class for branded HTML emails in the 1.0 (`App_`) framework. | library/app/email/template.php, library/app/email/agilant.php |
|
|
9
|
+
| [1.0 MVC Page Pattern & New-App Skeleton](features/mvc-page-pattern-and-app-skeleton.md) | This is the **reusable recipe for standing up a new 1.0 (`App_`) application** and for adding pages to one — the folder-based MVC routing, the page lifecycle, t | library/app/framework.php, library/app/frameworkindex.php, library/app/mvc.php, library/app/database.php, library/app/model.php, library/app/config.php |
|
|
9
10
|
| [NetSuite SuiteQL/REST API Reference](features/netsuite-suiteql-api-reference.md) | General working reference for the Agilant NetSuite integration: how to authenticate, how SuiteQL behaves, and the confirmed schema of the tables/columns/codes w | library/app/api/netsuite/rest.php, library/ssl/netsuite_ec_key.pem |
|
|
10
11
|
| [NetSuite SuiteQL/REST Shim — Field Semantics](features/netsuite-suiteql-rest-shim.md) | `App_Api_Netsuite_Rest` is the REST/SuiteQL replacement for the deprecated NetSuite SOAP toolkit. | library/app/api/netsuite/rest.php |
|
|
11
12
|
| [Startech PC Matic B2B Sync (library)](features/startech-pcmaticb2b-sync.md) | `library/app/api/toga2.php` handles bidirectional ticket sync for PC Matic B2B between TOGaDesk 1.0 and TOGA 2.0. | library/app/api/toga2.php |
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 1.0 MVC Page Pattern & New-App Skeleton
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: library
|
|
5
|
+
project: Library
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-06-25
|
|
10
|
+
owners: [jcardinal]
|
|
11
|
+
files:
|
|
12
|
+
- library/app/framework.php
|
|
13
|
+
- library/app/frameworkindex.php
|
|
14
|
+
- library/app/mvc.php
|
|
15
|
+
- library/app/database.php
|
|
16
|
+
- library/app/model.php
|
|
17
|
+
- library/app/config.php
|
|
18
|
+
related:
|
|
19
|
+
- ../architecture.md
|
|
20
|
+
- ../../togaview/architecture.md
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Summary
|
|
24
|
+
|
|
25
|
+
This is the **reusable recipe for standing up a new 1.0 (`App_`) application** and for adding
|
|
26
|
+
pages to one — the folder-based MVC routing, the page lifecycle, the model/DB conventions, and
|
|
27
|
+
the minimal new-app skeleton. The `library` core supplies all of it; an app contributes only its
|
|
28
|
+
`index.php`, config, `_/app/` framework subclasses, `mvc/` pages, and `common/` templates.
|
|
29
|
+
togaview is the reference implementation (see its architecture doc for the multi-tenant
|
|
30
|
+
specifics); this doc captures the framework-level pattern that any new 1.0 app reuses.
|
|
31
|
+
|
|
32
|
+
## How it works
|
|
33
|
+
|
|
34
|
+
### Folder-based, classless routing
|
|
35
|
+
A URL maps directly to a file on disk — **the file path IS the route**, there is no routing
|
|
36
|
+
config and no controller classes. `App_MVC::parseRoute()` turns the request URI into
|
|
37
|
+
`mvc/<folder…>/<httpmethod>.php`, matching **longest-to-shortest** so overlapping paths resolve
|
|
38
|
+
to the most specific folder.
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
GET /task_list/ajax -> mvc/task_list/ajax/get.php
|
|
42
|
+
POST /login -> mvc/login/post.php
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
- `<httpmethod>` is `get` or `post`, taken from the HTTP verb (overridable via a `_method` POST param).
|
|
46
|
+
- `get.php` renders a page; `post.php` does writes then redirects via `App_MVC::routeTo()`
|
|
47
|
+
(`header('Location: …'); exit;`).
|
|
48
|
+
- Because matching is longest-to-shortest, keep route folders distinct to avoid surprise matches.
|
|
49
|
+
|
|
50
|
+
### Entry point (3 lines)
|
|
51
|
+
```php
|
|
52
|
+
require '_.php'; // bootstraps library core + autoloader
|
|
53
|
+
App_Framework_<App>::initialize(); // env, config, DB links, session, Sentry
|
|
54
|
+
App_Framework_<App>::renderIndex(); // resolves stylePath + dispatches the page
|
|
55
|
+
```
|
|
56
|
+
App-specific framework classes live in `<app>/_/app/` and extend the library bases
|
|
57
|
+
`App_Framework` (`framework.php`) and `App_FrameworkIndex` (`frameworkindex.php`).
|
|
58
|
+
|
|
59
|
+
### Page lifecycle (no template engine)
|
|
60
|
+
`App_FrameworkIndex::body()` loads the matched mvc file **inline** between
|
|
61
|
+
`common/<stylePath>/header.php` and `common/<stylePath>/footer.php`. There is no master-template
|
|
62
|
+
engine — pages are inline PHP + HTML. `stylePath` is selected by `$_SERVER['HTTP_HOST']` in
|
|
63
|
+
`framework.php::renderIndex()`, giving per-brand CSS under `assets/css/<stylePath>/`. Pages guard
|
|
64
|
+
auth themselves by checking `$_SESSION` at the top.
|
|
65
|
+
|
|
66
|
+
### Adding a page
|
|
67
|
+
Create `mvc/<page>/get.php` (and `post.php` if it writes). Scaffold from `mvc/_TEMPLATE/`.
|
|
68
|
+
|
|
69
|
+
### Models
|
|
70
|
+
Extend `App_Model`, named `App_Model_<Db>_<Table>`, declaring `const TABLENAME`, `const DATABASE`,
|
|
71
|
+
and `public $field = self::FIELDTYPE_*` for each column. Field types: `PRIMARYKEY`, `INT`, `CHAR`,
|
|
72
|
+
`DATETIME`, `BLOB`, `BLOBSTORAGE`, `FOREIGNKEY`, `SERIALIZED`, `DATETIME_CREATED`,
|
|
73
|
+
`DATETIME_UPDATED`.
|
|
74
|
+
|
|
75
|
+
```php
|
|
76
|
+
class App_Model_Toga_Client extends App_Model {
|
|
77
|
+
const TABLENAME = 'Clients';
|
|
78
|
+
const DATABASE = 'db_toga';
|
|
79
|
+
public $id = self::FIELDTYPE_PRIMARYKEY;
|
|
80
|
+
public $clientName = self::FIELDTYPE_CHAR;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
Usage: `new App_Model_X($id)` loads a row; `->save()` persists; `App_Model_X::lookupValueByField()`.
|
|
84
|
+
|
|
85
|
+
### Databases (multiple are first-class)
|
|
86
|
+
DB access is mysqli via `App_Database::query($sql, 'db_<name>')`. **Multiple databases are
|
|
87
|
+
first-class:** each `[database_<name>]` section in `config.<env>.ini` is registered as registry
|
|
88
|
+
key `db_<name>` by `App_Database::registerDatabaseConnect()`. SELECTs **auto-route to
|
|
89
|
+
`<link>_read`** when the host is an RDS cluster (read-cluster support). Escape with
|
|
90
|
+
`App_Database::sqlEscape()`; read results with `buildArrayOfRows()` / `fetchRow()`.
|
|
91
|
+
|
|
92
|
+
### Config
|
|
93
|
+
`App_Config` does `parse_ini_file(config.<ENVIRONMENT>.ini)`; the environment comes from
|
|
94
|
+
`getenv('ENVIRONMENT')` (defaults to `'worker'` — an unset env loads the wrong file). Sections:
|
|
95
|
+
`[internal]`, `[database_*]`, `[email]`, `[external]`, `[modules]`, `[api]`.
|
|
96
|
+
|
|
97
|
+
> **Secrets are currently stored in plaintext ini files** — a known practice, not a recommended
|
|
98
|
+
> one. Document where a credential lives, never its value.
|
|
99
|
+
|
|
100
|
+
## Minimal new-app skeleton
|
|
101
|
+
```
|
|
102
|
+
index.php # the 3-line entry point
|
|
103
|
+
config.<env>.ini # per-environment config + DB sections
|
|
104
|
+
mvc/_TEMPLATE/get.php # page scaffold
|
|
105
|
+
mvc/<page>/{get,post}.php # one folder per route
|
|
106
|
+
common/<stylePath>/{header,footer}.php # brand shell wrapped around each page
|
|
107
|
+
common/404.php
|
|
108
|
+
assets/ # css/js per stylePath
|
|
109
|
+
```
|
|
110
|
+
The app depends on the `library` core repo (bootstrapped via `_.php`).
|
|
111
|
+
|
|
112
|
+
## Change history
|
|
113
|
+
- 2026-06-25 — Documented the 1.0 folder-based MVC page pattern, model/multi-DB conventions, and the minimal new-app skeleton, discovered while planning the new "Toolbox" 1.0 app (reference: togaview) (jcardinal)
|
|
@@ -3,4 +3,5 @@
|
|
|
3
3
|
| Doc | Summary | Files |
|
|
4
4
|
|-----|---------|-------|
|
|
5
5
|
| [saml Architecture](architecture.md) | The `saml` repo is the SAML 2.0 / SSO gateway for all TOGa applications. | saml/index.php, saml/_.php, saml/Controller/Index.php, saml/Config/production.ini, saml/.platform/hooks/prebuild/git.sh, saml/.ebextensions/git.php |
|
|
6
|
+
| [SAML Downstream Integration Contract](features/downstream-integration-contract.md) | The contract a **downstream TOGa app** implements to authenticate users through the SAML gateway (`saml.togahub.com`). | saml/Controller/Index.php, _underscore/Model/Core/ClientAuthentication.php, _underscore/Model/True/ClientAuthentication.php |
|
|
6
7
|
| [Rate SAML User Provisioning](features/rate-user-provisioning.md) | When a Rate user authenticates via SSO, `_Model_Rate_ClientAuthentication::getAuthenticatedSsoUser()` is called by the saml gateway. | _underscore/Model/Rate/ClientAuthentication.php, _underscore/Model/Rate/User.php, _underscore/Model/Rate/Customer.php, _underscore/Model/Rate/Contact.php |
|
|
@@ -7,7 +7,7 @@ client: shared
|
|
|
7
7
|
type: architecture
|
|
8
8
|
status: active
|
|
9
9
|
updated: 2026-06-11
|
|
10
|
-
owners: ["rgirish"]
|
|
10
|
+
owners: ["rgirish", "jcardinal"]
|
|
11
11
|
files:
|
|
12
12
|
- saml/index.php
|
|
13
13
|
- saml/_.php
|
|
@@ -80,9 +80,11 @@ To onboard a new SSO client, add the class in `_underscore` — not in this repo
|
|
|
80
80
|
## Gotchas / known issues
|
|
81
81
|
|
|
82
82
|
- **`_Database::register()` auto-starts a lazy transaction (since Apr 2 2026).** Any code that registers DBs then writes must call `_Database::transactionCommit()` before exiting — otherwise MySQL silently rolls back all writes on connection close. The `/acs` handler calls `transactionCommit()` after `getAuthenticatedSsoUser()` succeeds and before the redirect. See `_underscore/Database.php:48`.
|
|
83
|
-
- **SAML signature verification is commented out.** The IdP X509 cert verification block is disabled. The only gate is the encrypted RelayState. Re-enabling per-IdP signature verification is
|
|
83
|
+
- **SAML signature verification is commented out — this is the repo's top security priority.** The IdP X509 cert verification block in the `/acs` flow is disabled, so the gateway accepts any well-formed, status-success `SAMLResponse` without proving it was signed by the expected IdP. The only remaining gate is the encrypted RelayState, which authenticates the *originating TOGa request* — not the *asserting IdP*. Threat model: an attacker who can craft or replay a `SAMLResponse` (or a malicious/compromised IdP) can forge an identity assertion for any user, since nothing binds the assertion to a trusted signing key. Re-enabling per-IdP X509 signature verification is the single highest-impact security fix for this repo.
|
|
84
|
+
- **Plaintext secrets in source — move to AWS SSM Parameter Store.** `saml/Config/production.ini` stores credentials in plaintext, and a Sentry DSN is hardcoded in `saml/Controller/Index.php`. Both are checked into the repo. Migrate these to AWS SSM Parameter Store (SecureString) and load at runtime; the source tree should reference parameter names only, never literal credential values.
|
|
84
85
|
- **SLS not implemented.** `/sls` falls through to the default banner.
|
|
85
86
|
- **`set_exception_handler(null)` at top of `saml()`.** Unhandled exceptions output raw PHP errors. All exceptions from `getAuthenticatedSsoUser()` are caught and sent to Sentry.
|
|
86
87
|
|
|
87
88
|
## Change history
|
|
88
89
|
- 2026-06-11 — Added `transactionCommit()` before redirect; wrapped `getAuthenticatedSsoUser()` in try/catch with Sentry; echo+exit on auth failure (rgirish)
|
|
90
|
+
- 2026-06-25 — Sharpened signature-verification gotcha with explicit threat model and flagged it as the repo's top security priority; documented plaintext secrets in `production.ini` + hardcoded Sentry DSN in `Controller/Index.php` with SSM Parameter Store recommendation (jcardinal)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: SAML Downstream Integration Contract
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
repo: saml
|
|
5
|
+
project: SAML SSO Gateway
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-06-25
|
|
10
|
+
owners: [jcardinal]
|
|
11
|
+
files:
|
|
12
|
+
- saml/Controller/Index.php
|
|
13
|
+
- _underscore/Model/Core/ClientAuthentication.php
|
|
14
|
+
- _underscore/Model/True/ClientAuthentication.php
|
|
15
|
+
related:
|
|
16
|
+
- ../architecture.md
|
|
17
|
+
- ../../_underscore/architecture.md
|
|
18
|
+
- ../../../clients/rate/features/saml-sso.md
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Summary
|
|
22
|
+
|
|
23
|
+
The contract a **downstream TOGa app** implements to authenticate users through the SAML gateway
|
|
24
|
+
(`saml.togahub.com`). The architecture doc covers the gateway internals; this doc is the
|
|
25
|
+
**integration recipe** for an app that wants SSO — how to initiate the flow, what the gateway
|
|
26
|
+
hands back, and how to consume it. Reusable for any new SSO-consuming app.
|
|
27
|
+
|
|
28
|
+
## How it works
|
|
29
|
+
|
|
30
|
+
### SP-initiated flow
|
|
31
|
+
1. The downstream app calls
|
|
32
|
+
`_Model_Core_ClientAuthentication::singleSignOnServiceUrl(uuid, domainUuid, urlParameters)`
|
|
33
|
+
to build a signed SAML AuthnRequest (HTTP-Redirect binding). The RelayState
|
|
34
|
+
(`{v:1, time, domain, urlParameters}`) is encrypted with the Core `API_SECRET_ACCESS_TOKEN`
|
|
35
|
+
and carries a 300-second TTL.
|
|
36
|
+
2. The user authenticates at the client IdP, which POSTs the `SAMLResponse` to the gateway `/acs`.
|
|
37
|
+
3. `/acs` decrypts RelayState (supports key rotation via `API_SECRET_ACCESS_TOKEN_PREVIOUS`),
|
|
38
|
+
resolves Core `Domain → Client → Environment`, **dynamically registers the client DBs**
|
|
39
|
+
(`DB_CLIENT`, `DB_CLIENT_LOGS`, `DB_CLIENT_ARCHIVE`), then calls the client-specific mapper
|
|
40
|
+
`_Model_<ClientIdentifier>_ClientAuthentication::getAuthenticatedSsoUser($assertion)` to
|
|
41
|
+
resolve or create the user.
|
|
42
|
+
- Base `_Model_True_ClientAuthentication` matches by **email** (from the NameID).
|
|
43
|
+
- Compass matches `c_hrEmpUsername`; Rate matches `borrowerID`.
|
|
44
|
+
|
|
45
|
+
### Handoff back to the downstream app
|
|
46
|
+
The gateway redirects the browser to:
|
|
47
|
+
```
|
|
48
|
+
<appDomain>?saml=<base64(json)>
|
|
49
|
+
```
|
|
50
|
+
where the JSON is:
|
|
51
|
+
```json
|
|
52
|
+
{
|
|
53
|
+
"auth": "encrypted-user-uuid",
|
|
54
|
+
"payload": { "client": "encryptWithKey(client.uuid)", "user": "encryptWithKey(user.uuid)" }
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
all encrypted under the Core `API_SECRET_ACCESS_TOKEN`. An optional `?urlParameters` is forwarded
|
|
58
|
+
through.
|
|
59
|
+
|
|
60
|
+
The downstream app then: base64-decodes the `saml` param, JSON-parses it, decrypts the client and
|
|
61
|
+
user UUIDs with `_String::decryptWithKey()`, loads the user, and **establishes its own session**.
|
|
62
|
+
The gateway holds no session — session ownership is entirely the downstream app's.
|
|
63
|
+
|
|
64
|
+
### Integrating a NEW downstream app
|
|
65
|
+
1. Ensure an SSO config row exists in `_Model_Core_ClientAuthentications_Sso`.
|
|
66
|
+
2. Implement/extend `_Model_<Client>_ClientAuthentication::getAuthenticatedSsoUser()` in
|
|
67
|
+
`_underscore` (the gateway repo is not modified — see the per-client extension pattern in the
|
|
68
|
+
architecture doc).
|
|
69
|
+
3. Initiate SSO via `singleSignOnServiceUrl()`.
|
|
70
|
+
4. Consume the `?saml=` handoff and decrypt the UUIDs with `API_SECRET_ACCESS_TOKEN`.
|
|
71
|
+
|
|
72
|
+
## Gotchas / known issues
|
|
73
|
+
|
|
74
|
+
- **Lazy-transaction write-drop.** `_Database::register()` auto-starts a lazy transaction (since
|
|
75
|
+
Apr 2026). Any `/acs` write path (e.g. user auto-creation) must call
|
|
76
|
+
`_Database::transactionCommit()` before exit or the writes are silently rolled back.
|
|
77
|
+
- **Gateway holds no session** — every downstream app must build and own its own session from the
|
|
78
|
+
decrypted handoff.
|
|
79
|
+
|
|
80
|
+
## Change history
|
|
81
|
+
- 2026-06-25 — Documented the downstream integration contract (SP-initiated flow, `?saml=` handoff shape, and the 4 onboarding steps), discovered while planning a new SSO-consuming app (reference: saml) (jcardinal)
|
package/knowledge/INDEX.md
CHANGED
|
@@ -4,7 +4,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
4
4
|
|
|
5
5
|
## 1.0 framework
|
|
6
6
|
|
|
7
|
-
- **library** (Library) _(framework core)_ —
|
|
7
|
+
- **library** (Library) _(framework core)_ — 9 doc(s) → [1.0/apps/library/INDEX.md](1.0/apps/library/INDEX.md)
|
|
8
8
|
- **worker** (Worker) — 10 doc(s) → [1.0/apps/worker/INDEX.md](1.0/apps/worker/INDEX.md)
|
|
9
9
|
- **togadesk** (TOGa Desk) — 8 doc(s) → [1.0/apps/togadesk/INDEX.md](1.0/apps/togadesk/INDEX.md)
|
|
10
10
|
- **togaview** (TOGa View) — 6 doc(s) → [1.0/apps/togaview/INDEX.md](1.0/apps/togaview/INDEX.md)
|
|
@@ -20,7 +20,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
20
20
|
- **api2** (API) — 6 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
|
|
21
21
|
- **dbchanges2** (Database Changes) _(framework core)_ — 2 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
|
|
22
22
|
- **toga2-supply** (TOGa Supply) — 3 doc(s) → [2.0/apps/toga2-supply/INDEX.md](2.0/apps/toga2-supply/INDEX.md)
|
|
23
|
-
- **saml** (SAML SSO Gateway) —
|
|
23
|
+
- **saml** (SAML SSO Gateway) — 3 doc(s) → [2.0/apps/saml/INDEX.md](2.0/apps/saml/INDEX.md)
|
|
24
24
|
- **toga2-view** (TOGa View Frontend) — 4 doc(s) → [2.0/apps/toga2-view/INDEX.md](2.0/apps/toga2-view/INDEX.md)
|
|
25
25
|
- **toga2-hub** (TOGa Hub) — 2 doc(s) → [2.0/apps/toga2-hub/INDEX.md](2.0/apps/toga2-hub/INDEX.md)
|
|
26
26
|
- **talos** (TOGa IQ) — 6 doc(s) → [2.0/apps/talos/INDEX.md](2.0/apps/talos/INDEX.md)
|
|
@@ -51,6 +51,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
51
51
|
- **Quad Graphics** (`quad`) → [clients/quad/INDEX.md](clients/quad/INDEX.md)
|
|
52
52
|
- **Rate** (`rate`) → [clients/rate/INDEX.md](clients/rate/INDEX.md)
|
|
53
53
|
- **Tow Foundation** (`tow-foundation`) → [clients/tow-foundation/INDEX.md](clients/tow-foundation/INDEX.md)
|
|
54
|
+
- **TOGA Technology** (`true`) → [clients/true/INDEX.md](clients/true/INDEX.md)
|
|
54
55
|
- **Walmart Client Profile** (`walmart`) → [clients/walmart/INDEX.md](clients/walmart/INDEX.md)
|
|
55
56
|
- **Wiss, Janney, Elstner Associates, Inc.** (`wje`) → [clients/wje/INDEX.md](clients/wje/INDEX.md)
|
|
56
57
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# Client: TOGA Technology `true`
|
|
2
|
+
|
|
3
|
+
| Doc | Framework | Summary | Files |
|
|
4
|
+
|-----|-----------|---------|-------|
|
|
5
|
+
| [True Users / Personas Data Model](features/users-personas-data-model.md) | 2.0 | The `Client_True` schema models internal/staff users and their **personas** — used to gate UI and navigation by staff role in downstream tooling. | |
|
|
6
|
+
| [TOGA Technology](profile.md) | 2.0 | "True" is TOGa's own **internal / staff tenant** — the base client whose data lives in the `Client_True` schema in production. | |
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: True Users / Personas Data Model
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
project: _Underscore
|
|
5
|
+
client: true
|
|
6
|
+
type: client-feature
|
|
7
|
+
status: active
|
|
8
|
+
updated: 2026-06-25
|
|
9
|
+
owners: [jcardinal]
|
|
10
|
+
files: []
|
|
11
|
+
related:
|
|
12
|
+
- clients/true/profile.md
|
|
13
|
+
- 2.0/apps/saml/features/downstream-integration-contract.md
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Summary
|
|
17
|
+
|
|
18
|
+
The `Client_True` schema models internal/staff users and their **personas** — used to gate UI and
|
|
19
|
+
navigation by staff role in downstream tooling. After SSO resolves a user, an app looks up that
|
|
20
|
+
user's personas and drives visibility from persona membership.
|
|
21
|
+
|
|
22
|
+
## How it works
|
|
23
|
+
|
|
24
|
+
### Tables
|
|
25
|
+
- **`Users`** — key columns: `id`, `uuid` (char, unique), `email` (varchar, unique), `firstName`,
|
|
26
|
+
`lastName`, `displayName`, `isActive` (tinyint, default `1`), `password` (char, nullable), plus
|
|
27
|
+
FKs `contactId`, `clientId`, `locationId`, `userTypeId`, `supervisorUserId`.
|
|
28
|
+
- **`Personas`** — `id`, `uuid`, `name`, `number`.
|
|
29
|
+
- **`Users_Personas`** (many-to-many bridge) — `id`, `uuid`, `userId`, `personaId`.
|
|
30
|
+
|
|
31
|
+
### Live personas (production)
|
|
32
|
+
TOGa Technology, Development Team, Legal Team, Contact Center, Operations, Executive, Audit.
|
|
33
|
+
|
|
34
|
+
### Usage pattern for downstream apps
|
|
35
|
+
After SSO resolves the user, look up their personas via
|
|
36
|
+
`Users JOIN Users_Personas JOIN Personas`, then drive UI / navigation visibility by persona
|
|
37
|
+
membership.
|
|
38
|
+
|
|
39
|
+
## Gotchas / known issues
|
|
40
|
+
|
|
41
|
+
- **Cache personas in session.** Cache the resolved persona names in `$_SESSION` at login to avoid
|
|
42
|
+
a per-request DB read for visibility checks.
|
|
43
|
+
|
|
44
|
+
## Change history
|
|
45
|
+
- 2026-06-25 — Documented the Client_True Users/Personas data model and persona-gated UI usage pattern, discovered via prod DB schema inspection while planning persona-gated internal tooling (jcardinal)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "TOGA Technology"
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
apps:
|
|
5
|
+
- _underscore
|
|
6
|
+
project: _Underscore
|
|
7
|
+
client: true
|
|
8
|
+
type: profile
|
|
9
|
+
status: active
|
|
10
|
+
updated: 2026-06-25
|
|
11
|
+
owners: [jcardinal]
|
|
12
|
+
files: []
|
|
13
|
+
related:
|
|
14
|
+
- clients/true/features/users-personas-data-model.md
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Summary
|
|
18
|
+
|
|
19
|
+
"True" is TOGa's own **internal / staff tenant** — the base client whose data lives in the
|
|
20
|
+
`Client_True` schema in production. It is also the default SSO identity mapper
|
|
21
|
+
(`_Model_True_ClientAuthentication`, which matches users by email). Internal tooling that gates UI
|
|
22
|
+
by staff role (e.g. the planned Toolbox app) reads its `Users` / `Personas` model.
|
|
23
|
+
|
|
24
|
+
- **Client DB:** `Client_True`
|
|
25
|
+
- **Client identifier:** `True`
|
|
26
|
+
- **SSO mapper:** `_Model_True_ClientAuthentication` (base; matches by email from NameID)
|
package/package.json
CHANGED