AGENTS.md

Overview

This document describes how to configure and utilize AI coding assistants (e.g. OpenAI Codex-based agents) to aid development of the TAF ERP project. It covers the project’s tech stack and architecture, so the AI agents can produce code that fits our conventions. By informing the agents of the stack (PHP, JavaScript libraries, CSS framework, database, MVC structure), we can get more relevant suggestions. All developers (human or AI) should follow the MVC patterns and file placements outlined here to maintain consistency.



Tech Stack for TAF ERP

Backend Language: PHP (e.g., PHP 8.x). The project is a server-rendered web application using PHP for all backend logic.

Database: PostgreSQL for relational data storage. Agents should generate SQL queries compatible with PostgreSQL syntax. Use standard Postgres features for transactional support and constraints.

Server/Hosting: Typical LAPP stack (Linux, Apache/Nginx, PostgreSQL, PHP). The code runs on a web server and serves REST type API endpoints with json data. It can also serve html but for templating only

Frontend: Standard web technologies (HTML5, CSS3, JavaScript ES6). The application gets the data from the server side, and rendered on fronend with Javascript for interactivity


Primary JS Libraries (jsLibs): The project uses jQuery. Optional: Chart.js and d3.js for reports, Leaflet or Google Maps API for GIS.

CSS Framework (cssLibs): Tailwind css and DaisyUI (read DaisyUI.AGENTS.md file in this folder)
Database schema guidelines are described in sql/AGENTS.md

Schema: api/schema.php generates the IndexedDB stores dynamically using the `tenant_tables` records. No manual DB_VERSION bump is required.

Other Tools:

Ajax (via jQuery)

FontAwesome or similar icons

PHPMailer for emails using SMTP

PHPUnit for testing

Project Architecture & MVC Pattern

Models (models/)

Each model is a PHP class for a logical entity or database table (e.g., Users.php).

Should use prepared statements with mysqli or PDO.

Functions: CRUD (getById, save, delete, etc.), and business logic.

Controllers (controllers/)

Handle HTTP requests and call appropriate models. Most tables now sync through
`/api/sync` using `LocalSyncManager` so bespoke controllers are rarely needed.
Only create a new controller when specifically requested or when complex
business logic cannot be handled by the generic sync endpoints.

Controllers follow the format: `ModuleNameController.php`.

Use `GenericController` as a base where applicable to reuse CRUD operations.

Responsibilities: validate input, check permissions, call model methods, load
views.

Use DaisyUI for tables, forms, and layouts.

Routing

Handled via api/router.php front controller or .htaccess URL rewriting.

Pattern-based mapping, e.g., `users/list` maps to `UsersController::list()`.
New modules register through the module registry (backed by the `modules`
table), so `Dashboard.php` and `FrontEnd/js/router.js` rarely need manual
entries. Only touch the router for legacy modules that cannot yet be migrated.

API Layer (optional)

Can use api/ or controller methods returning JSON.

Use dedicated API endpoints for mobile or integrations.

Secure with token or JWT.

Utilities

Central helpers (auth, validation, uploads) go in shared classes.

Check for shared logic in GenericController.php before creating new methods.

Sync & Search Platform

- Always retrieve the singleton via `services/syncservice` (`getManager`,
  `registerPolicy`, `requestData`, `requestDataSource`, `onSyncUpdate`) instead
  of creating `LocalSyncManager` instances directly.
- Policies govern cadence, retention, retry behaviour, offline queuing and
  search metadata; adjust behaviour through policy overrides instead of
  hard-coded timers.
- Use the shared event bus (`services/eventBus`) to listen for `sync:*`,
  `queue:*`, `transport:*`, and `search:*` notifications when wiring UI
  feedback or telemetry.
- New or refactored search flows must call `services/searchHelper` so local and
  remote results stay in sync with policy-defined indexes and events.
- Wrap disruptive changes behind `syncPoliciesEnabled` when needed so new
  policies can run in shadow mode.
- Before touching a module, consult
  `docs/frontend/LocalSyncManagerModuleStatus.md` to confirm whether it already
  uses the singleton workflow.

Module Platform

- Store module definitions in the `modules` table; use ModuleBuilder to author
  configs and ModuleLoader to resolve them—do not add new `ui_modals`
  definitions.
- Declare module data sources so ModuleLoader can trigger progressive hydration
  (skeletons, incremental renders, pagination) without bespoke fetch chains.
- Bind actions through schema `data-action` or controller helpers to keep
  events scoped to the module instead of attaching handlers to `window`.
