Top.ug Logo Docs
On this page
Directory Pro — Setup & Customization

Documentation

A complete guide that covers local installation, deployment to Ubuntu 24.04 VPS using GitHub Actions, configuration of the production environment, queues, and how to theme your directory with Flux CSS variables.

Overview

Directory Pro is a digital business-card directory built for Uganda market (Only supports Momo/Airtel Payments) — its a publicly searchable directory for business cards, the card management system includes user avatar uploads. billing is powered by mobile-money via ioTec Pay. Directory pro also features a simple invoicing system with PDF receipts, and a full featured owners admin panel. The Tech Stack: PHP 8.5 / Laravel 13, Livewire 4, Flux UI 2, Tailwind 4, Vite, Pest.

Public directory

Paginated grid, avatar + bio, social links, per-card public page. Blocked users' cards are auto-hidden.

Billing & invoices

Free-slot gating, mobile-money checkout with webhook settlement, tokenized public invoice/receipt PDFs.

Admin panel

Dashboard, card moderation, user block/unblock, invoice oversight, site-wide Settings singleton.

Demo accounts

admin@dirpro.demo / password & user@dirpro.demo / password seeded via DemoSeeder.

Requirements

  • — PHP 8.3+ (recommended 8.5)
  • — Composer 2.x
  • — Node.js 20+ (CI uses 24) & npm
  • — SQLite / MySQL / Postgres
  • — Git
  • — Ubuntu 24.04 for VPS deploy
1

Manual setup (local)

Fastest way to get running locally. The repo ships a convenience script that does install, env, key, migrate and build in one go.

Clone & install

Terminal bash
git clone <your-repo-url> directory-pro
cd directory-pro

# one-command setup (composer + env + key + migrate + build)
composer run setup

# alternative — step by step
composer install
cp .env.example .env
php artisan key:generate
touch database/database.sqlite   # if using sqlite
php artisan migrate --force
npm install
npm run build

The composer run setup script is defined in composer.json:scripts.setup and copies .env.example only if .env doesn't exist.

Environment essentials

Edit .env after cloning. Minimum to change:

APP_NAME="Directory Pro"
APP_URL=http://localhost:8000
APP_ENV=local
APP_DEBUG=true

DB_CONNECTION=sqlite
# For MySQL/Postgres uncomment and fill:
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=directory_pro
# DB_USERNAME=root
# DB_PASSWORD=secret

QUEUE_CONNECTION=database
SESSION_DRIVER=database
CACHE_STORE=database
MAIL_MAILER=log
VITE_APP_NAME="${APP_NAME}"

Migrate & run

# dev servers (Laravel + Vite together)
composer run dev
# or separately
php artisan serve        # http://localhost:8000
npm run dev              # Vite HMR

# production build
npm run build
php artisan optimize
php artisan storage:link

# optional demo data
php artisan db:seed --class=Database\\Seeders\\DemoSeeder
Heads up: If you see Vite manifest not found, run npm run build (or npm run dev in development). The app expects public/build/manifest.json.
2

Automated deploy — Ubuntu 24.04 VPS + GitHub Actions

The repo's .github/workflows/deploy.yml builds assets on GitHub's runner and deploys to your VPS over SSH on every push to main. It uses an atomic folder-swap strategy and preserves storage/.

Prepare the VPS (once)

  1. Provision Ubuntu 24.04, create a deploy user (e.g. deploy) with sudo, and install PHP 8.5, Composer, Nginx/Apache, MySQL/SQLite.
  2. Generate an SSH key pair for deploys: ssh-keygen -t ed25519 -C "github-deploy". Add the public key to ~/.ssh/authorized_keys on the VPS.
  3. Create the web root and env source expected by the workflow:
    sudo mkdir -p /var/www/envs
    sudo chown $USER:$USER /var/www/envs
    # put your production env here — never commit it
    nano /var/www/envs/.dirprodemo   # or whatever ENV_SOURCE is
  4. Configure Nginx/Apache vhost root to /var/www/dirpro-demo.top.ug/public (or your SITE_DIR).
  5. Ensure the deploy user can run git clone to your repo. For private repos add the VPS's SSH key as a deploy key or use a GIT_REMOTE with token.

