Link Search Menu Expand Document

AGENTS.md — Puko Framework Knowledge Base

This file is an LLM-friendly technical reference for the Puko Framework, a full-stack PHP framework for Rapid Application Development (RAD). It consolidates how the framework works so agents can write accurate documentation without re-discovering behavior.

  • Framework source: github.com/Velliz/puko (PHP, HMVC)
  • Official docs: https://pukoframework.github.io (this repo, Jekyll)
  • PHP requirement: >= 7.0. Install via composer create-project velliz/puko <project-name>.

1. Architecture (HMVC)

Puko uses the Hierarchical Model-View-Controller (HMVC) pattern.

LayerLocation
Controllerscontroller/ (PSR-4, namespace controller;)
Views (HTML)assets/html/ (organized by language, then route path)
Models (generated wiring)plugins/model/<schema>/
Models (custom logic)model/

Controller types (all PSR-4 namespaced)

Controllers must extend one of three base classes:

ClassPurposeOutput
ViewRenders HTML via the PTE template engineHTML
ServiceJSON APIs (requires ext-json)JSON
ConsoleCLI/background scripts (php cli <route> [arg])stdout

Responses are exposed via the return keyword from a controller function.


2. Routing

Routing is managed exclusively via the Puko Console CLI (php puko routes ...). The generated config/routes.php file is read-only — never edit it manually.

php puko routes <clause> add <rest_style_urls>
php puko routes <clause> update <url>
php puko routes <clause> remove <url>
php puko routes service crud <schema>/<table>   # full CRUD API scaffold
php puko routes list
  • Clause: view, service, or console.
  • URL params: {?} (or ?) marks dynamic PHP GET parameters, e.g. member/?/reports.
  • Path separators: URLs use forward slashes (/), controller names use backslashes (\). Example: php puko routes view add accounts/user/{?}/links → controller controller/accounts/user.php, function links.
  • Generated files: config/routes.php + controller/<path>.php. For view clauses it also generates assets/html/en/<path>.html and assets/html/id/<path>.html.
  • Remove security note: Puko does NOT delete the .php/.html files when removing a route — remove them manually.

3. Controllers

Namespacing & base classes

namespace controller;            // or namespace controller\inventory;
class member extends View {}     // or Service / Console

Responses

public function member() {
    $data['Name'] = 'Didit Velliz';
    $data['Address'] = 'Bandung';
    return $data;
}

