Loyalora · Quickstart
Loyalora Quickstart, as shipped in the download
The QUICKSTART.txt in the download — the same steps your delivery email carries.
LOYALORA — QUICKSTART
=====================
Loyalty & rewards register. Self-hosted PHP 8 + MySQL/MariaDB or SQLite.
No Composer, no build step, no external services.
1 · WHAT YOU NEED
-----------------
* PHP 8.0 or newer with PDO (pdo_mysql or pdo_sqlite)
* MySQL/MariaDB, OR nothing at all if you use SQLite
* Any web server that serves PHP
2 · INSTALL (2 minutes)
-----------------------
a. Upload the "app" folder to your server.
b. Point a domain or subdomain at it.
c. Open it in a browser. The installer runs automatically.
d. Choose SQLite (zero config) or enter your MySQL details.
e. Create your admin account. Done.
The installer writes config.php. If you would rather write it yourself,
copy config.sample.php to config.php and fill it in.
3 · TAKE A LOOK FIRST
---------------------
With PHP on your own machine:
cd app
php -S localhost:8080
Then open http://localhost:8080 and follow the installer.
Or with Docker, from inside the app folder:
docker compose -f deploy/compose.yml up -d
Load the sample scheme from Settings -> Demo data. It contains a customer in
every state — one who can afford the top reward, one a handful of points
short, one who has redeemed before, one brand new at zero, and an inactive
customer who still holds points — plus both programme kinds running side by
side, so you can see what the register is actually for.
(demo login: admin@loyalora.app / admin123 — change it)
4 · WEB SERVER SNIPPETS
-----------------------
Apache — the shipped .htaccess handles routing. Just:
<VirtualHost *:80>
ServerName loyalty.example.com
DocumentRoot /var/www/loyalora/app
<Directory /var/www/loyalora/app>
AllowOverride All
Require all granted
</Directory>
</VirtualHost>
nginx:
server {
listen 80;
server_name loyalty.example.com;
root /var/www/loyalora/app;
index index.php;
location / { try_files $uri /index.php?$query_string; }
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
location ~ ^/(data|config\.php) { deny all; }
}
5 · FIRST FIVE MINUTES IN THE APP
---------------------------------
1. Programmes. Create one. Choose how it earns:
- points per amount spent (e.g. 1 point per unit, rounded down), or
- stamps per visit (e.g. the tenth coffee free).
Most businesses need exactly one programme.
2. Rewards. Add what the points are FOR. Points with nothing to spend them
on are just a number.
3. Customers. Add someone, or import a list you already keep (Customers ->
Import CSV — it runs a dry run first and writes nothing until you
confirm). An imported opening balance arrives as an adjustment entry
reading "Imported opening balance", because a balance is the sum of the
ledger and the ledger has to say where it came from.
4. Open a customer's card and record what they spent. You enter what
HAPPENED, never a number of points — the programme's rate decides.
5. When their balance reaches a reward, it appears on their card as
"Can have right now", redeemable in place.
6. Team. A clerk can redeem. Only a manager can ADJUST — the only entry
that creates or destroys points with nothing behind it but a reason.
6 · GOING FURTHER
-----------------
* API.md — REST API, signed webhooks, and the MCP endpoint for assistants.
* Settings -> API & Webhooks — mint a key. Choose "Read only" for anything
that should answer questions but never change anything.
* Settings -> Outbound mail — one customer's own balance, through your own
SMTP, off until you switch it on.
* The ledger (/entries) — every entry ever written, filterable, exportable.
* Points outstanding (/statement.pdf) — what the scheme owes, for the books.
* Backup & restore — JSON export always; a byte-exact .sqlite download on
SQLite installs. Restore previews the diff before it commits.
7 · HONEST LIMITS
-----------------
* Loyalora is NOT a marketing tool. No campaigns, no mailing lists, no
segments, no send-to-all — and that is a design decision, not a gap.
* It holds no card numbers, takes no payments and connects to no till.
* A balance is the sum of the ledger. There is no way to type a balance in,
on any screen or endpoint, because there is nowhere to put it.
* Entries are never edited or deleted. A mistake is corrected with a new,
opposite entry and a reason.
* Points earned are not voided when a programme is switched off or a
customer is set inactive. They were earned under the terms that applied
then, and the register does not rewrite that.
8 · SUPPORT
-----------
README.md covers the design decisions. Run `php tests/run.php` to prove the
install against its own suite — including the parallel-process race that
proves two people cannot spend the same points.
← Back to Loyalora · Manual · API · Test run