Repository Variables (Settings → Secrets and variables → Actions → Variables)

Defined at the top of deploy.yml:env. Override them here — each falls back to the default shown.

Variable Default Purpose
SITE_DIR dirpro-demo.top.ug Live folder under WWW_DIR that Nginx serves
SITE_NAME dirpro-demo Temp clone dir; also names the build artifact
GIT_REMOTE github-directory-pro:top-ug/… Clone URL (SSH alias or git@github.com:…)
ENV_SOURCE envs/.dirprodemo Path relative to WWW_DIR with production .env
WWW_DIR /var/www Base directory on VPS
VITE_APP_NAME — Injected at build time for Vite

Repository Secrets (same page → Secrets)

Secret Example Notes
HOST 203.0.113.10 VPS IP or hostname
USERNAME deploy SSH user
PORT 22 SSH port (custom if you changed it)
SSHKEY -----BEGIN OPENSSH… Private key (paste full file incl. header/footer)
Add them via GitHub → your repo → Settings → Secrets and variables → Actions → New repository secret / variable. Secrets are never echoed in logs.

What the workflow does (on push to main)

  1. Build on CI: setup-php 8.5 + setup-node 24 → composer install → npm install && npm run build. Saves VPS CPU.
  2. Copy assets: public/build is SCP'd to /tmp/<SITE_NAME>-build on the VPS before cloning, so no Vite build needed on the server.
  3. Fresh clone: Removes $WWW_DIR/$SITE_NAME, runs git clone $GIT_REMOTE $SITE_NAME and copies $ENV_SOURCE to .env.
  4. Install & migrate: composer install --no-dev → copy prebuilt public/build → php artisan migrate --force.
  5. Atomic swap: Moves current $SITE_DIR to $SITE_NAME_back, then promotes the new clone to $SITE_DIR; migrates storage/ from backup so uploads persist.
  6. Post-install: clear-compiled, optimize, storage:link, writes storage/app/public/installed marker, fixes permissions chgrp www-data / chmod ug+rwx.

Trigger: on.push.branches: [main]. Adjust if you deploy from another branch. Manual dispatch can be added with workflow_dispatch.

3

Configuration — .env & app settings

