From dd7a674c4d6056f6b433653c42025a9f0e0c99eb Mon Sep 17 00:00:00 2001 From: "Beau Beauchamp, WebTigers" Date: Fri, 17 Jul 2026 15:10:04 -0400 Subject: [PATCH] Marketing pages: home refresh + /vibe + /agency, and a Solutions mega-menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restructure the shipped marketing surface into audience pages, all static and part of tiger-core (included in every download): - New home (/) — an elegant, lean landing that positions Tiger broadly and surfaces three audience paths (Build Killer Websites -> /cms, Vibe SaaS Startups -> /vibe, Agency Friendly -> /agency) plus the core feature grid. A placeholder for a fuller redesign later. - /vibe — the former home content, repositioned as the SaaS-startup / vibe-coding pitch (IndexController::vibeAction + index/vibe.phtml). - /agency — new: the agency story (one client or a hundred, white-label per tenant, jumpstart every project) (IndexController::agencyAction + index/agency.phtml). - Solutions mega-menu — static HTML injected into the first header dropdown (puma public-header.phtml): a 2x2 card panel linking to /cms, /agency, /vibe, and a ghost "what else could go here" placeholder. Wide panel on desktop, stacks on mobile. Pretty routes /vibe + /agency are static exact-path routes into the default-namespace IndexController (Tiger_Application_Bootstrap::_initMarketingAliases, same pattern as the /login + /logout auth aliases). /cms is the CMS module's own public page. Smoke asserts /vibe + /agency return 200 and the home carries the mega-menu + audience links. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/smoke.yml | 10 + core/controllers/IndexController.php | 21 ++ core/views/scripts/index/agency.phtml | 113 +++++++ core/views/scripts/index/index.phtml | 241 +++------------ core/views/scripts/index/vibe.phtml | 286 ++++++++++++++++++ library/Tiger/Application/Bootstrap.php | 19 ++ .../scripts/_partials/public-header.phtml | 60 ++++ 7 files changed, 547 insertions(+), 203 deletions(-) create mode 100644 core/views/scripts/index/agency.phtml create mode 100644 core/views/scripts/index/vibe.phtml diff --git a/.github/workflows/smoke.yml b/.github/workflows/smoke.yml index e58169a..43aca62 100644 --- a/.github/workflows/smoke.yml +++ b/.github/workflows/smoke.yml @@ -143,10 +143,20 @@ jobs: check "landing /" 200 "http://127.0.0.1:8000/" check "login /login" 200 "http://127.0.0.1:8000/login" + check "marketing /vibe" 200 "http://127.0.0.1:8000/vibe" + check "marketing /agency" 200 "http://127.0.0.1:8000/agency" check "/api gateway alive" 200 "http://127.0.0.1:8000/api" check "unknown slug 404" 404 "http://127.0.0.1:8000/no-such-page-xyzzy" check "org-scoped CMS page" 200 "http://127.0.0.1:8000/ci-smoke-page" + # The home page must carry the Solutions mega-menu (its cards link to the marketing pages). + curl -s "http://127.0.0.1:8000/" >home.html || true + if grep -q 'tiger-mega' home.html && grep -q 'href="/vibe"' home.html && grep -q 'href="/agency"' home.html; then + echo "PASS home carries the Solutions mega-menu + audience links" + else + echo "FAIL home missing mega-menu / audience links"; fail=1 + fi + # The seeded page (org_id = the site org) must actually DISPATCH — its body has to render, not a # 404 shell. This is the guard for the org_id write-stamp ↔ read-scope path: a mismatch 404s here. curl -s "http://127.0.0.1:8000/ci-smoke-page" >page.html || true diff --git a/core/controllers/IndexController.php b/core/controllers/IndexController.php index ecd2c0d..abbdb7a 100644 --- a/core/controllers/IndexController.php +++ b/core/controllers/IndexController.php @@ -42,6 +42,27 @@ public function indexAction() $this->view->zendVersion = Zend_Version::VERSION; } + /** + * `/vibe` — the SaaS-startup / "vibe coding" pitch (the former home page). A shipped marketing + * page; the view owns its content. Routed via _initMarketingAliases. + * + * @return void + */ + public function vibeAction() + { + // view: index/vibe.phtml — nothing to wire; it's static marketing. + } + + /** + * `/agency` — the agency story (one client or a hundred). A shipped marketing page. + * + * @return void + */ + public function agencyAction() + { + // view: index/agency.phtml + } + /** The configured home-page id (tiger.site.home_page), or '' for the built-in landing. */ protected function _homePageId() { diff --git a/core/views/scripts/index/agency.phtml b/core/views/scripts/index/agency.phtml new file mode 100644 index 0000000..e57f42e --- /dev/null +++ b/core/views/scripts/index/agency.phtml @@ -0,0 +1,113 @@ +title = 'Agency friendly — host hundreds of client sites | Tiger'; + +$benefits = [ + ['fa-diagram-project', 'One install, many tenants', 'Every client is an org on the same platform — isolated data, their own users and roles, their own theme and content. Add a client, not a server.'], + ['fa-gauge-high', 'Jumpstart every project', 'New client on Monday, a running multi-tenant site the same day. Skip the auth/roles/CMS boilerplate you rebuild on every engagement and go straight to their brief.'], + ['fa-palette', 'White-label per client', 'Theme and skin resolve per org, so each client sees their brand — not yours, and not a template. Swap looks live with no redeploy.'], + ['fa-user-shield', 'Scoped access, safely', 'Deny-by-default ACL with roles on the membership. Give a client access to their org and nothing else; add a teammate as manager here, viewer there.'], + ['fa-server', 'Runs where you host', 'cPanel, a $5 VPS, or a fleet behind a load balancer — zero build step, tiny footprint. Host hundreds of sites without a hosting bill that eats the margin.'], + ['fa-sliders', 'Live config, no deploys', 'Change a client\'s settings, copy, or branding from the admin — the config and translation tiers override at request time, so edits ship without a release.'], +]; +?> + +
+
+ + For agencies & freelancers + +

One client, or a hundred.

+

+ Tiger is multi-tenant to the core, so a single install runs all your client sites — each + isolated, white-labeled, and managed from one back office. Jumpstart every project and + keep the margin the hosting bill used to eat. +

+ +
+
+ + +
+
+
+
+
+
+ +

Solo & single-client

+

+ Stand up a polished, secure site for one client without wiring auth, roles, and a + CMS from scratch. Everything's included — you focus on their brief, not the boilerplate. +

+
+
+
+
+
+
+ +

Multi-client at scale

+

+ Run your whole book on one platform — every client an isolated tenant with its own + users, roles, theme, and content, all from a single admin. Add the next client in minutes. +

+
+
+
+
+
+
+ + +
+
+
+

Built for the way agencies actually work

+

Isolated tenants, white-label branding, live config — no per-client rebuild.

+
+
+ +
+
+
+
+ +
+

escape($b[1]) ?>

+

escape($b[2]) ?>

+
+
+
+ +
+
+
+ + +
+
+
+
+

Turn your next client into a tenant

+

One command scaffolds a running, themed, multi-tenant platform you can grow onto.

+
+ $ composer create-project webtigers/tiger my-agency
+ $ cd my-agency && vendor/bin/tiger install:admin +
+ +
+
+
+
diff --git a/core/views/scripts/index/index.phtml b/core/views/scripts/index/index.phtml index b5467b0..4ea39d5 100644 --- a/core/views/scripts/index/index.phtml +++ b/core/views/scripts/index/index.phtml @@ -2,21 +2,30 @@ // SPDX-License-Identifier: BSD-3-Clause // Copyright (c) 2026 WebTigers. Tiger™ and WebTigers™ are trademarks of WebTigers. /** - * Public landing page. Rendered inside the PUMA public layout (header + footer). - * Bootstrap + --bs-* tokens, so it restyles live with the theme (light/dark) and the - * active skin — the switchers in the header change this page with no reload. + * Public home page. Rendered inside the PUMA public layout (header + footer). Bootstrap + + * --bs-* tokens, so it restyles live with the theme (light/dark) and the active skin. + * + * A deliberately lean "surface the major points" home — a placeholder for a fuller redesign. + * It positions Tiger, points at the three audience pages (/cms, /vibe, /agency), and shows the + * core feature grid. The audience cards mirror the header's Solutions mega-menu. */ -$this->title = 'Tiger — a 1-click SaaS platform on TigerZF'; +$this->title = 'Tiger — one platform: sites, SaaS, and client work'; + +$paths = [ + ['fa-wand-magic-sparkles', 'Build killer websites', 'No WordPress® required', '/cms', 'A database-driven CMS with layouts, menus, versioning, and a visual builder — themeable, multi-tenant, fast.'], + ['fa-rocket', 'Vibe SaaS startups', 'A secure MVP in minutes, not days','/vibe', 'Auth, orgs, roles, and a clean /api from the first commit — so you and your AI pair ship product, not plumbing.'], + ['fa-people-group', 'Agency friendly', 'Host hundreds of sites', '/agency', 'One install, many tenants. Jumpstart every client project and run them all from a single back office.'], +]; $features = [ - ['fa-layer-group', 'Front-end agnostic', 'Server-rendered .phtml or any SPA (React, Vue, …) against one JSON /api. The core ships no UI framework — build the front end however you like.'], - ['fa-building', 'Multi-tenant by default', 'Orgs, users, and memberships out of the box. A user can be admin in one org and viewer in another — roles live on the membership.'], - ['fa-bolt', 'Zero build toolchain', 'No npm, no webpack, no Sass. composer install and the UI renders. Assets are vendored; a build tool only appears if a theme opts in.'], - ['fa-language', 'i18n with live overrides', 'Semantic keys, language-only locales, /es/ URLs. Change any string in production with no deploy — same for config.'], - ['fa-shield-halved', 'Auth & ACL included', 'Password policy, lockout, DB sessions, an audit log, and a deny-by-default ACL with live, per-tenant roles.'], - ['fa-cloud', 'Pluggable logging', 'Structured JSON logs to error_log, stderr, syslog — or straight to CloudWatch / GCP / Azure. Switch with one config line.'], - ['fa-palette', 'Live theming & skins', 'Light/dark and swappable skins that hot-swap with no reload — per user and per org. Try the switchers above ↑'], - ['fa-terminal', 'Batteries-included CLI', 'bin/tiger migrate, install:admin, make:module — scaffold a live module (controller + /api service + ACL) in seconds.'], + ['fa-layer-group', 'Front-end agnostic', 'Server-rendered .phtml or any SPA against one JSON /api. The core ships no UI framework.'], + ['fa-building', 'Multi-tenant by default', 'Orgs, users, and memberships out of the box — roles live on the membership, not the user.'], + ['fa-bolt', 'Zero build toolchain', 'No npm, no webpack, no Sass. composer install and the UI renders. Assets are vendored.'], + ['fa-shield-halved', 'Auth & ACL included', 'Password policy, lockout, DB sessions, an audit log, and a deny-by-default, per-tenant ACL.'], + ['fa-language', 'i18n + live overrides', 'Semantic keys, /es/ URLs, and any string or config changed in production with no deploy.'], + ['fa-gauge-high', 'Built for speed', 'A lean core — OPcache-tuned, tiny footprint. Flies on a $5 shared host, not just a big server.'], + ['fa-palette', 'Live theming & skins', 'Light/dark and swappable skins that hot-swap with no reload — per user and per org.'], + ['fa-terminal', 'Batteries-included CLI', 'bin/tiger migrate, install:admin, make:module — scaffold a live module in seconds.'], ]; ?> @@ -25,11 +34,11 @@ $features = [ Built on TigerZF · ZendFramework 1 for modern PHP -

Build the SaaS, not the plumbing.

-

- Tiger is a 1-click, multi-tenant SaaS foundation for PHP — auth, orgs, roles, theming, - i18n, and a clean /api — so you ship product from day one. Front-end - agnostic, zero build step. +

One platform. Sites, SaaS, and client work.

+

+ Tiger is a 1-click, multi-tenant foundation for PHP — auth, orgs, roles, a CMS, theming, + i18n, and a clean /api. Whether you're building a website, a SaaS, or a hundred + client sites, you start with product, not plumbing.

- +
- - -
-
-
+

Everything a SaaS needs, none of the busywork

@@ -178,92 +99,6 @@ $features = [
- -
-
-
- - Webservices — the TIGER pattern - -

REST without the bloat

-

- One endpoint. The message says where it's going. Add a method and it's live — no route - to design, no verb to argue about, no endpoint zoo to maintain. -

-
-
-
-
-
-
- -
-
-

One endpoint, not 50

-

- A single /api. The module + service + - method ride in the message, so a new call is a new method — - not a new route, a new controller, and a new version to babysit. -

-
-
-
-
-
-
-
-
- -
-
-

Secured by ACL

-

- Every call is authorized before it runs — deny-by-default, resource = - the service, privilege = the method. Auth isn't a check you can forget to write; - it's the gateway you can't route around. -

-
-
-
-
-
-
-
-
- -
-
-

Stateless or stateful

-

- Ride the session for a first-party UI, or go token-based and stateless for a public - API or a mobile client — the same services answer either way. Pick the model - per surface, not per framework. -

-
-
-
-
-
-
-
-
- -
-
-

Discoverable by design

-

- Because routing is data in the message, the API can describe itself — versioned - services and an OpenAPI / Swagger catalog fall out of the pattern, not a bolt-on spec - you keep in sync by hand. -

-
-
-
-
-
-
-
-
diff --git a/core/views/scripts/index/vibe.phtml b/core/views/scripts/index/vibe.phtml new file mode 100644 index 0000000..2e03768 --- /dev/null +++ b/core/views/scripts/index/vibe.phtml @@ -0,0 +1,286 @@ +title = 'Vibe SaaS Startups — a secure MVP in minutes | Tiger'; + +$features = [ + ['fa-layer-group', 'Front-end agnostic', 'Server-rendered .phtml or any SPA (React, Vue, …) against one JSON /api. The core ships no UI framework — build the front end however you like.'], + ['fa-building', 'Multi-tenant by default', 'Orgs, users, and memberships out of the box. A user can be admin in one org and viewer in another — roles live on the membership.'], + ['fa-bolt', 'Zero build toolchain', 'No npm, no webpack, no Sass. composer install and the UI renders. Assets are vendored; a build tool only appears if a theme opts in.'], + ['fa-language', 'i18n with live overrides', 'Semantic keys, language-only locales, /es/ URLs. Change any string in production with no deploy — same for config.'], + ['fa-shield-halved', 'Auth & ACL included', 'Password policy, lockout, DB sessions, an audit log, and a deny-by-default ACL with live, per-tenant roles.'], + ['fa-cloud', 'Pluggable logging', 'Structured JSON logs to error_log, stderr, syslog — or straight to CloudWatch / GCP / Azure. Switch with one config line.'], + ['fa-palette', 'Live theming & skins', 'Light/dark and swappable skins that hot-swap with no reload — per user and per org. Try the switchers above ↑'], + ['fa-terminal', 'Batteries-included CLI', 'bin/tiger migrate, install:admin, make:module — scaffold a live module (controller + /api service + ACL) in seconds.'], +]; +?> + +
+
+ + For vibe coders & SaaS founders + +

A secure MVP in minutes, not days.

+

+ Tiger hands you the boring-but-essential SaaS substrate — auth, orgs, roles, billing-ready + multi-tenancy, i18n, and a clean /api — so you and your AI pair ship + product from the first commit. Predictable patterns your assistant reads before it + writes, so the vibe code doesn't rot. +

+ +

+ + Flip light/dark or the skin in the header — this page restyles live, no reload. +

+
+
+ + +
+
+
+
+
+
+ +

Startup-friendly

+

+ Zero to a running, themed, multi-tenant app in one command — on a $0 stack if you + want. No infra to stand up, no boilerplate to write. Spend your runway on product, + not plumbing. +

+
+
+
+
+
+
+ +

Enterprise-class MVPs

+

+ Auth, role-based access, audit logging, multi-tenancy, i18n, and live config — the + substrate enterprises spend months on — ship with your first commit. Your MVP is + production-shaped out of the gate. +

+
+
+
+
+
+
+ +

Structured for vibe coding

+

+ Predictable patterns, docs that live in the code, and an AGENTS.md your + AI assistant reads before it writes. Describe what you want and let the conventions + keep it clean — vibe code that doesn't rot. +

+
+
+
+
+
+
+ + +
+
+
+
+
+
+ +

Built for speed

+
runs on
+
PHP 8.x+
+

+ A lean core with no per-request framework bloat — zero build step, tiny memory + footprint, OPcache-tuned. Flies on a $5 shared host, not just a beefy server. + Fast is the default, not an upgrade. +

+
+
+
+
+
+
+ +

The numbers don't lie

+
responds in
+
~10 ms
+

+ Steady at the median, the 95th, and the 99th percentile — the tail + stays flat under load, not just on a quiet box. That's the raw cost of generating a + real page, with no output cache and no tricks. Consistent, with zero errors. +

+
+
+
+
+
+
+ +

The competition

+
up to
+
3–10×
+

+ faster than Laravel, Next.js, or Django + ORM at generating the same + dynamic page — most of their time is framework plumbing, not your code. And + Tiger does it on a $5 shared host those stacks can't even run on. Lean beats heavy. +

+
+
+
+
+
+
+

+ ~10 ms measured (single warm request, 2‑vCPU box, PHP 8 + OPcache). Multipliers reflect + typical per‑request generation times for an equivalent dynamic page vs. mainstream framework + defaults — not a controlled benchmark; results vary by workload and hardware. +

+
+
+
+
+ + +
+
+
+

Everything a SaaS needs, none of the busywork

+

The boring-but-essential substrate, done right.

+
+
+ +
+
+
+
+ +
+

escape($f[1]) ?>

+

escape($f[2]) ?>

+
+
+
+ +
+
+
+ + +
+
+
+ + Webservices — the TIGER pattern + +

REST without the bloat

+

+ One endpoint. The message says where it's going. Add a method and it's live — no route + to design, no verb to argue about, no endpoint zoo to maintain. +

+
+
+
+
+
+
+ +
+
+

One endpoint, not 50

+

+ A single /api. The module + service + + method ride in the message, so a new call is a new method — + not a new route, a new controller, and a new version to babysit. +

+
+
+
+
+
+
+
+
+ +
+
+

Secured by ACL

+

+ Every call is authorized before it runs — deny-by-default, resource = + the service, privilege = the method. Auth isn't a check you can forget to write; + it's the gateway you can't route around. +

+
+
+
+
+
+
+
+
+ +
+
+

Stateless or stateful

+

+ Ride the session for a first-party UI, or go token-based and stateless for a public + API or a mobile client — the same services answer either way. Pick the model + per surface, not per framework. +

+
+
+
+
+
+
+
+
+ +
+
+

Discoverable by design

+

+ Because routing is data in the message, the API can describe itself — versioned + services and an OpenAPI / Swagger catalog fall out of the pattern, not a bolt-on spec + you keep in sync by hand. +

+
+
+
+
+
+
+
+ + +
+
+
+
+

Spin up your app in minutes

+

One command scaffolds a running, themed, multi-tenant app.

+
+ $ composer create-project webtigers/tiger my-app
+ $ cd my-app && vendor/bin/tiger install:admin +
+ +
+
+
+
diff --git a/library/Tiger/Application/Bootstrap.php b/library/Tiger/Application/Bootstrap.php index 17be466..0af25b8 100644 --- a/library/Tiger/Application/Bootstrap.php +++ b/library/Tiger/Application/Bootstrap.php @@ -98,6 +98,25 @@ protected function _initAuthAliases() )); } + /** + * Pretty aliases for the shipped marketing pages (IndexController actions): `/vibe` (SaaS-startup + * pitch — the former home) and `/agency` (the agency story). Static exact-path routes into the + * default-namespace IndexController, same pattern as the auth aliases. The canonical /index/* + * paths keep working; `/cms` is the CMS module's own public page (no alias needed). + */ + protected function _initMarketingAliases() + { + $this->bootstrap('frontController'); + $router = $this->getResource('frontController')->getRouter(); + + $router->addRoute('tiger_vibe', new Zend_Controller_Router_Route_Static( + 'vibe', ['module' => 'default', 'controller' => 'index', 'action' => 'vibe'] + )); + $router->addRoute('tiger_agency', new Zend_Controller_Router_Route_Static( + 'agency', ['module' => 'default', 'controller' => 'index', 'action' => 'agency'] + )); + } + /** * AUTHORIZATION: build the ACL (Tiger_Acl_Acl loads roles/resources/rules from * ini + DB) and register the unbypassable gate (Tiger_Controller_Plugin_ diff --git a/themes/puma/views/scripts/_partials/public-header.phtml b/themes/puma/views/scripts/_partials/public-header.phtml index 2c5859d..ceef4e6 100644 --- a/themes/puma/views/scripts/_partials/public-header.phtml +++ b/themes/puma/views/scripts/_partials/public-header.phtml @@ -19,6 +19,14 @@ $identity = Zend_Auth::getInstance()->hasIdentity() ? Zend_Auth::getInstance()->getIdentity() : null; $authRegion = $this->placeholder('tigerHeaderAuth'); ?> +