Files
biibaye/fleetbase-source/AGENTS.md

24 KiB

AGENTS.md — Fleetbase

Architecture

  • Dual-stack monorepo: Laravel 10 (PHP) backend + Ember.js 5.4 frontend + 12 Git submodules
  • Docker services: application (FrankenPHP/Caddy :8000), httpd (:80→8000), console (Nginx :4200), socket (SocketCluster :38000), database (MySQL 8.0 :3306), cache (Redis), queue, scheduler
  • Console port 4200, API port 8000 — both must be free or mapped differently
  • Packages: Each packages/<name>/ is a Git submodule; contains PHP (composer.json + server/) and/or Ember code (addon/, app/, extension.json)
  • Core packages: core-api, ember-core, ember-ui, dev-engine — framework layers all extensions depend on

Prerequisites & Constraints

  • PHP >= 8.0, <= 8.2.30 (strict upper bound — 8.3+ will break)
  • Node.js >= 22
  • pnpm is the JS package manager (not npm/yarn) — pnpm@11.0.9
  • Composer uses private registry at https://registry.fleetbase.io — authentication may be required for private packages
  • Git submodules must be initialized: git submodule update --init --recursive

Commands

Docker (most common)

docker compose up -d                          # Start all services
docker compose exec application bash          # Shell into API container
docker compose exec application php artisan … # Run artisan commands
docker compose exec application bash -c "./deploy.sh"  # Run deployment script

Backend (api/)

cd api && composer install    # Install PHP deps (uses fleetbase registry)
cd api && php artisan …       # Laravel artisan (run inside container or locally with DB access)
cd api && php artisan test    # Run PHPUnit tests
cd api && ./vendor/bin/php-cs-fixer fix   # Fix PHP style
cd api && vendor/bin/phpstan analyse       # Static analysis (in packages with phpstan.neon.dist)

Frontend (console/)

cd console && pnpm install    # Install JS deps
cd console && pnpm start      # Ember dev server (requires API + socket running)
cd console && pnpm lint       # ESLint + stylelint + template-lint
cd console && pnpm test       # Lint + ember test (QUnit via Testem)
cd console && pnpm build      # Production build → dist/

Single test runs

cd api && php artisan test --filter=MyTest           # PHP: single test class
cd api && php artisan test --filter=MyTest::testFoo  # PHP: single test method
cd console && pnpm test --filter='My test name'       # Ember: filter by test name
cd console && pnpm test --server                      # Ember: watch mode

Extensions (Custom Packages)

Each extension is a Git submodule under packages/<name>/ with this structure:

extension.json          # Metadata (name, version, engine, api)
composer.json           # PHP dependencies (if has API)
package.json            # JS dependencies (if has Ember engine)
server/                 # PHP API code (PSR-4)
addon/                  # Ember engine files
app/                    # Ember app files

Scaffold a new extension

flb scaffold                            # CLI wizard
# Or manually: create packages/<name>/ with extension.json, composer.json, package.json
# Register it as submodule: git submodule add <repo-url> packages/<name>
node scripts/package-linker.mjs                 # Symlink all packages/ into api/ and console/

Package registry flow

flb register                              # One-time: create registry account
flb verify -e <email> -c <code>           # Verify email
flb generate-token -e <email>             # Get auth token
flb set-auth <token>                      # Save token for installs
flb install fleetbase/<extension>         # Install extension from registry

Production Deployment (VPS: 37.27.183.102)

SSH key: Config/fleet_key  (chmod 600, OpenSSH RSA private key)
SSH command: ssh -i Config/fleet_key root@37.27.183.102

Key env vars for production (docker-compose.override.yml)

  • ENVIRONMENT=production, APP_DEBUG=false
  • APP_KEY — generate with docker compose exec application bash -c "php artisan key:generate --show"
  • APP_URL, CONSOLE_HOST — set to actual domain/IP
  • SESSION_DOMAIN — domain for session cookies
  • SOCKETCLUSTER_OPTIONS — restrict origins to production domains
  • MAIL_* — configure real mailer (not log driver)
  • FILESYSTEM_DRIVER=s3 — S3 for file storage (not local disk)
  • GOOGLE_MAPS_API_KEY, IPINFO_API_KEY, TWILIO_* — for full feature set
  • REGISTRY_HOST, REGISTRY_PREINSTALLED_EXTENSIONS — extension registry config
  • OSRM_HOST — routing engine URL

