toga-ai 1.0.1113 → 1.0.1114

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.
@@ -2,5 +2,6 @@
2
2
 
3
3
  | Doc | Summary |
4
4
  |-----|---------|
5
+ | [API 1.0 (api) Architecture](architecture.md) | The 1.0 REST `api` (clients, suppliers, Talos Voice): single front controller `api.php`, route classes in `_/app/route/`, no sessions, error handling from libra |
5
6
  | [Talos Ticket API (1.0 api POST/PUT /ticket) — Desk tickets + file uploads from Talos Voice](features/talos-ticket-endpoint.md) | 1.0 `api` route that Talos Voice calls to create (`POST /ticket`) and update (`PUT /ticket/{ticketNumber}`) TOGa Desk tickets and attach call files; open before |
6
7
  | [Deploying API 1.0 to Elastic Beanstalk (PHP 8.5 / Amazon Linux 2023)](workflows/deploy-to-elastic-beanstalk-al2023.md) | How the 1.0 `api` deploys on EB PHP 8.5 / AL2023 (Apache proxy) — new prod env + pipeline, s3fs 1.97 mount over IMDSv2, cross-account `asifiles`, php-fpm ini ru |
@@ -0,0 +1,50 @@
1
+ ---
2
+ title: API 1.0 (api) Architecture
3
+ framework: "1.0"
4
+ repo: api
5
+ project: API 1.0
6
+ client: shared
7
+ type: architecture
8
+ status: active
9
+ updated: 2026-10-22
10
+ owners: ["jcardinal"]
11
+ files:
12
+ - api/api.php
13
+ - api/_/app/framework.php
14
+ - api/_/app/route.php
15
+ - api/_/app/route/
16
+ - api/_/app/error.php
17
+ - api/.htaccess
18
+ related:
19
+ - workflows/deploy-to-elastic-beanstalk-al2023.md
20
+ - features/talos-ticket-endpoint.md
21
+ - ../library/architecture.md
22
+ - ../library/features/php-8-5-runtime-compatibility.md
23
+ - ../togadesk/features/s3fs-asifiles-file-storage.md
24
+ ---
25
+
26
+ The 1.0 REST `api` (clients, suppliers, Talos Voice): single front controller `api.php`, route classes in `_/app/route/`, no sessions, error handling from library; open before adding a route or changing how api boots, logs, or stores files.
27
+
28
+ ## Summary
29
+
30
+ `api` is a 1.0 `App_` app (bootstraps `library/_.php`) serving `api.agilantsolutions.com` / `api.togatechnology.com`. Runs on EB PHP 8.5 / AL2023 (php-fpm), env `togatech-legacy-api-production`, us-east-1 — see [deploy](workflows/deploy-to-elastic-beanstalk-al2023.md). Cutover from the old env was by Route 53 DNS (not EB CNAME swap).
31
+
32
+ **Critical rules:**
33
+ - Never put `php_value` in `.htaccess` — "Invalid command" 500 under php-fpm. Use `application.ini` / `phpini` option settings.
34
+ - Never call `App_Cloud` from api — no composer / AWS SDK here; it throws `Error`. File bytes go to the s3fs mount of `asifiles` ([s3fs asifiles](../togadesk/features/s3fs-asifiles-file-storage.md)).
35
+ - `useSessions=false` — `$_SESSION` lives for one request only. Do not rely on it.
36
+ - The live error handler is library's `App_Error::handleError`; it exits on any warning/deprecation ([PHP 8.5 compatibility](../library/features/php-8-5-runtime-compatibility.md)). Cast nullable input before string functions.
37
+
38
+ ## Structure
39
+
40
+ - `api.php` — front controller: parses the URI, answers `/health/` with 200 `OK`, logs every inbound call to `Logs.API`, authenticates, then dispatches.
41
+ - Auth: HMAC-SHA256 of the client timestamp with `apiSecret`, key looked up in `TOGA.Clients` / `Suppliers`; or a `securityToken` in the request body (also on GET).
42
+ - Routes: `_/app/route/<name>.php` = `abstract class App_Route_<Name> extends App_Route` with `static $routes = ['METHOD /path/{param}' => 'methodName']`. Add a route by adding a class here.
43
+ - `_/app/framework.php` — `App_Framework_ASIAPI::initialize()`: `useSessions=false`, barcode generator.
44
+ - `_/app/error.php` — `App_Error_Api` is dead code (its `initialize()` call is commented out). Do not extend it.
45
+ - `config.<env>.ini` in the web root, blocked from the web by the root `.htaccess` deny rule.
46
+
47
+ ## Gotchas
48
+
49
+ - **`App_Framework::getInstanceId()` logs a blank `instanceId` on AL2023.** `App_Cloud::getInstanceId` likely uses IMDSv1 (EB AL2023 sets `DisableIMDSv1=true`); the blank value is then cached in `/var/www/cache/instanceId.txt`. Open — follow-up ticket.
50
+ - **Security, open (values not recorded):** `config.prod.ini` holds DB / SMTP / cert passwords (needs rotating); an old GitHub token and the old s3fs IAM key are in git history; `test.php` and `api.php` (accounts shortcut) hold hardcoded tokens.
@@ -33,13 +33,13 @@ How the 1.0 `api` deploys on EB PHP 8.5 / AL2023 (Apache proxy) — new prod env
33
33
 
