# Trakop — Ubuntu Setup Guide (new dev machine)

Derived from the working checkout on this machine (Ubuntu 24.04, Apache 2.4.58, PHP 7.4.33-FPM, MySQL 8.0.46, Node 24, Python 3.12).

---

## 0. Hard requirements — read first

| Rule | Why |
|---|---|
| Checkout path **must** be `/var/www/html/trakop-web/` (app root `/var/www/html/trakop-web/code`) | `config/paths.php` derives `$project_root` from `getBetween(getcwd(), "html/", "webroot")` and only matches the local-dev DB branch when it equals `trakop-web/code/`. Any other path silently falls through to the `default:` branch (`root` / `Root@123` / `27215_vendor`) and nothing connects. |
| **PHP 7.4**, not 8.x | CakePHP 3.4/3.5 codebase. Ubuntu 24.04 ships 8.3, so the `ondrej/php` PPA is mandatory. |
| **Never run `composer install`** | `code/vendor/` is committed to git (8,253 files, CakePHP 3.5.17). `composer.lock` pins cakephp 3.4.6 — installing downgrades vendor/ and every page 500s with `getSession does not exist` / `MissingPluginException`. Recovery: `git checkout -- code/vendor/` + reset opcache. |
| MySQL 8 is fine | The app forces `SET sql_mode = ''` per connection (`config/app.php` Datasources `init`). Raw clients (python scripts, migration tool) do **not** — see §6. |

---

## 1. Base packages

```bash
sudo apt update && sudo apt install -y software-properties-common
sudo add-apt-repository -y ppa:ondrej/php
sudo apt update

# Web server + PHP 7.4 (extension set matches this machine exactly)
sudo apt install -y apache2 \
  php7.4-fpm php7.4-cli php7.4-common \
  php7.4-mysql php7.4-pgsql php7.4-mbstring php7.4-intl php7.4-gd \
  php7.4-curl php7.4-xml php7.4-xsl php7.4-zip php7.4-soap \
  php7.4-bcmath php7.4-gmp php7.4-imap php7.4-ldap php7.4-bz2 \
  php7.4-opcache php7.4-readline

# Database
sudo apt install -y mysql-server

# Node (realtime server) + Python (report/delivery tooling)
curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash -
sudo apt install -y nodejs python3 python3-pip

# Composer — needed only for `composer test` / `cs-check`, NOT for install
sudo apt install -y composer
```

Verify: `php -v` → 7.4.x, `php -m` must include `intl mbstring pdo_mysql gd soap zip bcmath gmp xsl imap ldap`.

---

## 2. Apache

```bash
sudo a2enmod rewrite proxy_fcgi setenvif
sudo a2enconf php7.4-fpm
sudo systemctl restart apache2
```

`/etc/apache2/sites-enabled/000-default.conf` — the app relies on `.htaccess`, so `AllowOverride All` is required:

```apache
<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html

    <Directory /var/www/html>
        Options Indexes FollowSymLinks
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
```

App is then reachable at `http://localhost/trakop-web/code/` (the root `/` route → `UsersController::login()`).

### PHP-FPM pool — `/etc/php/7.4/fpm/pool.d/www.conf`

The stock `pm.max_children = 5` saturates immediately (the dashboard fires many parallel XHRs and every request blocks a child). Raise it:

```ini
pm = dynamic
pm.max_children = 25
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
```

> **Do not copy** any `env[TRAKOPLENS_AI_ENDPOINT] = http://127.0.0.1:8899/...` line from an existing pool file. That repoints the live LLM at the local stub gateway and leaks `[STUB GATEWAY]` text into user-facing answers. The endpoint override is meant to be CLI-only.

### PHP ini — `/etc/php/7.4/fpm/php.ini`

```ini
memory_limit = 256M
max_execution_time = 300
post_max_size = 64M
upload_max_filesize = 8M     ; 2M default is too small for bulk excel/image uploads
date.timezone = Asia/Kolkata
max_input_vars = 5000        ; large delivery-sheet / bulk forms exceed the 1000 default
```

For the CLI (`/etc/php/7.4/cli/php.ini`) set `memory_limit = -1` and `max_execution_time = 0` — the migration tool and TrakopLens check scripts need it.

```bash
sudo systemctl restart php7.4-fpm apache2
```

---

## 3. Source checkout

```bash
sudo mkdir -p /var/www/html && cd /var/www/html
git clone http://192.168.0.17/gurbrindersingh/trakop-web.git
cd trakop-web
git checkout <your-branch>          # e.g. develop, or feature-trakop_lens_2
```

