toga-ai 1.0.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/.claude/settings.json +119 -0
- package/.claude-plugin/marketplace.json +87 -0
- package/.claude-plugin/plugin.json +22 -0
- package/CLAUDE.md +161 -0
- package/README.md +72 -0
- package/agents/framework-pattern-checker.md +67 -0
- package/agents/harness-optimizer.md +102 -0
- package/agents/knowledge-writer.md +62 -0
- package/agents/php-build-resolver.md +51 -0
- package/agents/php-reviewer.md +51 -0
- package/agents/planner.md +88 -0
- package/agents/session-capture.md +101 -0
- package/agents/sql-reviewer.md +67 -0
- package/contexts/dev.md +43 -0
- package/contexts/research.md +49 -0
- package/contexts/review.md +37 -0
- package/knowledge/1.0/apps/library/INDEX.md +5 -0
- package/knowledge/1.0/apps/library/architecture.md +105 -0
- package/knowledge/1.0/apps/worker/INDEX.md +5 -0
- package/knowledge/1.0/apps/worker/architecture.md +223 -0
- package/knowledge/1.0/standards/backend-php.md +450 -0
- package/knowledge/2.0/apps/_underscore/INDEX.md +6 -0
- package/knowledge/2.0/apps/_underscore/architecture.md +183 -0
- package/knowledge/2.0/apps/_underscore/features/recursive-item-fulfillments.md +111 -0
- package/knowledge/2.0/apps/api2/INDEX.md +5 -0
- package/knowledge/2.0/apps/api2/architecture.md +162 -0
- package/knowledge/2.0/apps/worker2/INDEX.md +6 -0
- package/knowledge/2.0/apps/worker2/architecture.md +127 -0
- package/knowledge/2.0/apps/worker2/features/creating-worker-actions.md +135 -0
- package/knowledge/2.0/standards/backend-php.md +710 -0
- package/knowledge/CONVENTIONS.md +117 -0
- package/knowledge/INDEX.md +19 -0
- package/knowledge/clients/.gitkeep +0 -0
- package/knowledge/registry.json +7 -0
- package/knowledge.js +384 -0
- package/mcp-configs/README.md +72 -0
- package/mcp-configs/mcp-servers.json +23 -0
- package/package.json +50 -0
- package/rules/README.md +53 -0
- package/rules/common/coding-style.md +123 -0
- package/rules/common/git-workflow.md +72 -0
- package/rules/common/security.md +118 -0
- package/rules/common/testing.md +74 -0
- package/rules/php/app-framework.md +104 -0
- package/rules/php/underscore-framework.md +111 -0
- package/scripts/harness.js +605 -0
- package/scripts/hooks/evaluate-session.js +55 -0
- package/scripts/hooks/post-edit-validate.js +102 -0
- package/scripts/hooks/session-end.js +13 -0
- package/scripts/hooks/session-start.js +57 -0
- package/scripts/install.js +611 -0
- package/scripts/pre-commit +46 -0
- package/skills/capture/SKILL.md +294 -0
- package/skills/code-review/SKILL.md +140 -0
- package/skills/create-elastic-beanstalk/SKILL.md +217 -0
- package/skills/harness-audit/SKILL.md +152 -0
- package/skills/kickoff/SKILL.md +151 -0
- package/skills/php-patterns/SKILL.md +296 -0
- package/skills/session-resume/SKILL.md +156 -0
- package/skills/session-save/SKILL.md +158 -0
- package/skills/sync-team-skills/SKILL.md +87 -0
- package/sync-skills.js +71 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# worker (Worker) — 1.0 knowledge
|
|
2
|
+
|
|
3
|
+
| Doc | Summary | Files |
|
|
4
|
+
|-----|---------|-------|
|
|
5
|
+
| [Worker (1.0 Framework) Architecture](architecture.md) | `worker` is the legacy (**1.0** `App_` framework) **background-job tier**. | worker/index.php, worker/_/app/framework.php, worker/crons/, worker/schedules/, worker/ebs/cron.worker.php, worker/.ebextensions/035_cron.worker.config |
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Worker (1.0 Framework) Architecture
|
|
3
|
+
framework: "1.0"
|
|
4
|
+
repo: worker
|
|
5
|
+
project: Worker
|
|
6
|
+
client: shared
|
|
7
|
+
type: architecture
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-06-08
|
|
10
|
+
owners: [jcardinal]
|
|
11
|
+
files:
|
|
12
|
+
- worker/index.php
|
|
13
|
+
- worker/_/app/framework.php
|
|
14
|
+
- worker/crons/
|
|
15
|
+
- worker/schedules/
|
|
16
|
+
- worker/ebs/cron.worker.php
|
|
17
|
+
- worker/.ebextensions/035_cron.worker.config
|
|
18
|
+
related:
|
|
19
|
+
- ../library/architecture.md
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Summary
|
|
23
|
+
|
|
24
|
+
`worker` is the legacy (**1.0** `App_` framework) **background-job tier**. It is a single
|
|
25
|
+
codebase of ~550 standalone PHP CRON scripts (under `crons/`) that handle everything the web
|
|
26
|
+
apps must not do inline: notifications/reports, database backups, third-party syncs (NetSuite,
|
|
27
|
+
EDI partners, NYC DOE, ManageEngine, Syncro…), cloud-infrastructure maintenance, and the
|
|
28
|
+
TOGa / TOGaDesk / TOGa-2 client integrations.
|
|
29
|
+
|
|
30
|
+
In production the tier is **one Elastic Beanstalk environment running 7 instances**, each of
|
|
31
|
+
which **self-elects a distinct role** (`notification`, `database`, `infrastructure`, `toga`,
|
|
32
|
+
`togadesk`, `sync`, `catalog`) and runs only that role's slice of the schedule. Platform:
|
|
33
|
+
**PHP 7.2 running on 64-bit Amazon Linux / 2.8.8**.
|
|
34
|
+
|
|
35
|
+
> This repo is the "legacy worker" referred to in the 1.0 back-end standard's
|
|
36
|
+
> *Asynchronous / Background Processing* note — long-running work is handed off here rather
|
|
37
|
+
> than run inside a web request. It builds on the `library` core (see
|
|
38
|
+
> [Library architecture](../library/architecture.md)).
|
|
39
|
+
|
|
40
|
+
## How a job becomes a cron (the dispatch pipeline)
|
|
41
|
+
|
|
42
|
+
There is **no in-process scheduler**. Jobs are plain PHP files invoked by the OS `crontab`,
|
|
43
|
+
which is generated at deploy time:
|
|
44
|
+
|
|
45
|
+
1. **`schedules/cron.<env>.json`** declares the jobs for an environment. Each entry is
|
|
46
|
+
`{ active, name, schedule (5-field cron expr), cron | command | url }`:
|
|
47
|
+
- `cron` → `php /var/www/html/crons/<path>` (the common case)
|
|
48
|
+
- `command` → run the raw shell command (e.g. `apachectl -k graceful`)
|
|
49
|
+
- `url` → `wget http://localhost<url>`
|
|
50
|
+
- `active: 0` disables the entry without deleting it.
|
|
51
|
+
2. **`.ebextensions/035_cron.worker.config`** runs `ebs/cron.worker.php` as an EB
|
|
52
|
+
`container_command` on every deploy.
|
|
53
|
+
3. **`ebs/cron.worker.php`** reads the `ENVIRONMENT` env var, loads `cron.<env>.json`, and for
|
|
54
|
+
the `worker` env *also* loads the **role-specific** `cron.worker.<role>.json` (see role
|
|
55
|
+
election below). It writes the assembled crontab into the EB appdeploy enact hook
|
|
56
|
+
`/opt/elasticbeanstalk/hooks/appdeploy/enact/01_cron.sh`, which installs it via
|
|
57
|
+
`crontab cronjobs`.
|
|
58
|
+
4. The OS cron daemon then runs each `php /var/www/html/crons/<path>` on its schedule.
|
|
59
|
+
|
|
60
|
+
So **to add/modify a scheduled job you edit a `schedules/*.json` file and redeploy** — the cron
|
|
61
|
+
path is relative to `crons/`. Editing the `.php` alone does nothing until it is referenced by a
|
|
62
|
+
schedule entry.
|
|
63
|
+
|
|
64
|
+
### Schedule files
|
|
65
|
+
|
|
66
|
+
| File | Purpose |
|
|
67
|
+
|---|---|
|
|
68
|
+
| `cron.worker.json` | **Base — runs on every production worker** regardless of role: `apachectl -k graceful` (closes DB connections) + `worker/worker_heartbeat.php` (every minute). |
|
|
69
|
+
| `cron.worker.<role>.json` | Per-role job set. The 7 roles: `notification` (~88), `sync` (~96), `toga` (8), `togadesk` (14), `infrastructure` (12), `database` (3), `catalog` (2). |
|
|
70
|
+
| `cron.{alpha,beta,demo,hotfix,sprint,stage,ui}.json` | Non-prod environments — each runs the *entire* job set on a single box (no role splitting). |
|
|
71
|
+
|
|
72
|
+
## Production topology: 7 self-electing workers
|
|
73
|
+
|
|
74
|
+
The 7 production instances share one image; **role assignment is dynamic, not baked in.** This
|
|
75
|
+
is the most important and least obvious part of the architecture.
|
|
76
|
+
|
|
77
|
+
- The roster lives in DB table **`Workers`** (`workerInstanceId`, `workerName`, `dtHeartbeat`)
|
|
78
|
+
in the **`Vision_Log`** database (config group `db_log`).
|
|
79
|
+
- The canonical role list is **`App_Worker::$desiredWorkers`** (in `library`): `notification`,
|
|
80
|
+
`database`, `infrastructure`, `toga`, `togadesk`, `sync`, `catalog`. (`ebs/cron.worker.php`
|
|
81
|
+
carries its own near-duplicate copy of this list — keep the two in sync.)
|
|
82
|
+
- **Role election (at deploy, in `ebs/cron.worker.php`):** the script connects to `Vision_Log`,
|
|
83
|
+
reads `Workers`, computes which roles are not yet claimed, and assigns this instance (keyed by
|
|
84
|
+
its EC2 instance-id) the **first unclaimed role** — `INSERT`/`UPDATE`-ing its `Workers` row.
|
|
85
|
+
It then appends that role's `cron.worker.<role>.json` to the crontab.
|
|
86
|
+
- **Heartbeat / self-healing (`crons/worker/worker_heartbeat.php`, every minute on all 7):**
|
|
87
|
+
- Updates this instance's `dtHeartbeat = NOW()`.
|
|
88
|
+
- First time an instance is seen, tags the EC2 instance `Worker=<ROLE>-WORKER`, **associates
|
|
89
|
+
the role's dedicated Elastic IP** (`App_Worker::$associateWorkerWithElasticIpAllocationId`),
|
|
90
|
+
and emails ops that the role was instated.
|
|
91
|
+
- If any worker's heartbeat is stale (> **270 s** in the heartbeat; the deploy script uses a
|
|
92
|
+
separate **7-minute** cutoff), it **terminates that EC2 instance** via the AWS API and
|
|
93
|
+
deletes its `Workers` row. EB replaces the instance, which re-runs deploy, finds the now-open
|
|
94
|
+
role, and re-claims it → automatic self-recovery. Each instance staggers with a random
|
|
95
|
+
`sleep(rand(1,50))` to avoid races.
|
|
96
|
+
- **`App_Worker::getWorkerName()`** returns the current instance's role; helpers
|
|
97
|
+
`isPrimaryWorker()` / `isPrimaryDbWorker()` (currently commented out) gated "primary-only"
|
|
98
|
+
jobs in an older model.
|
|
99
|
+
|
|
100
|
+
> Net effect: roles are a **claim-the-first-free-slot pool**, and a dead worker's role is
|
|
101
|
+
> reclaimed by its replacement within minutes. There is no static instance→role mapping to edit.
|
|
102
|
+
|
|
103
|
+
## Anatomy of a cron script
|
|
104
|
+
|
|
105
|
+
Every script is self-contained and follows this boilerplate:
|
|
106
|
+
|
|
107
|
+
```php
|
|
108
|
+
<?php
|
|
109
|
+
require_once('_.php'); // library bootstrap (see below)
|
|
110
|
+
App_Framework_Worker::initialize(); // worker framework init
|
|
111
|
+
App_Framework::cronInitialization($timeLimitSeconds); // lock + logging + time limit
|
|
112
|
+
|
|
113
|
+
// ... the job's work, written against App_Model / App_Database / App_Api / App_Email ...
|
|
114
|
+
|
|
115
|
+
App_Framework::cronFinished(); // log completion
|
|
116
|
+
App_Database::closeConnections();
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
- **`App_Framework_Worker::initialize()`** (`_/app/framework.php`) extends the library
|
|
120
|
+
`App_Framework`, disables sessions, registers the vendored libraries this tier needs
|
|
121
|
+
(PHPExcel reader/writer, NetSuite toolkit, phpseclib, php-imap2), and initializes **Sentry**
|
|
122
|
+
(project `worker1`, environment = the EB env).
|
|
123
|
+
- **`App_Framework::cronInitialization($timeLimitSeconds = 7200, $okayToPerformOnReadCluster =
|
|
124
|
+
false, $exitIfProcessAlreadyRunning = true)`** (in `library`):
|
|
125
|
+
- **Overlap guard** — `exitIfProcessRunning()` scans `ps -ef` for another PHP process running
|
|
126
|
+
the same script file and exits early if found (prevents a slow job from stacking on its next
|
|
127
|
+
tick). This is a process-table lock, not a file lock.
|
|
128
|
+
- `set_time_limit()`, `date_default_timezone_set('America/Chicago')`, optional read-cluster
|
|
129
|
+
routing.
|
|
130
|
+
- Logs a `CRON_START` row to the `Log` table (`db_log`) and a row to `CronJobExecutions`
|
|
131
|
+
(`db_common`) for monitoring.
|
|
132
|
+
- **`cronFinished()`** logs completion; **`App_Database::closeConnections()`** must be called so
|
|
133
|
+
the connection is released before the next tick.
|
|
134
|
+
- **Sentry cron monitors (newer jobs):** wrap the body with
|
|
135
|
+
`if (App_Framework::isProcessRunning()) exit;` then `App_Worker::checkIn('<monitor-slug>')`
|
|
136
|
+
… work … `App_Worker::checkOut()`. A missing `checkOut()` makes Sentry flag the run as missed.
|
|
137
|
+
|
|
138
|
+
## Directory layout
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
worker/
|
|
142
|
+
├── index.php # thin web entry: require _.php; App_Framework_Worker::{initialize,renderIndex}
|
|
143
|
+
├── _/app/ # APPROOT marker + app-level App_ overrides
|
|
144
|
+
│ ├── framework.php # App_Framework_Worker (extends library App_Framework)
|
|
145
|
+
│ └── frameworkindex.php # App_FrameworkIndex_Worker (renders the minimal web index)
|
|
146
|
+
├── crons/ # ~553 standalone job scripts, grouped by domain (below)
|
|
147
|
+
├── schedules/ # *.json crontab definitions (per env + per role)
|
|
148
|
+
├── mvc/ # minimal web routes (get / login / logout / 404) — worker has a thin web face
|
|
149
|
+
├── common/ # header.php / footer.php for the web face
|
|
150
|
+
├── ebs/ # deploy-time provisioning scripts (run by .ebextensions)
|
|
151
|
+
├── .ebextensions/ # EB platform config (apache, https, imap, s3fs, ldap, redis, composer, git, cron)
|
|
152
|
+
├── config.<env>.ini # per-environment DB connections + settings (one per dev/stage/prod box)
|
|
153
|
+
├── composer.json/vendor/ # Composer deps (Sentry, AWS SDK, …) — note: 1.0 apps normally vendor via library
|
|
154
|
+
└── assets/
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`_.php` itself is **not committed** — it is the `library` framework bootstrap, made available on
|
|
158
|
+
the box at deploy (library is git-cloned to `/var/www/library`; the `_/` folder is the
|
|
159
|
+
`__APPROOT__` marker the autoloader walks up to find). App-level classes named `App_*` resolve to
|
|
160
|
+
`_/app/...`, shadowing the library copies (standard 1.0 autoloader behavior).
|
|
161
|
+
|
|
162
|
+
### `crons/` domains
|
|
163
|
+
|
|
164
|
+
| Folder | ~Files | What it does |
|
|
165
|
+
|---|---:|---|
|
|
166
|
+
| `notifications/` | 115 | Emailed reports, reminders, campaigns, CSAT surveys, daily/weekly/monthly client reports (Office Depot, Walmart, NYC DOE, Canon, Newegg, InComm…). Also `infrastructure/send_emails.php` outbound mail queue + code-commit digests. |
|
|
167
|
+
| `sync/` | 97 | Record syncing & reconciliation: NetSuite, EDI partners (Prudential, Canon, DOE), ManageEngine, Syncro, Active Directory, Staples, tracking-number reconciliation. |
|
|
168
|
+
| `toga2/` | 162 | **TOGa-2 (2.0) client integrations** — per-client subfolders (`compass`, `compasscanada`, `prudential`, `aig`, `rate`, `wje`, `elite`, `startech`, `nychh`, `northwell`, `sap_ariba`, `bankofamerica`, `managelife`, `quad`…), the NetSuite `togasupply` syncs, and `forecast2/` sales/order/opportunity imports. |
|
|
169
|
+
| `toga/` | 23 | Core TOGa (1.0) processors: order processor, Walmart e-comm/B2B, subscription billing, garbage collector, client sync. |
|
|
170
|
+
| `infrastructure/` | 18 | DB cluster failover, AWS GuardDuty auto-terminate, domain documenter, `system_monitors.php`, sprint open/close automation, forecast2 imports. |
|
|
171
|
+
| `vendorinvoiceretrieval/` | 18 | Automated vendor-invoice retrieval. |
|
|
172
|
+
| `catalog/` | 17 | Catalog DB reconciliation (Office Depot inventory imports). |
|
|
173
|
+
| `maintenance/` | 9 | Hourly/daily/weekly maintenance + TOGaDesk ticket archiving. |
|
|
174
|
+
| `togadesk/` | 8 | TOGaDesk helpdesk: inactive-people cleanup, UMA customer/ticket sync, task reminders, repair-order status. |
|
|
175
|
+
| `test_active_directory/` | 5 | AD integration test scripts. |
|
|
176
|
+
| `database/` | 4 | Backups, restores, restore scheduling. |
|
|
177
|
+
| `worker/` | 2 | `worker_heartbeat.php` (the self-healing heartbeat) + helper. |
|
|
178
|
+
| `DOA/` | 75 | **Dead-On-Arrival** — deprecated jobs kept for reference, **not scheduled**. Per the 1.0 standard, do not build on `DOA_`-prefixed code. |
|
|
179
|
+
|
|
180
|
+
## Cross-repo bridges (cloned at deploy via `ebs/git.json`)
|
|
181
|
+
|
|
182
|
+
The worker box is assembled from several repos, not just this one. `ebs/git.json` clones:
|
|
183
|
+
|
|
184
|
+
| Repo | Deployed to | Why |
|
|
185
|
+
|---|---|---|
|
|
186
|
+
| `library` | `/var/www/library` | 1.0 framework core (`_.php`, all `App_*`). |
|
|
187
|
+
| `resources` | `…/resources` | Front-end assets (not used by crons). |
|
|
188
|
+
| `dbchanges` | `/var/www/dbchanges` | DB migration scripts. |
|
|
189
|
+
| `togadesk` | `…/ontrack` | TOGaDesk app — note `cron.worker.togadesk.json` runs `../ontrack/crons/tickets_prod.php` and `monitoring_prod.php` **out of the sibling repo**. |
|
|
190
|
+
| `_underscore` | `/var/www/_underscore` | **2.0 framework core** — present because the `toga2/` client integrations reach into 2.0 (TOGa-2 / TOGaSupply). This is a genuine 1.0↔2.0 bridge living inside a 1.0 app. |
|
|
191
|
+
|
|
192
|
+
## Deploy-time provisioning (`.ebextensions/` → `ebs/`)
|
|
193
|
+
|
|
194
|
+
Container commands set up the box on each deploy: apache tuning, force HTTP→HTTPS, install IMAP,
|
|
195
|
+
**mount S3 via s3fs**, export/cache folders, LDAP, php.ini, Redis, Composer, clone the git
|
|
196
|
+
libraries above, permit library executables, **symbolic links** (`ebs/setup_symbolic_links.php`
|
|
197
|
+
links paths from `links.<env>.json`, e.g. `ontrack/desk/uploads` → an S3-backed folder), run
|
|
198
|
+
`dbchanges`, and finally generate the crontab. `index.php` exists only to give the box a trivial
|
|
199
|
+
web face (`mvc/` GET routes for login/logout/404); the tier's real work is the crons.
|
|
200
|
+
|
|
201
|
+
## Conventions & gotchas
|
|
202
|
+
|
|
203
|
+
- **Schedules are the source of truth for what runs.** A `.php` under `crons/` that no schedule
|
|
204
|
+
references is dormant (and may be `DOA/`). Set `active: 0` to disable without deleting.
|
|
205
|
+
- **All cron paths are relative to `crons/`** except the `../ontrack/...` jobs that run from the
|
|
206
|
+
sibling TOGaDesk repo.
|
|
207
|
+
- **Always call `App_Database::closeConnections()`** at the end; rely on `cronInitialization`'s
|
|
208
|
+
overlap guard rather than rolling your own lock.
|
|
209
|
+
- **Timezone is `America/Chicago`** everywhere; cron expressions are in that zone, but several
|
|
210
|
+
`togadesk/` UMA jobs are commented with their UTC equivalents — read the `name` carefully.
|
|
211
|
+
- **Two stale-worker cutoffs exist** (270 s in the heartbeat, 7 min in the deploy script) and the
|
|
212
|
+
`$desiredWorkers` list is duplicated in `ebs/cron.worker.php` and `App_Worker` — keep them
|
|
213
|
+
aligned when changing roles.
|
|
214
|
+
- **Per-role Elastic IPs** mean a role's outbound IP is stable across instance replacement —
|
|
215
|
+
relevant for partner allow-lists (EDI/SFTP endpoints).
|
|
216
|
+
|
|
217
|
+
## ⚠ Security note — committed secrets
|
|
218
|
+
|
|
219
|
+
Several files contain **live credentials checked into the repo**: AWS access keys
|
|
220
|
+
(`ebs/cron.worker.php`, and in a comment in `crons/worker/worker_heartbeat.php`), GitHub PATs
|
|
221
|
+
(`ebs/git.json`), and a Sentry DSN (`_/app/framework.php`). These should be rotated and moved to
|
|
222
|
+
environment variables / SSM Parameter Store rather than living in source. (Values are
|
|
223
|
+
deliberately not reproduced here.)
|