# Module: gmarketapi (`b2g_gmarketapi/`)
Purpose: backend for the gMarket green-marketplace SPA — supplier products/services, business sources, factories, supplier certification forms, landing stats, NIBE Bridge sync. Owner: Sanjay.
Entry points: `web/index.php` → `config/web.php`; modules `bizsource`, `certificate`, `factory`, `masterdata`, `suppliercert`, `products`, `services`, `landing`, `network` (`modules/*/controllers`, heavy logic in `modules/*/components/*Service|Manager|Fetch.php`, `services/SuppCertFormService.php`); all API controllers extend `components/BaseApiController.php`.
Data: `bgi_b2g_gmarket_{dev|prod}` (`config/db-*.php`) — key tables: `memcompproddtls_tbl`, `memcompservicedtls_tbl`, `memcompbussrcdtls_tbl`, `memcompprodbussrcmap_tbl`, `supportcollateraldtls_tbl`, `memcompfctydtls_tbl`, `suppcertform*tmp_tbl`. `usermst_tbl`/company data live in `bgi_b2g_reg_*` and lookups in `bgi_b2g_master_*` (`regDbName`/`masterDbName` params) — reached mostly via sibling HTTP calls, not this connection.
Calls: micro (`MICRO_BASE_URL` → `b2gMicroBaseUrl`, `BSGPACK_BASE_URL` → `bsgPackBaseUrl`), profilemgmt (`PROFILEMGMT_BASE_URL`), usermgmt (`USERMGMT_BASE_URL`), filemst (`FILEMST_BASE_URL`, embedded in browser "View Documents" links); NIBE Bridge external API via `components/BridgeApiClient.php` + `components/bridge/` (`BRIDGE_BASE_URL`, `BRIDGE_PROJECT_ID[_INT]`). Overrides merged in `config/params-local.php`.
Env selection: `APP_ENV` first (local/dev/demo/uat/prod), else hostname (`demo.blu2green.earth`→demo, `blu2green.earth`→prod, else local) — see `config/web.php`; loads `params-{env}.php` + `db-{env}.php`.
Invariants:
- Every API controller extends `BaseApiController` (JSON format + `checkAuth()` 401 gate); OPTIONS preflight must stay unauthenticated.
- `*_BASE_URL` values carry no trailing slash; callers append the route.
- Outbound curl must set `CURLOPT_TIMEOUT` (BridgeApiClient uses `bridgeHttpTimeout`/`bridgeConnectTimeout`); `ci/curl-timeout-check.py` enforces it.
Gotchas:
- Auth is weak: any JWT-shaped Bearer (`x.y.z`) is accepted on presence only (no signature check), as is a base64 of the shared `encryptionKey` param via header/query/body.
- Only `params-/db-{local,demo,prod}.php` exist; root `docker-compose.yml` sets `APP_ENV: dev`, which would require a missing `params-dev.php` (verify local boot).
- Log stderr mirror is still a `FileTarget` on `/proc/self/fd/2` — the pattern root CLAUDE.md calls a known bug (verify whether the `StderrLogTarget` fix has landed here).
- `vendor/` is not committed; the Dockerfile `deps` stage runs `composer install --no-scripts`. Bind-mounted local runs need `vendor/` installed separately (verify).
- Bridge access tokens sit in Yii `FileCache` and push logs in `runtime/logs/bridge_api_push_*.log` — per-container, lost on redeploy, not shipped to CloudWatch.
Prod debugging: CloudWatch `/ecs/b2g-prod/gmarketapi` (demo: `/ecs/b2g-demo/gmarketapi`); health `GET /healthz` on :80; ECS service `gmarketapi`, task family `b2g-gmarketapi` / `b2g-demo-gmarketapi`. Runbooks: `docs/runbooks/`.