34
34
  TRUE-83054 moved `api` off EB "PHP 7.2 / 64bit Amazon Linux 2.8.9" (AL1, Apache + mod_php) to "PHP 8.5 / Amazon Linux 2023 4.13.13" with `ProxyServer: apache`. Shared AL2023 rules (ini via cfn-init `files:`, fpm overrides `/etc/php.d`, clone fails the deploy, `/var/app/staging`) live in the [Tools deploy doc](../../tools/workflows/deploy-to-elastic-beanstalk-al2023.md) — not repeated here. This doc holds only what differs for api.
35
35
 
36
- - Env `togatech-legacy-api-production`, EB app `API`, us-east-1, production account 654654170868. Old AL1 env kept as rollback; cutover = CNAME swap.
37
- - Pipeline `Legacy-API-Production` (us-east-1), copied from `Legacy-Store-Production`: role `service-role/AWS-CodePipeline-Service`, artifacts `true-elasticbeanstalk-deployments-1`, CodeStar source `agilantsolutions/api` branch `_production`, Manual approval stage, EB deploy.
36
+ - Env `togatech-legacy-api-production`, EB app `API`, us-east-1, production account 654654170868. Old AL1 env `agilant-api-prod` (legacy account 502614707982, us-west-2) kept as rollback; cutover = Route 53 alias (step 12).
37
+ - Pipeline `Legacy-API-Production` (us-east-1), copied from `Legacy-Store-Production`: role `service-role/AWS-CodePipeline-Service`, artifacts `true-elasticbeanstalk-deployments-1`, CodeStar source `agilantsolutions/api` branch `_production`, Manual approval stage, EB deploy. The AL2023 work reached `_production` via PR #41 plus later direct merges.
38
38
 
39
39
  ## Steps
40
40
 
41
- 1. `009_setup_phpini.config` — sets `ProxyServer: apache`; writes `/etc/php.d/application.ini` (cfn-init `files:`); `memory_limit` / `max_execution_time` go in `aws:elasticbeanstalk:container:php:phpini` because the fpm pool overrides `/etc/php.d` for them.
42
- 2. `005` CVE-2026 stopgap kept; `post_max_size` / `upload_max_filesize` = 50M (8M broke Talos base64 uploads). Deploy guard path is `/var/app/staging`. Installs + enables `cronie`.
41
+ 1. `009_setup_phpini.config` — sets `ProxyServer: apache`; writes `/etc/php.d/application.ini` (cfn-init `files:`); `memory_limit` / `max_execution_time` go in `aws:elasticbeanstalk:container:php:phpini` because the fpm pool overrides `/etc/php.d` for them. Also sets the health check in `aws:elasticbeanstalk:environment:process:default`: `HealthCheckPath: /health/`, `MatcherHTTPCode: 200` (commit `e3490ff`).
42
+ 2. `005` CVE-2026 stopgap kept, writes to `/etc/php.d` directly (commit `df9dd7a`); `post_max_size` / `upload_max_filesize` = 50M (8M broke Talos base64 uploads). Deploy guard path is `/var/app/staging`. Installs + enables `cronie`.
43
43
  3. `006_mount-s3fs.config` builds s3fs **1.97** from the pinned GitHub tarball, sha256 checked (mismatch fails the deploy). Needs `fuse3` / `fuse3-devel`; `libcurl-devel` via `dnf install --allowerasing`.
44
44
  4. `.platform/hooks/predeploy/10-mount-s3fs.sh` (identical copy in `.platform/confighooks/predeploy/`) mounts per `ebs/s3fs.<ENVIRONMENT>.json` (env from `get-config`), webapp uid/gid, `iam_role=auto`, cache `/var/cache/s3fs`; then a write/read/delete test as webapp, else `exit 1`. Also creates the cache dir (mkdir/chown).
45
45
  5. `020_setup_git_libraries.config` (bash, `exit 1` on failure) clones `library` and `dbchanges` `_production`. Token = EB env property `GITHUB_TOKEN` read with `get-config`, passed via `GIT_ASKPASS` — never in the URL or log.