Ownership: keep the tree owned by your user, but everything Apache writes must be writable by `www-data`:

```bash
cd /var/www/html/trakop-web/code
mkdir -p tmp logs webroot/cache_files webroot/invoices webroot/csv \
         webroot/bulk_excel webroot/xero webroot/quickbook
chmod -R 777 tmp logs webroot/cache_files webroot/invoices webroot/csv \
             webroot/bulk_excel webroot/xero webroot/quickbook
```

(These are all git-ignored, so a fresh clone has none of them — CakePHP fails hard on an unwritable `tmp/cache`.)

`code/webroot/db_records.txt` does not exist locally and is not needed — `paths.php` guards with `file_exists()` and falls through to the local-dev branch.

---

## 4. Database

### 4.1 Create the user

```sql
CREATE USER 'localuser'@'localhost' IDENTIFIED BY 'Master123#';
GRANT ALL PRIVILEGES ON *.* TO 'localuser'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
```

### 4.2 Load a vendor DB

Dump from the existing machine and restore. Pick the DB by how much data you need:

| DB | Size | Use |
|---|---|---|
| `48116_vendor` | ~8.6 GB | Full multi-branch test vendor ("Haribol") — the realistic one |
| `trakop_48230_vendor` | ~1.3 GB | Medium |
| `trakop_11280_vendor` | ~106 MB | Light, fast to move |
| `1754_vendor` | ~4 MB | Smoke-test only |

```bash
# on the source machine
mysqldump -ulocaluser -p --single-transaction --quick --routines --triggers \
  --set-gtid-purged=OFF 48116_vendor | gzip > 48116_vendor.sql.gz

# on the new machine
mysql -ulocaluser -p -e "CREATE DATABASE 48116_vendor CHARACTER SET utf8mb4;"
zcat 48116_vendor.sql.gz | mysql -ulocaluser -p 48116_vendor
```

For the 8.6 GB dump, bump `max_allowed_packet` and `innodb_buffer_pool_size` first (§6) or the restore crawls.

---

## 5. Local configuration (2 tracked files you must edit and never commit)

### 5.1 `code/config/paths.php`

Edit **only** the `trakop-web/code/` branch (~line 88) to match §4.1:

```php
if (($project_root == 'trakop-web/code/') && !in_array($_SERVER['SERVER_ADDR'], [...])) {
    define('DBHOST', 'localhost');
    define('DBUSERNAME', 'localuser');
    define('DBPASSWORD', 'Master123#');
    define('DBNAME', '48116_vendor');
}
```

### 5.2 `code/migration-tool/ruckusing.conf.php`

Its `trakop-web/code/` branch still carries stale defaults (`root`/`root`/`402_vendor`). Point it at the same DB:

```php
if ($project_root == 'trakop-web/code/') {
    $temp['DBHOST'] = 'localhost';
    $temp['DBUSERNAME'] = 'localuser';
    $temp['DBPASSWORD'] = 'Master123#';
    $temp['DBNAME'] = '48116_vendor';
}
```

Both files are tracked in git — keep the edits local:

```bash
git update-index --skip-worktree code/config/paths.php code/migration-tool/ruckusing.conf.php
```

(Reverse with `--no-skip-worktree` when you genuinely need to change them for everyone.)

---

## 6. MySQL tuning — `/etc/mysql/mysql.conf.d/mysqld.cnf`

The CakePHP connection clears `sql_mode` itself, but the Ruckusing migration tool and the Python report scripts connect directly and *do* hit MySQL 8 strict mode. For a dev box:

```ini
[mysqld]
sql_mode = ""
innodb_buffer_pool_size = 2G      # scale to ~50% of RAM for the 8.6 GB DB
max_allowed_packet = 256M
innodb_flush_log_at_trx_commit = 2
```

```bash
sudo systemctl restart mysql
```

---

## 7. Python tooling (delivery sheets, reports, TrakopLens delivery tools)