Production checklist

  1. Copy repo to server, run docker compose up -d (with correct override)
  2. Ensure ports 80/443/8000/4200/38000 are open in firewall
  3. Set up SSL/reverse proxy (Caddyfile for API, Nginx for console)
  4. Use external/managed MySQL in production (not bundled container)
  5. S3 for file storage (not local disk)
  6. Restrict SOCKETCLUSTER_OPTIONS origins

Environment File Locations

Env Notes
docker-compose.override.yml Primary — env vars injected into all Docker services
api/.env Only needed for local PHP runs outside Docker
api/.env.example Template reference
console/environments/.env.development Ember dev env
console/environments/.env.production Ember prod env

Git Submodule Gotchas

  • Always git submodule update --init --recursive after clone
  • Submodules track specific commits — working on a package means committing inside packages/<name>/ first, then updating the parent repo's submodule pointer
  • After git pull in parent, run git submodule update --recursive to sync submodules
  • Package linker script (scripts/package-linker.mjs) symlinks submodules into api/console/ for local dev — run it after changing module structure

Linting (all layers)

Layer Tool Command
PHP php-cs-fixer ./vendor/bin/php-cs-fixer fix (in api/ or package)
PHP PHPStan vendor/bin/phpstan analyse (in packages with neon config)
JS ESLint + Prettier pnpm lint (in console/)
CSS Stylelint pnpm lint:css
Templates ember-template-lint pnpm lint:hbs
i18n fleetbase-intl-lint pnpm lint:intl

Conventions

  • Ember Octane edition — use Glimmer components (@glimmer/component), <template> tags, @tracked
  • Tailwind CSS 3.4 is the styling framework, inter-ui is the typeface
  • PHP controllers return API resources via \App\Http\Resources\ namespace
  • Caddy replaces traditional Nginx/Apache for the API server (FrankenPHP)
  • SocketCluster handles real-time WebSocket connections
  • Prettier config: 4-space tabs, single quotes for JS, double quotes for HBS, 190 print width

Session: 2026-05-24 — Biibaye Branding Extension

Branch Strategy

  • main: Clean upstream from github.com:fleetbase/fleetbase. Never commit here — only git pull.
  • custom-production: Working branch with custom branding + WhatsApp alterations. Created off main at v0.7.41.

Private Git Repo

  • URL: ssh://git@git.1.warancloud.com:2222/Ali/biibaye.git
  • SSH Key: ~/.ssh/deploy_key (same key present on both local and VPS)
  • SSH Config entry (on VPS at /root/.ssh/config):
    Host git.1.warancloud.com
        IdentityFile ~/.ssh/deploy_key
        IdentitiesOnly yes
        AddKeysToAgent yes
        port 2222
        user git
    

New Extension: packages/biibaye-branding/

Git submodule pointing at private repo. Provides all custom branding:

packages/biibaye-branding/
├── extension.json              # "Biibaye Branding" v1.0.0
├── package.json                # @biibaye/branding, fleetbase-extension + ember-engine keywords
├── index.js                    # Ember addon entry
├── config/environment.js       # Engine config
├── addon/
│   ├── engine.js               # Minimal Ember Engine (required by Fleetbase build system)
│   └── extension.js            # Branding logic — runs at Ember boot
└── public/
    ├── favicon/                # 22 Biibaye-branded icon files (apple-icon-*, android-icon-*, ms-icon-*)
    └── images/                 # logo SVGs, icon PNGs

extension.js does 5 things on boot:

  1. document.title = "Biibaye - Delivery System" (in both setupExtension and onEngineLoaded)
  2. intl.addTranslations('en-us', { 'app.name': 'Biibaye' }) — runtime translation injection
  3. Injects CSS: --primary: #FF4500, dark theme background-color: #343538
  4. Replaces all <link rel="icon"> / <link rel="apple-touch-icon"> with Biibaye files
  5. Updates meta tags: msapplication-TileColor, theme-color, msapplication-TileImage

Why translations/en-us.yaml was removed: ember-intl merges translations at build time with host app files taking HIGHEST priority. console/translations/en-us.yaml defines app.name: Fleetbase, which always wins over any addon's app.name. Other Fleetbase extensions avoid this by using namespaced keys (e.g., fleet-ops.*, storefront.*). Solution: in overrideAppName(), look up the intl service from appInstance and call intl.addTranslations('en-us', { 'app.name': 'Biibaye' }) at runtime.

Key implementation detail: setupExtension() calls universe.extensionManager.ensureEngineLoaded('@biibaye/branding') to force the engine to boot. Without this, the engine never loads (root-mounted engines have no route to trigger boot). onEngineLoaded re-sets translation and title after boot, defeating any race with ember-page-title re-render.

Deploy Script: /opt/fleetbase/scripts/deploy-biibaye.sh