Infrastructure config lives in .env & config/*.php. Business logic (pricing, currency, billing toggles) lives in the database via Admin → Settings (the settings singleton).

Quick .env reference

Key Default / example Description
APP_NAME Directory Pro Shown in mails, navbar, PDF header
APP_ENV production local vs production
APP_DEBUG false Never true in production
APP_URL https://example.com Used by URL generation, mail & Vite
DB_CONNECTION sqlite / mysql Set DB_DATABASE etc. for MySQL
QUEUE_CONNECTION database Keep database unless you provision Redis
CACHE_STORE database Optional: redis
SESSION_DRIVER database —
MAIL_MAILER log / smtp Set SMTP creds if you send invoices by mail
VITE_APP_NAME "${APP_NAME}" Exposed to Vite at build time

After changing .env on the VPS run php artisan optimize:clear && php artisan optimize.

Admin → Settings (database-driven)

Visit /admin/settings as an admin user. Changes apply instantly — no redeploy needed. Secrets (iotec_client_secret, iotec_callback_secret) are stored encrypted.

Directory

  • auto_publish_cards — publish immediately vs queue for review
  • billing_enabled + free_slots_per_user + price_per_card
  • currency — UGX / USD / ITX

Invoices & payments

  • invoices_billing_enabled + free slots / price per doc
  • default_tax_rate + invoice/receipt_number_prefix
  • iotec_* — wallet, client id/secret, callback secret
The webhook POST /webhooks/iotec-pay validates X-Iotec-Signature against iotec_callback_secret. Correlation via externalId prefixes card-{id} / invoice-{id}.
4

Queue workers & scheduler on the VPS

The app uses the database queue driver by default. Jobs include mail, PDF generation and payment settlement. You also need the scheduler for queued jobs that rely on cron.

Install the queue worker (Supervisor) — queue-worker-setup.sh

Run from your project root with sudo on Ubuntu 24.04. The script installs supervisor, rewrites /etc/supervisor/supervisord.conf (minfds 10000), and creates a per-project config /etc/supervisor/conf.d/laravel-queue-<project>.conf with 2 workers as www-data.

# on the VPS, from the live folder (e.g. /var/www/dirpro-demo.top.ug)
sudo ./queue-worker-setup.sh

# what it creates (sanitized project name)
# /etc/supervisor/conf.d/laravel-queue-dirpro-demo-top-ug.conf
# command=php /var/www/dirpro-demo.top.ug/artisan queue:work --sleep=3 --tries=3 --max-time=3600
# numprocs=2, autostart=true, autorestart=true

# manage
sudo supervisorctl status
sudo supervisorctl restart laravel-queue-dirpro-demo-top-ug:*
sudo supervisorctl stop laravel-queue-dirpro-demo-top-ug:*
tail -f /var/log/supervisor/laravel-queue-dirpro-demo-top-ug.log
tail -f /var/log/supervisor/supervisord.log
If you re-clone to a new folder, re-run the script — the config name is derived from basename $(pwd) lowercased & sanitized. Alternatively use php artisan queue:work or queue:listen for development.

Enable the scheduler — cron.sh

Laravel's scheduler runs every minute. The helper script adds the cron entry for www-data (via sudo) or current user.

# from project root
sudo ./cron.sh

# verifies artisan works, then installs:
# * * * * * cd /var/www/dirpro-demo.top.ug && php artisan schedule:run >> /dev/null 2>&1

# without sudo (current user crontab)
./cron.sh   # or sudo not needed if no www-data user

# verify
sudo crontab -u www-data -l   # when installed with sudo
crontab -l                    # otherwise

The script is idempotent — it removes any previous artisan schedule:run entries before adding the new one.

5

Theming & customization — CSS variables

Directory Pro uses Flux UI + Tailwind 4 with CSS variables. No PHP needed to re-theme — edit the @theme block in resources/css/app.css or generate a full theme visually.

Generate a theme at fluxui.dev/themes

  1. Open https://fluxui.dev/themes.
  2. Pick your palette, radius, fonts and dark-mode variant visually.
  3. Copy the generated CSS — it's a drop-in @theme { … } snippet with all Flux variables.
  4. Replace the @theme + @layer theme blocks in resources/css/app.css and rebuild.
# after editing resources/css/app.css
npm run build        # production
npm run dev          # HMR while tweaking

Current variables (starter palette)

File: resources/css/app.css:11

@theme {
    --font-sans: 'Instrument Sans', ui-sans-serif, system-ui, sans-serif;
    /* map zinc → slate for a cooler neutral */
    --color-zinc-50: var(--color-slate-50);
    --color-zinc-100: var(--color-slate-100);
    /* ... zinc-200 → slate-200 through zinc-950 → slate-950 */
    --color-accent: var(--color-indigo-500);
    --color-accent-content: var(--color-indigo-600);
    --color-accent-foreground: var(--color-white);
}
@layer theme {
    .dark {
        --color-accent: var(--color-indigo-500);
        --color-accent-content: var(--color-indigo-300);
        --color-accent-foreground: var(--color-white);
    }
}

Quick tweaks

  • Change accent: --color-accent → e.g. --color-emerald-500
  • Warmer neutral: map --color-zinc-* to --color-stone-* or zinc-* itself
  • Font: change --font-sans + update vite.config.js:fonts

Pro tip

Flux tokens like --color-accent cascade to every <flux:button variant="primary">, badge, and input ring — one variable recolors the whole app.

Also see resources/views/components/app-logo.blade.php for the mark — swap the SVG or set config('app.name') via APP_NAME.

Troubleshooting

Vite manifest not found
Run npm run build locally, or ensure public/build was SCP'd during deploy. Check vite.config.js inputs.
403 / storage not linked
Run php artisan storage:link and ensure storage/ bootstrap/cache are chgrp www-data + chmod ug+rwx. Verify Nginx user is www-data.
Queue not processing
Check QUEUE_CONNECTION=database, run supervisorctl status, tail the log. Ensure php artisan migrate created jobs table.
Deploy fails on git clone
Verify GIT_REMOTE var and that the VPS SSH key is authorized on GitHub (deploy key or machine user). Test with sudo -u deploy git ls-remote $GIT_REMOTE.