- Reuse ModalBuilder's component registry (grids, computed state, analytics
  widgets) before creating custom markup.
- Use `requestDataSource`/`requestData` to hydrate views so policies and
  auto-refresh logic remain consistent across modules.
- Avoid introducing bespoke controllers or router entries for new modules;
  leverage the module registry and ModuleLoader integration instead.
- Apply the tenant→org terminology updates across JS/PHP when touching
  relevant areas, including IndexedDB store names and analytics.

UI & Forms

- Share form element type constants between FormBuilder, FormUtils, and
  ModalBuilder to avoid hard-coded strings.
- Build UI with DaisyUI/Tailwind primitives and ensure layouts meet WCAG
  requirements (focus management, ARIA labelling, keyboard navigation).
- Adopt the lightweight file upload widget and preview helpers for attachments;
  route heavy workflows through the Document Management Service.
- Use the action guard helper when wiring buttons or forms to prevent double
  submits and race conditions.
- Surface offline and diagnostic messaging via the event bus-driven helpers
  rather than bespoke banners.

Security, Auth & API Usage

- Authenticate REST, sync, and websocket routes with JWT; refresh tokens on
  login and keep them in secure storage (IndexedDB/session).
- Include JWT validation, jittered retries, and fallback polling when managing
  websocket lifecycles.
- Generate endpoints through the shared `services/api` helper so base-URL
  overrides, multi-org routing, and tests stay consistent.
- Ensure Document Management Service endpoints and queued uploads reuse the
  JWT middleware and emit standard error payloads.

Coding Style & Best Practices

Follow PSR-12 coding style.

Document functions with PHPDoc.

Security: Escape output, use prepared statements.

Transactions: Use BEGIN; COMMIT; for multi-step DB updates.
.

### General Requirements
- All user functionality must be accessible from `FrontEnd/Dashboard.html`.
- Table labels, buttons and forms must be configurable per tenant, department or location.
- Provide unit tests for all PHP and JS. JS code should be testable end-to-end including API requests.

Agents for Frontend Tasks

Use jQuery for DOM/AJAX:

$('#categorySelect').on('change', function() {
    $.get('/inventory/productsByCategory', { id: $(this).val() }, function(data) {
        // populate select
    });
});

Minimize reliance on React/Angular/Vue (not used).

Testing


Use PHPUnit for PHP and Jest for JavaScript. Run `test_setup.sh` to provision PostgreSQL and recreate the schema, then execute the relevant test suites manually before committing.

- Add or update Jest suites when introducing search helper usage so local and
  remote result handling is covered.
- Exercise progressive hydration, event bus flows, and offline/online
  transitions using the IndexedDB/fetch/websocket mocks in `tests/js`.
- Extend PHPUnit coverage for JWT middleware, modules API endpoints, and data
  migration scripts whenever those areas change.


Component Docs
--------------
- docs/frontend/DataLoader.md explains the DataLoader helper used by front-end modules.
- docs/FormBuilder.md describes the form builder and metadata tables.
- docs/WorkflowEngine.md covers workflow configuration and triggers.
- docs/frontend/ModalBuilder.md outlines the UI modal builder pattern used for dynamic modules.

ModalBuilder Guidelines
-----------------------
* Use `ModalBuilder` for all new modal-based interfaces; definitions are stored in the `modules` table and resolved by ModuleLoader.
* Author configs through ModuleBuilder and include data sources, state/actions, layout presets, and scoped events instead of bespoke JavaScript.
* Render modules with ModuleLoader + ModalBuilder (full modal, body-only, or targeted regions) so progressive hydration and cleanup hooks fire automatically.
* Table row actions should rely on the shared helpers `selectRecord` and `openSelectedDetail` rather than module-specific DOM lookups.
* When modifying the UI builder or adding new modules, run `./test_setup.sh` and execute both the PHP (`phpunit`) and JavaScript (`npm test`) suites before committing.
* Table views are deprecated; listing logic belongs in models and should be rendered via `DataLoader` without new `table_views` entries.
* Modules must sync data through `LocalSyncManager` and `/api/sync` unless a documented legacy API is explicitly required.
* For legacy `ui_modals` entries, migrate them to the `modules` table at the first opportunity—new work should not create additional legacy records.

Summary

Codex agents must:

Respect MVC separation

Match file/folder naming conventions

Use the declared tech stack and libraries (no Laravel)

Be consistent with existing examples (like UsersController.php)

Document any assumptions or required follow-ups using // TODO:

This setup ensures agents produce drop-in-compatible code that accelerates development without introducing architectural drift.
