Skip to content

Getting started

Tiger is a multi-tenant SaaS foundation — orgs, users, memberships, roles, auth, an admin back office, a CMS, an API layer, and theming, already built. You add features as modules; the framework lives in vendor/ and updates like any Composer package without ever eating your work.

This page is the orientation lap: what you get, then a concrete first ten minutes. It's not a reference — every section points at the guide that goes deep.

Install it

One composer create-project, then four console steps — the whole thing is on one page: Install in 60 seconds. Come back here when install:admin has printed your founding account.

What you get before you write a line

Multi-tenancy org / user / org_user — the membership row is both the tenancy boundary and the role carrier (more)
Auth email-or-username login, peppered password hashing, self-service reset, passwordless code login, TOTP 2FA, DB-backed sessions, server-authoritative auto-logout (more)
Authorization a deny-by-default Zend_Acl graph enforced by a front-controller plugin you can't forget to inherit (more)
Webservices one /api endpoint; shipping an endpoint means writing a method (more)
Admin back office a themed shell with Content, Users, Organizations, Modules, Updates, and Settings screens (more)
CMS database-driven pages / layouts / partials, versioned on every save, schedulable, tenant- and locale-aware (more)
UI vendored Bootstrap 5 — no npm, no build step — with runtime CSS-variable skins and light/dark (more)
Config a four-tier cascade whose bottom tier is a DB table, so settings change live with no deploy (more)

Everything above is substrate. Your job starts at the module.

Your first ten minutes

1. Sign in

bin/tiger install:admin created your founding org and its owner. Sign in at:

/auth/login

Email or username, plus the password you set. (If you skipped install:admin, run it now — Tiger deliberately ships with no default account.)

2. Look around the back office

/admin is the dashboard: a grid of widgets that modules register (Tiger_Dashboard), reordered and collapsed per user. A fresh install's dashboard is sparse — that's correct, nothing is hardcoded.

The sidebar is ACL-filtered live, so you only see what your role can actually reach (and only what's active — most of these are first-party modules):

Sidebar item Path What it manages
Dashboard /admin your widget grid
Content /cms/page CMS pages, layouts, partials
Articles /blog/post blog posts
Menus /cms/menu the drag-drop menu builder
Media /media uploads and storage
Users /access/user people (everyone)
Organizations /access/org tenants
Code /code the Code Area (PHP/CSS/JS snippets)
Modules /system/modules · /system/updates install/activate, and updates
Settings each module's settings page, ACL-filtered

The header carries site search, the language switcher, a light/dark toggle, the skin switcher, and your user menu. /account is the other surface — the same shell, but the menu is your stuff (profile, your organization) instead of the platform's. Admin manages everyone; the account surface manages yourself.

3. Publish a page

Go to Content → New. The editor asks for the things that actually matter:

Field Notes
title / slug the slug is the public URL — /pricing
type page, layout, partial, or block
format html, markdown, phtml, or builder (the drag-drop editor)
status draft / published / archived
published_at leave blank to publish now, or set a future time to schedule it

Save, then visit /your-slug — the front controller resolves an unclaimed URL to a published page. Every save snapshots a version you can restore, and renaming a slug leaves a 301 behind automatically. Details in CMS → Pages.

Want it at /? The admin Settings screen sets the site name and which page is served as the home page — those are rows in the config table, so the change is live on the next request with no deploy (Settings).

4. Reskin it

Open the skin switcher in the header and pick another palette. It hot-swaps with no reload, because a skin is nothing but a :root { --bs-* } CSS-variable overlay — no recompile, no node_modules. Skins resolve per-user (a cookie) and per-org (a config row), which is also how tenant branding works. See Theming & skins.

5. Scaffold a feature

vendor/bin/tiger make:module billing
vendor/bin/tiger module:activate billing

You now have a Bootstrap.php, a live controller, an example /api service, its acl.ini / routes.ini / module.ini / dependency.ini, a view script, and empty models/, migrations/, and assets/ folders in application/modules/billing/. It's reachable at /billing/ immediately — zero route registration, zero core files touched — and the scaffolded service answers a call right away:

fetch('/api', { method: 'POST', body: new URLSearchParams({
    module: 'billing', service: 'example', method: 'ping',
})}).then(r => r.json());

Activation is zero-infrastructure: no Apache/nginx edit, no DNS. Add a method to the service and it's callable — that's the whole loop.

Where to go next

  • Core concepts — the vocabulary and mental model to have before you write code: the four layers, ownership, tenancy, the config cascade, the /api message.
  • Your first module — the five-minute philosophy tour, then How to write your first module for the full walkthrough (table, service, ACL, settings, clean uninstall).
  • Building on Tiger — the hub: which guide covers which step.
  • Admin — running the site from the back office (no shell required).