Located on VPS. Handles the Docker build context issue (console build context is ./console/, not repo root). Steps:

  1. git pull origin main in extension submodule
  2. Copies extension into console/packages/biibaye-branding/ (Docker build context)
  3. Copies public/favicon/* and public/images/* into console/public/ (so files serve from root /favicon/* URLs)
  4. NEW — Patch console/app/index.html: Replace Fleetbase defaults to prevent branding flash during reload:
    sed -i 's|<title>Fleetbase Console</title>|<title>Biibaye - Delivery System</title>|' console/app/index.html
    sed -i 's|content="#da532c"|content="#FF4500"|' console/app/index.html
    sed -i 's|content="#ffffff"|content="#FF4500"|' console/app/index.html
    sed -i 's|href="/favicon/apple-touch-icon.png"|href="/favicon/apple-icon-180x180.png"|' console/app/index.html
    sed -i 's|href="/favicon/android-chrome-192x192.png"|href="/favicon/android-icon-192x192.png"|' console/app/index.html
    sed -i 's|href="/favicon/android-chrome-256x256.png"|href="/favicon/android-icon-144x144.png"|' console/app/index.html
    sed -i 's|color="#5bbad5"|color="#FF4500"|' console/app/index.html
    
  5. NEW — Patch console/tailwind.config.js: Replace sky-500 blue (#3485e2) palette with Biibaye orange (#FF4500). This is the PRIMARY fix for the color theme — without this, Fleetbase shows blue buttons/accents because all UI uses Tailwind sky-* classes directly:
    sed -i "s/'#e6f0fb'/'#FFF0E6'/" console/tailwind.config.js
    sed -i "s/'#bad5f5'/'#FFD0B3'/" console/tailwind.config.js
    sed -i "s/'#8dbbef'/'#FFB380'/" console/tailwind.config.js
    sed -i "s/'#61a0e8'/'#FF7A33'/" console/tailwind.config.js
    sed -i "s/'#3485e2'/'#FF4500'/" console/tailwind.config.js
    sed -i "s/'#1c6cc7'/'#E03D00'/" console/tailwind.config.js
    sed -i "s/'#16539a'/'#B33100'/" console/tailwind.config.js
    sed -i "s/'#103b6d'/'#8A2600'/" console/tailwind.config.js
    sed -i "s/'#092341'/'#611A00'/" console/tailwind.config.js
    
  6. Adjusts pnpm workspace paths for Docker (../packages/packages/)
  7. Injects COPY packages/ packages/ before pnpm install in Dockerfile (so pnpm resolve the link dependency)
  8. Removes --frozen-lockfile during build (new dep not in lockfile)
  9. Runs docker compose build console --no-cache
  10. Restores all original configs (Dockerfile, package.json, workspace, index.html, tailwind.config.js) — restore is critical to keep the clean checkout intact
  11. Restarts console, httpd, application containers

Why both tailwind.config.js patching AND extension.js CSS injection?

  • tailwind.config.js patching (build-time): Changes primary color at the Tailwind compilation level. This prevents the blue flash because the compiled @fleetbase/console.css already contains orange colors. However, ember-ui's pre-compiled CSS in vendor.css (like .btn.btn-primary) uses #3485e2 at @apply compile time and is NOT affected by the console's tailwind config.
  • extension.js CSS injection (runtime): Acts as a safety net, overriding any blue that leaks through from vendor.css with !important rules. Covers the gap where ember-ui's pre-compiled CSS still references blue.

To update branding assets in the future:

# Locally: replace files in packages/biibaye-branding/public/ then:
cd packages/biibaye-branding
git add -A && git commit -m "Update assets" && git push origin main

# On VPS:
ssh root@37.27.183.102
/opt/fleetbase/scripts/deploy-biibaye.sh

VPS Changes Made (37.27.183.102)

What Where Details
custom-production branch /opt/fleetbase/ Created off main, committed submodule addition
packages/biibaye-branding submodule /opt/fleetbase/.gitmodules Points at private repo
APP_NAME: "Biibaye" docker-compose.override.yml Was "Fleetbase"
MAIL_FROM_NAME: "Biibaye" docker-compose.override.yml Was "Fleetbase"
EXTENSIONS: "@biibaye/branding" console/fleetbase.config.json Critical — without this extension.js never runs
SSH config /root/.ssh/config Added git.1.warancloud.com entry
SSH key /root/.ssh/deploy_key Copied for private repo access
Deploy script /opt/fleetbase/scripts/deploy-biibaye.sh Rebuilds console with branding

VPS State (Pre-existing)

What Value
Fleetbase version v0.7.41
Domains api.biibaye.com, console.biibaye.com, socket.biibaye.com
.env.development API: http://37.27.183.102:8000
.env.production API: https://api.biibaye.com
fleetbase.config.json API/Socket prod URLs
Docker services All running (scheduler unhealthy — pre-existing)

Branding Spec

Property Value
App name Biibaye
Window title Biibaye - Delivery System
Primary color #FF4500
Dark theme background #343538
Favicon files 22 Biibaye-branded icons (apple-icon-, android-icon-, ms-icon-*)
Logo files SVG-02.svg, icon.svg, icon.png, fleetbase-logo-svg.svg

Troubleshooting: app.name Translation

Problem: {{t "app.name"}} still shows "Fleetbase" after extension loaded.

Root cause: ember-intl v6.3.2 build-time merge gives host app (console/translations/en-us.yaml) priority over addon translations. Key app.name: Fleetbase at line 2 of console translations defeats any addon override.

Fix: Instead of relying on build-time translations/en-us.yaml, use runtime injection via intl.addTranslations():

// In setupExtension + onEngineLoaded:
const intl = appInstance.lookup('service:intl');
intl.addTranslations('en-us', { 'app.name': 'Biibaye' });

Verification: Check that appInstance.lookup('service:intl') returns the intl service and addTranslations method exists. ember-intl 6.3.2 has this API confirmed via addTranslations in test-support.js.

Troubleshooting: Primary Color Not Applied (CSS Variables Don't Work)

Problem: Extension injected :root { --primary: #FF4500; } but Fleetbase UI still shows blue (#3485e2).

Root cause: Fleetbase does NOT use CSS custom properties for theming. All colors are hardcoded via Tailwind's sky-* palette (e.g., bg-sky-500, text-sky-500). The --primary variable is never referenced by any Fleetbase component or CSS rule.

Fix (two layers):

  1. Build-time — Patch tailwind.config.js to replace the sky palette with Biibaye orange before the Docker build. This changes all sky-* class definitions in the compiled console.css.

  2. Runtime — extension.js injects !important CSS overrides targeting Tailwind utility classes (.bg-sky-500, .text-sky-500, etc.) and component classes (.btn.btn-primary). This catches any blue that leaks through from ember-ui's pre-compiled vendor.css.


Session: 2026-05-25 — CSS Color Fix + Fleetbase UI Removal

Two critical fixes applied

1. Post-build CSS color patching (the approach that finally worked)

Problem: Building tailwind.config.js patches into Docker failed repeatedly (host-side sed, Dockerfile-internal Node.js patching, post-build sed — none worked). The built CSS always retained Fleetbase blue rgba(52, 133, 226, ...).

Solution: console/patch-css-colors.js — a Node.js script that runs AFTER pnpm build inside the Dockerfile. It walks the dist/ directory tree, finds all .css files, and replaces Fleetbase blue hex/RGB values with Biibaye orange directly in the compiled output.

RUN pnpm build --environment $ENVIRONMENT
RUN node patch-index-html.js && node patch-css-colors.js

Result: 4 CSS files patched (console.css, vendor.css, fleetops-engine/engine.css, registry-bridge-engine/engine.css). Zero blue references remain — 11 orange refs in console.css, 16 in vendor.css.

2. Extension loading fix

Problem: The @biibaye/branding extension never loaded because extensions.json (generated at build time by scanning node_modules) didn't include it. The deploy script's sed commands to modify pnpm workspace paths were no-ops because the source files never contained the biibaye entries to begin with.

Solution: Added "@biibaye/branding": "link:../packages/biibaye-branding" to console/package.json dependencies. Committed to custom-production branch. The deploy script converts the link path from link:../packages/ (host) to link:packages/ (Docker build context) via sed. This is the ONLY reliable sed in the deploy script — the workspace.yaml sed was removed.

Result: extensions.json now contains @biibaye/branding. The extension loads, all runtime features fire on boot.

Extension.js Enhancements

Added in this session:

  1. CSS color overrides — replaced non-functional --primary: #FF4500 CSS variables with !important overrides for actual Tailwind classes (.bg-sky-500, .text-sky-500, .border-sky-500, .btn.btn-primary, etc.) and dark theme body[data-theme="dark"] background.

  2. Fleetbase UI removal:

    • Menu links — CSS rules hide .support-user-nav-item (Help & Support), .docs-user-nav-item (Documentation), and a[href*="discord.gg"] (Discord).
    • Default widgetsremoveFleetbaseWidgets() accesses the widget registry and removes dashboard#fleetbase-blog and dashboard#fleetbase-github-card from both widget and default-widget lists.

Patch Scripts (in console/ directory on VPS)

Script Purpose When runs
patch-index-html.js Replace Fleetbase title/favicon/meta in dist/index.html Docker: after pnpm build
patch-css-colors.js Replace Fleetbase blue → Biibaye orange in all compiled CSS Docker: after pnpm build
patch-index-html.py Same as .js version but in Python (used on host) Deprecated — uses .js version now
patch-tailwind.js Replace sky palette in tailwind.config.js Deprecated — didn't work reliably in Docker

Deploy Script (current version)

Located at /opt/fleetbase/scripts/deploy-biibaye.sh on VPS. Current steps:

  1. git pull origin main in extension submodule
  2. Copy extension into console/packages/biibaye-branding/
  3. Copy public assets (favicon, images) into console/public/
  4. Run python3 patch-index-html.py on host (patches source app/index.html)
  5. Adjust Dockerfile: remove --frozen-lockfile, inject COPY packages/ packages/, inject RUN node patch-index-html.js before build
  6. Adjust package.json: convert link:../packages/link:packages/ for Docker context
  7. docker compose build console --no-cache
  8. Restore all modified files (index.html, package.json, Dockerfile)
  9. Restart containers

Fleetbase Source Changes (custom-production branch)

File Change
console/package.json Added "@biibaye/branding": "link:../packages/biibaye-branding" in dependencies
AGENTS.md All session documentation

These changes are mirrored in the custom-pr branch of the biibaye extension repo under fleetbase-source/ for safekeeping.


Session: 2026-05-25 — Email Template Rebrand

Problem

OTP email showed "14411 is your fleetbase verification code" (lowercase fleetbase), Fleetbase logo in email header, and "2026 Fleetbase..." in footer. Other notification emails (password reset, user invite, etc.) had hardcoded "Fleetbase" in subject lines and body text.

Root Cause

The application container had APP_NAME=Fleetbase despite docker-compose.override.yml setting APP_NAME: "Biibaye". The container was created before the override was applied and restart doesn't pick up new env vars — only --force-recreate does.

Fix Applied

  1. Environment fix: Recreated application container with --force-recreate to pick up APP_NAME=Biibaye from override. This fixed all config('app.name') references:

    • OTP email subject: "XXXX is your Biibaye verification code"
    • SMS code: "Your Biibaye verification code is XXXX"
    • Email footer: "© 2026 Biibaye"
    • Logo alt text: "Biibaye Logo"
    • Password reset (forgot): "Your password reset link for Biibaye"
    • User credentials: "Your login credentials for ... on Biibaye"
  2. Hardcoded Fleetbase → config('app.name'): Modified PHP source files to replace hardcoded "Fleetbase" strings. Applied via Docker volume mounts (overlay patched files over vendor directory):

    File Change
    PasswordReset.php "Your password reset link for Fleetbase"config('app.name')
    UserInvited.php "...on Fleetbase!""...on " . config('app.name') . "!"
    UserAcceptedCompanyInvite.php "...on Fleetbase!" + "Thank you for using Fleetbase!"config('app.name')
    TestMail.php Subject set via config('app.name') in constructor
    test.blade.php "test email from Fleetbase"{{ config('app.name') }}
    fleetbase.php Logo URL → https://console.biibaye.com/images/icon.png
    mail.php From address default → no-reply@biibaye.com, name fallback → Biibaye
    Utils.php getDefaultMailFromAddress default → null (uses CONSOLE_HOST)
    StorefrontNetworkInvite.php ->from('hello@fleetbase.io',...)config('mail.from.address')
  3. Volume mounts in docker-compose.override.yml:

    application:
      volumes:
        - ./api/patches/core-api/src/Notifications/PasswordReset.php:/fleetbase/api/vendor/fleetbase/core-api/src/Notifications/PasswordReset.php
        # ... (8 mount points total)
    

    This overlays the patched files over the pre-built Docker image without requiring a custom image build.

Email branding summary

Element Before After
OTP subject "XXXX is your fleetbase verification code" "XXXX is your Biibaye verification code"
Email header logo Fleetbase S3 logo Biibaye icon (from admin setting, fallback: console.biibaye.com)
Email footer "© 2026 Fleetbase" "© 2026 Biibaye"
From address hello@fleetbase.io (default) no-reply@biibaye.com (default)
From name Fleetbase (default) Biibaye (default)
Password reset subject "Your password reset link for Fleetbase" "Your password reset link for Biibaye"
User invite subject "...invited to join Company on Fleetbase!" "...invited to join Company on Biibaye!"