@@ -48,12 +48,18 @@ TRUE-83054 moved `api` off EB "PHP 7.2 / 64bit Amazon Linux 2.8.9" (AL1, Apache
48
48
  8. `.platform/hooks/postdeploy/01-restart-php-fpm.sh` restarts php-fpm and checks the live ini values.
49
49
  9. Apache conf in `.platform/httpd/conf.d/`: `enforce_https.conf` (from api2), `timeouts.conf` (`Timeout` / `ProxyTimeout` 900 — ALB `IdleTimeout` must also be 900), `hostlog.conf`.
50
50
  10. Root `.htaccess`: `FilesMatch` deny for `config.*`, `.ini/.env/.json/.sh`, dotfiles, `test.php`; `manual/.htaccess` = `Require all denied`.
51
+ 11. Load balancer (new env had only HTTP:80 and an LB security group open on 80): add an HTTPS:443 listener, policy `ELBSecurityPolicy-TLS13-1-2-2021-06`, ACM certs `*.agilantsolutions.com` (default) + `*.togatechnology.com` (SNI) in us-east-1 / 654654170868; open 443 on the LB security group; ALB `idle_timeout` 900. Plain HTTP gets a 302 to https from `enforce_https.conf` (ALB sends `X-Forwarded-Proto: http`).
52
+ 12. Cutover: old and new env are in different accounts and regions, so EB "Swap environment URLs" is impossible. Before DNS, test with `curl --resolve <host>:443:<ALB IP> https://<host>/health/`. Then Route 53 alias UPSERT to the new ALB (alias zone `Z35SXDOTRQ7X7K`): `api.agilantsolutions.com` (zone in legacy account) and `api.togatechnology.com` (zone in new account). Rollback = alias both back to `agilant-api-prod.us-west-2.elasticbeanstalk.com` (zone `Z38NKT9BP95V3O`).
51
53
 
52
54
  **Cross-account `asifiles`** (bucket in us-west-2, legacy account 502614707982): bucket policy allows role `arn:aws:iam::654654170868:role/ElasticBeanstalk-EC2-Instance-Profile` ListBucket / GetBucketLocation + Get/Put/Delete/PutObjectAcl; that shared role has inline policy `asifiles-readwrite`. Bucket has no ownership controls, so `public-read` ACLs work.
53
55
 
54
56
  ## Gotchas
55
57
 
56
58
  - **`php_value` in `.htaccess` = "Invalid command" 500 under php-fpm.** Move each value to `application.ini` or the `phpini` option settings.
59
+ - **`php --ini` returns nothing inside cfn-init `container_commands` on AL2023.** Parsing it for the scan folder gave "PHP scan folder not found" and failed the deploy (`005`). Write to `/etc/php.d` directly. Same trap in any deploy script that parses `php --ini`.
60
+ - **EB default health check path `/` → env Severe.** On api `/` is a folder with no index → Apache AH01276 403 → `Target.ResponseCodeMismatch`. Use `/health/` (200 from `api.php`), as the old env did.
61
+ - **GET calls carry `securityToken` as a JSON body** with `content-type: application/x-www-form-urlencoded` (e.g. WinTuner `GET /order/{n}`). Postman does not send a GET body by default, and PowerShell 5.1 strips `\"` inside a double-quoted `curl.exe` argument — both give 405 "Method not allowed" (no `securityToken` seen, `api.php:3349`). In PowerShell use single quotes with `\"` inside.
62
+ - **Rebuild a failing call from `Logs.API`** (legacy Logs DB): every inbound call is stored with method, endpoint, `requestHeaders`, `requestPayload`.
57
63
  - **AL1 hooks are dead on AL2023.** Anything under `/opt/elasticbeanstalk/hooks/appdeploy/...` (s3fs mount, cache folder, cron, tests) never runs. Use `.platform/hooks/*` (+ `confighooks` copy for config-only deploys).
58
64
  - **s3fs 1.84 cannot read the instance role over IMDSv2** (AL2023 EB sets `DisableIMDSv1=true`) → mount fails. Use 1.97 (1.96+ needs fuse3). `nonempty` is ignored on fuse3. Keep the cache off `/tmp` (tmpfs on AL2023).
59
65
  - **`libcurl-devel` conflicts with preinstalled `libcurl-minimal`.** Use `dnf install --allowerasing`; `dnf swap` fails on rerun.
@@ -64,4 +70,5 @@ TRUE-83054 moved `api` off EB "PHP 7.2 / 64bit Amazon Linux 2.8.9" (AL1, Apache
64
70
  - **Security, open (values not recorded):** `config.prod.ini` in the repo holds DB / SMTP / cert passwords (now blocked from the web by the deny rule; still need rotating); an old GitHub token is in git history (`ebs/git.json`, also tools `020`); `test.php` has a hardcoded client token. Developer will rotate.
65
71
 
66
72
  ## Change history
73
+ - 2026-10-22 — Live deploy: `/etc/php.d` direct write, `/health/` health check, HTTPS:443 listener, Route 53 cutover + rollback, GET-body / `Logs.API` debugging (TRUE-83054) (jcardinal)
67
74
  - 2026-10-22 — Created: AL1 → PHP 8.5 / AL2023 with Apache proxy, new prod account env + pipeline, s3fs 1.97 over IMDSv2, cross-account `asifiles` (TRUE-83054) (jcardinal)
@@ -6,7 +6,7 @@ project: Library
6
6
  client: shared
7
7
  type: architecture
8
8
  status: active
9
- updated: 2026-09-17
9
+ updated: 2026-10-22
10
10
  owners: [jcardinal]
11
11
  files:
12
12
  - library/_.php
@@ -19,7 +19,7 @@ The 1.0 `App_` framework core: bootstrap/autoloader, the `app/` (`App_`) + `brow
19
19
 
20
20
  ## Summary
21
21
 
22
- `library` is the shared repo for **all 1.0 (legacy) applications** — the `App_` framework. It provides every server-side PHP asset those apps consume: server-side classes, vendored third-party packages, and the bootstrap/autoloader. Target PHP 7.2+, compatible through 8.1. Each app `require`s `library/_.php` to bootstrap.
22
+ `library` is the shared repo for **all 1.0 (legacy) applications** — the `App_` framework. It provides every server-side PHP asset those apps consume: server-side classes, vendored third-party packages, and the bootstrap/autoloader. Target PHP 7.2+; runs on PHP 8.5 (Tools, Walmart Activate, api) — see [PHP 8.5 compatibility](features/php-8-5-runtime-compatibility.md). Each app `require`s `library/_.php` to bootstrap.
23
23
 
24
24
  **Critical rules:** All folder/file names under `app/` and `browser/` are **lowercase** (autoloader lowercases before lookup). **No front-end assets here** — JS/CSS belong in the `resources/` repo. **No Composer in consuming apps** — add packages directly to `library/`. Remove all `debugVar()` calls before merging. A class that only makes HTTP calls to an external/cross-framework API belongs in `app/api/` and should **extend nothing** (see the class-placement feature doc).
25
25
 
@@ -109,6 +109,8 @@ The 1.0 error handler **terminates** on a PHP deprecation notice (`App_Error::ha
109
109
 
110
110
  - When porting or running 1.0 code on PHP 8.x, **audit for deprecated-in-8.x calls** in every reachable path before deploy.
111
111
  - Known offender: **`curl_close()`** — deprecated as of PHP 8.5, a no-op since PHP 8.0. Remove all `curl_close()` calls; the cURL handle closes automatically. (Design Demo Admin incident — see framework-rules-cases.md.)
112
+ - In `library`, guard deprecated calls by version (`PHP_VERSION_ID`) and use 7.1-valid syntax (`?string $x = null`) — other 1.0 apps still run PHP 7.2. Fixed/open list: [PHP 8.5 compatibility](../apps/library/features/php-8-5-runtime-compatibility.md).
113
+ - Never pass `null` to internal string functions (`trim`, `base64_decode`, `stripos` — deprecated 8.1). Cast `(string)` first; DB/JSON fields can be null.
112
114
  - Do not suppress the deprecation with `@` (see coding-style rules) — remove/replace the deprecated call.
113
115
 
114
116
  ## Error handling in controllers
@@ -18,7 +18,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
18
18
  - **store** (Store) — 4 doc(s) → [1.0/apps/store/INDEX.md](1.0/apps/store/INDEX.md)
19
19
  - **tools** (Tools) — 25 doc(s) → [1.0/apps/tools/INDEX.md](1.0/apps/tools/INDEX.md)
20
20
  - **vision** (Vision) — 0 doc(s) → [1.0/apps/vision/INDEX.md](1.0/apps/vision/INDEX.md)
21
- - **api** (API 1.0) — 2 doc(s) → [1.0/apps/api/INDEX.md](1.0/apps/api/INDEX.md)
21
+ - **api** (API 1.0) — 3 doc(s) → [1.0/apps/api/INDEX.md](1.0/apps/api/INDEX.md)
22
22
 
23
23
  ## 2.0 framework
24
24
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toga-ai",
3
- "version": "1.0.1113",
3
+ "version": "1.0.1114",
4
4
  "description": "TOGA Technology Team Claude Knowledge System — shared AI coding harness with skills, knowledge base CLI, and project installer for Claude Code.",
5
5
  "keywords": [
6
6
  "claude",