Doc Tags (annotation-style, prefix #)

Doc tags sit in PHP doc comments above a class or function. All must be prefixed with #; otherwise the framework skips them. Only tags in comments — function logic stays clean.

TagKeyValueDescription
#ValuenameDidit VellizSends data directly to the view.
#Templatemastertrue/falseUse the master layout.
#Templatehtmltrue/falseOutput as HTML in the browser.
#Templatecachetrue/falseCache HTML output with the PTE cache driver.
#Datebefore/afterd-m-Y H:i:sTime-window access restriction (server time).
#ClearOutputbinarytrue/falseBypass framework output processing.
#Authbearer/session/cookiestrueRequires authentication.
#Mastermaster-admin.htmlChoose a non-default master layout.
#DisplayExceptiontrue/falseForward exceptions to View/Service middleware.
#UnderConstructiontrue/falseShow the “Under Construction” page.
#Permission\pukoframework\auth\Bearer@\plugins\auth\UserAuthpermissions@MANAGERRole-based access; shows “Permission Denied” on failure.

Example:

/**
 * #Value Hobby Swimming
 * #Auth bearer true
 * #Master master-admin.html
 */
public function member() { ... }

Console controllers

  • Generated via php puko routes console add <route_name> (defaults to GET verb).
  • Example: message/forgot/password/subscribe → controller console\forgot\password, method subscribe.
  • Run via php cli message/forgot/password/subscribe <argument> (only one argument supported).
  • Benefits: no HTTP (more secure), no web-server timeouts, event-driven, message queues, WebSocket servers.

4. Views & PTE Template Engine

  • View layer is presentation only — no business logic.
  • Controllers wire a matching HTML file automatically (same directory structure as the controller). Generated by php puko routes view add ....
  • Templates are pure HTML using PTE tags.

PTE tags

TagMeaning
{!x}Print a value / variable.
<!--{!x}--><!--{/x}-->Loop over an array.
{!fn()} / {!fn(x)} / {!fn(x,y,z)}Function calls.
{CONTENT}Inject the content HTML into the master layout.
{!css(<link ... />)} / {!js(<script ... ></script>)}Declare assets in a content file.
{!part(css)} / {!part(js)}Render declared assets (placed in the master layout).
{x.html}Load an HTML segment/element file.
{!url()}Base URL helper, e.g. <a href="{!url()}user/profile">.
  • To exclude an asset, wrap it in an HTML comment inside the tag: {!js(<!--<script src="..."></script>-->)}.

Master layouts

  • master.html (default) contains {CONTENT}, {!part(css)}, {!part(js)}.
  • Multiple masters supported (master.html, master-admin.html, master-guest.html, …) for role-specific layouts; select via #Master doc tag (defaults to master.html).

Elements (modular view components)

  • Self-contained packages in plugins/elements/<name>/ with <name>.php|html|js|css.
  • Manage via CLI: php puko element add <name> (create) or php puko element download <name> (fetch from the official github.com/Velliz/elements repo).
  • Names must be alphanumeric/underscore only ([a-z_A-Z]), no spaces or leading numbers.
  • Instantiate in controller, then render via the PTE tag:
    $desc = new AdminLTE_Description('desc', []);
    $desc->SetStyle(AdminLTE_Description::HORIZONTAL);
    $data['desc'] = $desc;
    

    ```html

{!desc}

---

## 5. Database Layer

### DBI (DataBase Interface) — singleton
```php
DBI::Prepare($sql)->GetData($params);    // all rows, indexed array
DBI::Prepare($sql)->FirstRow($params);   // single row
DBI::Prepare($sql)->Run($params);        // UPDATE/DELETE/stored procs
  • Prepared statements: @1, @2 positional params: DBI::Prepare("SELECT * FROM inventory WHERE id = @1 AND name = @2")->GetData($id, $name).

Data Objects (auto-generated)

  • Generated by php puko setup db into plugins/model/<schema>/read-only.
  • Class extends Model; mapped via doc tags: ```php /**
  • #Table tree_seeds
  • #PrimaryKey id */ class tree_seeds extends Model { /** #Column id int(10) */ var $id = null; /** #Column price int(8) */ var $price = null; } ```
  • Table names must be letters only (no special characters/spaces).
  • CRUD:
    • Create: set properties → $obj->save();
    • Read: $obj = new plugins\model\primary\inventory(1);
    • Update: $obj->modify();
    • Delete: $obj->remove();
    • All rows: inventoryContracts::GetAll();

Model Contracts (generated static methods)

<Model>Contracts:: exposes: GetData(), GetById($id), IsExists($id), IsExistsWhere($column, $value), GetDataSize(), GetDataSizeWhere($condition = []), GetLastData(), SearchData($keyword = []), GetDataTable($condition = []).

For custom joins/stored procedures, extend the generated model and implement ModelContracts:

class InventoryModel extends inventory implements ModelContracts {
    public static function SearchData($keyword = []) {
        $strings = "";
        foreach ($keyword as $column => $values) {
            $strings .= sprintf(" AND (%s = '%s') ", $column, $values);
        }
        $sql = sprintf("SELECT i.id, i.created, i.name, i.descriptions
                        FROM inventory i
                        WHERE (i.created IS NOT NULL) %s;", $strings);
        return DBI::Prepare($sql)->GetData();
    }
}

Transactions

$transaction = DBI::Transactional('primary', function($dbi) use ($v) {
    $v->save($dbi);
    return true;   // true = commit, false = roll back
});

$transaction evaluates to true/false.

Multiple databases

  • Each connection has a unique schema label (default primary). Set up extra connections via php puko setup db (prompts: database type, hostname, port, schema name, db name, user, pass).
  • config/database.php is an array keyed by schema label.
  • Use non-primary schemas by passing the label:
    $object = new models(null, 'dashboard');   // insert
    $object = new models(20, 'dashboard');     // update
    $result = DBI::Prepare($sql, 'dashboard')->GetData();
    
  • Supported engines (v1.1.6): MySQL, MariaDB, MSSQL. The setup wizard lists mysql, oracle, sqlsrv, mongo as prompts.

6. Authentication & Roles

Setup

php puko setup auth <AuthName>       # e.g. StudentAuth

Generates plugins/auth/StudentAuth.php with three boilerplate methods.

Login($username, $password)

Validate credentials (model, cURL, etc.), then must return a PukoAuth object:

public function Login($username, $password)
{
    $student = model\primary\StudentModel::GetByUsernamePassword($username, $password);
    $dataToSecure = ["id" => $student['id'], "username" => $student['user'], "class" => $student['class']];
    $permissions = ["STUDENT"];
    return new PukoAuth($dataToSecure, $permissions);
}

Invoking login

$login = Session::Get(StudentAuth::Instance())->Login($username, $password);
  • Session/Cookies: true on success, false on failure.
  • Bearer tokens: encrypted token string on success, false on failure.

Logout()

Cleanup callback; return true.

GetLoginData($secure, $permission)

Receives decoded $dataToSecure and the permission codes:

public function GetLoginData($secure, $permission)
{
    return ["data" => $secure, "authorization" => $permission];
}

Protecting functions

/**
 * #Auth session true
 */
public function create() {}

Permissions

  • Permissions are string arrays attached at login: $permissions = ["MANAGER"];
  • Enforce with the #Permission doc tag: ```php /**
  • #Auth session true
  • #Permission \pukoframework\auth\Bearer@\plugins\auth\UserAuth permissions@MANAGER */ public function profile() ```
  • Important: the #Permission tag requires the full PSR-4 path to the plugin auth class: \pukoframework\auth\Bearer@\plugins\auth\UserAuth.

7. Configuration

.env (never committed)

DB_* connection vars, ENVIRONMENT (DEVELOPMENT | STAGING | PROD | MAINTENANCE), ENCRYPTION_KEY. Start from .env.example.

config/app.php

Three root identifiers:

  • const — app-wide constants, read via $this->GetAppConstant('KEY') or Config::Data().
  • cache — Memcached connection (kind, expired, host, port).
  • logs — Slack Incoming WebHooks error reporting (disabled by default; set active: true).

config/database.php

Connection array keyed by schema label; managed via php puko setup db (or php puko refresh db to refresh without overwriting).

config/encryption.php

AES-256-CBC key protecting session/cookie/bearer auth data; set via php puko setup secure.

config/routes.php

Auto-managed route registry — read-only, manage via CLI.

Custom config files

Create e.g. config/rabbitmq.php; load via Config::Data('rabbitmq'):

$config = pukoframework\config\Config::Data('rabbitmq');

8. Internationalization (i18n)

  • Language detection: client sends X_LANG header with a 2-letter ISO 639-1 code (en, id, jp, …). Defaults to id when missing.
  • Frontend: separate HTML per language under assets/html/<lang>/ — copies of templates must be maintained per language (performance-first, no runtime processing).
  • Backend: $this->say('KEY', [$arg1, ...]) reads assets/master/<lang>.master.json. Supports sprintf %s placeholders:
    { "WRONG_ADDR": "The address for %s was not found for the email: %s" }
    
    throw new Exception($this->say('WRONG_ADDR', [$username, $email]));
    

9. Utilities

jQuery DataTables (server-side processing)

$table = new DataTables(DataTables::POST);
$table->SetColumnSpec(["name", "age", "address", "email"]);
$table->SetQuery("SELECT * FROM students;");
return $table->GetDataTables(function ($result) {
    foreach ($result as $key => &$val) { /* transform */ }
    return $result;
});
  • JS ajax.type must be POST; column count/order must match SetColumnSpec.
  • Include assets via PTE: {!js(<script src="assets/js/jquery.dataTables.min.js"></script>)}.
  • Recommend DataTables >= 1.10.

Pagination

$paginate = new Paginations();
$paginate->SetLength(10);
$paginate->SetQuery("SELECT * FROM students WHERE status = 'active'");
return $paginate->GetDataPaginations(function ($result) { ... });
  • Requires ?page= (1-based) and ?length= query params.
  • Response shape: {page, totalpage, length, displayed, anchor[], totaldata, data[]}.

File uploads

  • HTML form needs POST + enctype="multipart/form-data".
  • $file = Request::Files('filedata', null, true); (key, default, true = return object).
  • File object methods: getName(), getType() (MIME), getTmpName(), getSize() (kB), isError(), isSizeSmallerThan($limit) (default 10MB), getFile().
  • Save to DB (LONGBLOB column) via $model->filedata = $file->getFile();, or move to disk via move_uploaded_file($file->getTmpName(), $uploadPath).

Framework helpers (inside View/Service/Console controllers)

| Helper | Description | | :— | :— | | $this->GetServerDateTime() | Current server time, Y-m-d H:i:s. | | $this->GetRandomToken($len = 6) | Random alphanumeric token. | | $this->GetAppConstant('KEY') | Value from config/app.php const section. | | $this->RedirectTo('login', false) | Redirect; true = replace history. | | $this->say('KEY', [$args]) | Localized string from assets/master. | | Framework::$factory->getBase() | Base URL (e.g. http://localhost:3000/). | | Framework::$factory->getRoot() | Absolute server path to project root. | | Framework::$factory->getEnvironment() | DEVELOPMENT, STAGING, or PROD. | | Framework::$factory->getStart() | PHP execution start microtime. |

Controller lifecycle hooks

public function BeforeInitialize() { /* before main function */ }
public function AfterInitialize()  { /* after main function */ }

10. System States (Error Pages)

View-backed (extend View middleware)

  • controller/error.php + assets/html/id/error/display.html — triggered when the HTTP ACCEPT header doesn’t match the route’s registered verb.
  • controller/error.php + assets/html/id/error/maintenance.html — shown when ENVIRONMENT = MAINTENANCE.
  • controller/error.php + assets/html/id/error/notfound.html — non-existent route.

Doc-tag / exception driven (system templates, no controllers)

  • system/auth.html#Auth true with unauthenticated user.
  • system/construction.html#UnderConstruction true.
  • system/error.html — internal error (e.g. undefined variable).
  • system/exception.html — thrown Exception.
  • system/permission.html#Permission check failed.

11. Puko Console (CLI) — Full Command Reference

php puko help                          # list commands
php puko version                       # console version
php puko setup db                      # DB wizard + generate model wiring
php puko refresh db                    # refresh DB config without overwriting
php puko setup secure                  # configure AES-256-CBC encryption
php puko setup auth <AuthName>         # auth boilerplate in plugins/auth/
php puko routes <clause> add <url>     # scaffold route
php puko routes <clause> update <url>  # modify HTTP verbs via wizard
php puko routes <clause> remove <url>  # delete route (files kept)
php puko routes service crud <schema>/<table>   # full CRUD API
php puko routes list                   # list registered routes
php puko generate db                   # create tables from plugins/model schemas
php puko serve [port]                  # dev server (default 8080)
php puko tests                         # run tests in tests/unit/
php puko element add <name>            # create a view element
php puko element download <name>       # fetch element from official repo
php puko cli <route_path>              # run a console controller

12. Project Structure (Puko app layout, as documented)

assets/
├── html/            # View templates by language (en/id) — matches route paths
├── master/          # Master layouts + localized string JSONs (<lang>.master.json)
└── system/          # System templates (auth, error, exception, permission, construction)
bootstrap/           # Docker/Nginx infrastructure configs
config/              # app.php, database.php, encryption.php, routes.php, custom files
controller/          # View/Service/Console controllers
model/               # Custom model contracts (extend generated models)
plugins/             # auth/, elements/, model/ (generated Data Object wiring)
tests/unit/          # Unit tests (run via `php puko tests`)
cli                  # Console entry point: php cli <route_path> [argument]
index.php            # Web entry point
puko                 # Puko CLI dev tool

Generated content to treat as read-only: plugins/model/, config/routes.php, assets/html/<lang>/<route>.html.