PHP shells out to `python3` **on PATH** — there is no venv path baked in, so install system-wide (or put a venv's `bin` first on PATH for the FPM/CLI environment):

```bash
sudo apt install -y python3-pymysql python3-pandas python3-openpyxl \
                    python3-xlsxwriter python3-reportlab python3-requests \
                    python3-numpy
# Google Drive/email helpers (drive_email_utils.py, gdrive_reauth.py)
pip3 install --break-system-packages google-api-python-client google-auth-oauthlib
```

Verify against the versions on the working box:

```bash
python3 -c "import pymysql, pandas, openpyxl, xlsxwriter, reportlab, requests; print('ok')"
```

> TrakopLens delivery tools run `webroot/python_script/delivery_inventory.py`. When invoking anything that bootstraps CakePHP from the CLI, `chdir` to `code/webroot` **before** requiring bootstrap — otherwise `$project_root` resolves wrong and DBNAME becomes `27215_vendor`, and every python-backed delivery tool returns `tool_failed`.

---

## 8. Node realtime server (optional — WebSocket tracking, port 8400)

```bash
cd /var/www/html/trakop-web/code/nodeServer
npm install
```

Edit `app/config/db.config.js` (ships with `root`/`root`/`27215_vendor`):

```js
module.exports = { HOST: "localhost", USER: "localuser", PASSWORD: "Master123#", DB: "48116_vendor" };
```

```bash
npm start        # nodemon server.js → http://localhost:8400
```

`paths.php` defines `NODE_URL` as `{protocol}://{SERVER_NAME}:8400/` for non-`192.168.0.10` hosts, so this lines up automatically.

---

## 9. Flask utilities (optional — invoice processing, port 5000)

```bash
cd /var/www/html/trakop-web/flask_app
pip3 install --break-system-packages -r requirements.txt
python3 run.py       # http://0.0.0.0:5000
```

---

## 10. Migrations

```bash
cd /var/www/html/trakop-web/code/migration-tool
php ruckus.php db:version        # current
php ruckus.php db:migrate        # apply pending
```

---

## 11. TrakopLens extras (only if you work on that feature)

- Kong/LLM config lives in `config/paths.php` (`TRAKOPLENS_AI_*`, `TRAKOPLENS_KONG_*`). `TRAKOPLENS_KONG_KEY` defaults to the demo string — `/gateway-api/*` fail-closes on it, which is intended.
- `code/docs/trakoplens-rag/kb-snapshot.ndjson` is **git-ignored**. Either copy `docs/trakoplens-rag/` across from the working machine or rebuild it:
  ```bash
  cd /var/www/html/trakop-web/code && bin/cake rag_reindex
  ```
  Without it, RAG retrieval returns nothing.
- Check scripts live in `code/tests/TrakopLens/` (also git-ignored — copy them over):
  ```bash
  php tests/TrakopLens/run_checks.php
  ```
  Note: `run_checks.php` has pre-existing unrelated FAILs; compare against the baseline, don't expect all-green.

---

## 12. Smoke test

```bash
# 1. DB reachable through the app's own resolution logic
cd /var/www/html/trakop-web/code/webroot && php -r 'require "../config/paths.php"; echo DBNAME, "@", DBHOST, "\n";'
# expect final line: 48116_vendor@localhost   (NOT 27215_vendor — that means the path check failed)
# The "Undefined index: SERVER_ADDR / SERVER_NAME" notices are expected under CLI and harmless.

# 2. Web
curl -sI http://localhost/trakop-web/code/ | head -1     # expect 200/302, not 500

# 3. Logs on failure
tail -50 /var/log/apache2/error.log
tail -50 /var/www/html/trakop-web/code/logs/error.log
```

---

## 13. Troubleshooting quick table

| Symptom | Cause | Fix |
|---|---|---|
| Every page 500s, `Call to undefined method getSession` / `MissingPluginException` | `vendor/` was downgraded to CakePHP 3.4.6 by `composer install` | `git checkout -- code/vendor/` then `sudo systemctl restart php7.4-fpm` (resets opcache) |
| Connects to `27215_vendor` | Checkout is not at `/var/www/html/trakop-web/code`, or CLI cwd is wrong | Move the checkout; for CLI, `cd code/webroot` before bootstrapping |
| `Could not apply permissions to tmp/cache` | Missing/unwritable dirs after fresh clone | Re-run the `mkdir`/`chmod` block in §3 |
| Stale/phantom data (wrong timezone, old feature flags) | File cache in `webroot/cache_files/` | Delete `timezone_*.txt` / `masterConfig_*.txt`, or call `$this->Custom->createAndClearCacheFile()` |
| Requests hang under load | `pm.max_children = 5` | Raise it (§2) |
| `SQLSTATE[42000] ... only_full_group_by` from a python/migration script | Global strict mode | Set `sql_mode = ""` in `mysqld.cnf` (§6) |
| MySQL 8 auth error on connect | `caching_sha2_password` | `ALTER USER 'localuser'@'localhost' IDENTIFIED WITH mysql_native_password BY 'Master123#';` |
| 403 on a newly added controller action | ACL | Add to `$this->Auth->allow([])` in `initialize()`, or `AclManager.ignoreActions` in `bootstrap.php` |
