From 9aeb2d5e4b392d7f96a336949c951638f1f385fb Mon Sep 17 00:00:00 2001 From: roble Date: Mon, 8 Jun 2026 20:59:01 +0100 Subject: [PATCH] feat: enhance installation documentation and module card styling with framework badges --- docs/getting-started/installation.md | 10 +- src/components/ModuleCard.module.css | 45 ++++++++ src/components/ModuleCard.tsx | 17 +++ src/data/modules.json | 163 +++++++++++++++++++++++---- static/for-agents.md | 139 ++++++++++++++++++----- 5 files changed, 327 insertions(+), 47 deletions(-) diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index d1a2459..95e5340 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -28,13 +28,19 @@ Open the URL shown in your terminal. The setup screen will guide you through cho Using Claude Code, Cursor, or another coding agent? Paste this before you start: ``` -I'm building a SaaS with Saucebase — a modular Laravel starter kit. +I'm building a new application with Saucebase — a modular Laravel SaaS starter kit. -Read https://saucebase-dev.github.io/docs/for-agents.md for the project conventions, structure, and patterns. Treat it as the source of truth for how to add features, where files belong, and what commands to run. +Fetch and follow the instructions from https://saucebase-dev.github.io/docs/for-agents.md Treat the returned Markdown as the source of truth for how to install, set up, and build with Saucebase in this session. ``` [Read the full agent guide →](pathname:///for-agents.md) +:::warning SQLite limitations +The default installation uses SQLite, which is sufficient for basic development but does not support all features. Some Filament admin panel widgets and Billing module charts require MySQL-specific capabilities and may not display correctly with SQLite. + +For full functionality, configure the app to use **MySQL** — run it locally, or use [Laravel Herd](https://herd.laravel.com), [Laravel Sail](https://laravel.com/docs/sail), or Docker (`bash bin/setup-env`). +::: + = { @@ -45,6 +46,11 @@ function resolveDependencyTitle(id: string): string { return mod ? mod.title : id; } +const FRAMEWORK_LABELS: Record = { + vue: 'Vue', + react: 'React', +}; + export default function ModuleCard({ title, description, @@ -55,6 +61,7 @@ export default function ModuleCard({ href, features = [], dependencies = [], + frameworks = [], }: ModuleCardProps): JSX.Element { const coverStyle = !coverImage ? { background: `linear-gradient(135deg, ${color}88, ${color}33)` } @@ -84,6 +91,16 @@ export default function ModuleCard({

{title}

{description}

+ {frameworks.length > 0 && ( +
+ {frameworks.map(fw => ( + + {FRAMEWORK_LABELS[fw] ?? fw} + + ))} +
+ )} + {features.length > 0 && (
{features.map(feature => ( diff --git a/src/data/modules.json b/src/data/modules.json index ee74988..08b0ac5 100644 --- a/src/data/modules.json +++ b/src/data/modules.json @@ -70,6 +70,7 @@ "logo": "lucide:lock", "badge": "free", "href": "/modules/auth", + "frameworks": ["vue", "react"], "features": [ { "icon": "lucide:log-in", @@ -112,6 +113,7 @@ "logo": "lucide:settings-2", "badge": "free", "href": "/modules/settings", + "frameworks": ["vue"], "features": [ { "icon": "lucide:user", @@ -148,6 +150,7 @@ "logo": "lucide:credit-card", "badge": "free", "href": "/modules/billing", + "frameworks": ["vue"], "features": [ { "icon": "lucide:shopping-cart", @@ -174,7 +177,7 @@ "details": "Payment events are verified and processed reliably. Duplicate events are safely ignored, and failed payments update subscription status automatically." } ], - "dependencies": ["auth"] + "dependencies": ["auth", "settings"] }, { "id": "roadmap", @@ -184,6 +187,7 @@ "logo": "lucide:map", "badge": "free", "href": "/modules/roadmap", + "frameworks": ["vue"], "features": [ { "icon": "lucide:lightbulb", @@ -220,6 +224,7 @@ "logo": "lucide:megaphone", "badge": "free", "href": "/modules/announcements", + "frameworks": ["vue"], "features": [ { "icon": "lucide:layout-template", @@ -262,6 +267,7 @@ "logo": "lucide:palette", "badge": "free", "href": "/modules/themes", + "frameworks": ["vue"], "features": [ { "icon": "lucide:palette", @@ -296,8 +302,9 @@ "description": "Full-featured blog with posts, categories, tags, and a Filament admin panel for content management.", "color": "#ec4899", "logo": "lucide:newspaper", - "badge": "coming-soon", - "href": "#", + "badge": "new", + "href": "/modules/blog", + "frameworks": ["vue"], "features": [ { "icon": "lucide:file-text", @@ -327,34 +334,152 @@ "dependencies": ["auth"] }, { - "id": "teams", - "title": "Teams", - "description": "Multi-user team collaboration with role-based permissions, invitations, and team switching for B2B SaaS applications.", + "id": "webhooks", + "title": "Webhooks", + "description": "Send reliable HTTP callbacks to external services when events occur in your app, with delivery logs and retry handling.", "color": "#6b7280", - "logo": "lucide:users", + "logo": "lucide:webhook", "badge": "coming-soon", "href": "#", + "frameworks": ["vue"], "features": [ { - "icon": "lucide:users", - "name": "Team Collaboration", - "description": "Multi-user teams", - "details": "Users can create and switch between multiple teams. All data is automatically scoped to the active team, making it straightforward to build B2B multi-tenant applications." + "icon": "lucide:zap", + "name": "Event Triggers", + "description": "Fire webhooks on any app event", + "details": "Register listeners for any application event and automatically dispatch an HTTP POST to configured endpoints. Supports custom payloads and per-event endpoint routing." }, { - "icon": "lucide:key", - "name": "Role Permissions", - "description": "Role-based access control", - "details": "Built-in owner, admin, and member roles with permission checks via `$user->hasTeamPermission('billing')`. Role definitions are customizable to match your application's needs." + "icon": "lucide:list", + "name": "Delivery Logs", + "description": "Inspect every webhook attempt", + "details": "Every delivery attempt is logged with the request body, response status, and latency. Browse the full history from the admin panel to diagnose issues." + }, + { + "icon": "lucide:refresh-cw", + "name": "Retry Handling", + "description": "Automatic retries with exponential backoff", + "details": "Failed deliveries are retried automatically with exponential backoff. You can also trigger a manual retry from the delivery log for any failed attempt." }, { - "icon": "lucide:mail-plus", - "name": "Invitations", - "description": "Team invitations by email", - "details": "Invite users to a team by email. Invited users receive an email with an accept link. Pending invitations are managed from the team settings page and expire after 7 days." + "icon": "lucide:bell-off", + "name": "Failure Alerts", + "description": "Get notified when deliveries fail repeatedly", + "details": "After a configurable number of consecutive failures, an alert is sent to the team. Endpoints can be temporarily disabled to prevent noise during known outages." } ], "dependencies": ["auth"] + }, + { + "id": "integrations", + "title": "Integrations", + "description": "Connect your app with third-party services like Slack, Zapier, and more through a unified integration layer.", + "color": "#6b7280", + "logo": "lucide:blocks", + "badge": "coming-soon", + "href": "#", + "frameworks": ["vue"], + "features": [ + { + "icon": "lucide:slack", + "name": "Slack", + "description": "Send notifications to Slack channels", + "details": "Post messages to any Slack channel when events occur in your app. Supports custom message formatting, channel routing per event type, and OAuth app installation." + }, + { + "icon": "lucide:webhook", + "name": "Zapier", + "description": "Trigger Zapier workflows from your app", + "details": "Connect to thousands of apps via Zapier triggers. Any event in your app can kick off a Zapier workflow without custom code." + }, + { + "icon": "lucide:plug", + "name": "Custom Connections", + "description": "Build your own integration adapters", + "details": "A driver-based integration layer lets you implement custom adapters for any third-party service. Register them alongside the built-in drivers with no framework changes." + }, + { + "icon": "lucide:layers", + "name": "Unified Layer", + "description": "One API for all integrations", + "details": "All integrations share a common interface for connecting, sending events, and handling credentials. Switching or adding providers requires no changes to your event code." + } + ], + "dependencies": ["auth"] + }, + { + "id": "notifications", + "title": "Notifications", + "description": "In-app and email notifications with templates, user preferences, and delivery tracking for every channel.", + "color": "#6b7280", + "logo": "lucide:bell", + "badge": "coming-soon", + "href": "#", + "frameworks": ["vue"], + "features": [ + { + "icon": "lucide:bell", + "name": "In-App", + "description": "Real-time notifications inside the app", + "details": "Notifications appear in a dropdown bell menu and are marked read on open. Unread count is updated in real time via broadcasting without a full page reload." + }, + { + "icon": "lucide:mail", + "name": "Email", + "description": "Transactional email notifications", + "details": "Each notification type has a corresponding email template. Emails are queued and sent via Laravel's mail system — swap the driver (SMTP, Mailgun, SES) in the config." + }, + { + "icon": "lucide:file-text", + "name": "Templates", + "description": "Editable notification templates", + "details": "In-app and email notification content is defined in template classes. Subject, body, and action URL are customizable per notification type without touching core code." + }, + { + "icon": "lucide:sliders-horizontal", + "name": "Preferences", + "description": "Per-channel user preferences", + "details": "Users control which notifications they receive and on which channels from a preferences page. Preferences are evaluated before dispatch — muted channels are skipped entirely." + } + ], + "dependencies": ["auth"] + }, + { + "id": "analytics", + "title": "Analytics", + "description": "Track pageviews, custom events, and user behavior with a privacy-friendly built-in dashboard — no third-party scripts.", + "color": "#6b7280", + "logo": "lucide:bar-chart-3", + "badge": "coming-soon", + "href": "#", + "frameworks": ["vue"], + "features": [ + { + "icon": "lucide:eye", + "name": "Pageviews", + "description": "Automatic pageview tracking", + "details": "Every page navigation is tracked automatically via an Inertia event listener. No script tags or manual calls needed — views are recorded server-side with referrer and path." + }, + { + "icon": "lucide:mouse-pointer-click", + "name": "Custom Events", + "description": "Track any user action", + "details": "Fire custom events from anywhere in the frontend with a single helper call. Events are batched and sent to a lightweight endpoint that writes them to the analytics store." + }, + { + "icon": "lucide:layout-dashboard", + "name": "Dashboard", + "description": "Built-in analytics dashboard", + "details": "A Filament dashboard page visualises pageviews, unique visitors, top pages, and custom event counts over configurable date ranges. No third-party service required." + }, + { + "icon": "lucide:shield", + "name": "Privacy First", + "description": "No cookies, no third-party scripts", + "details": "All data is stored in your own database. No cookies are set, no external scripts are loaded, and no personal data leaves your server — fully GDPR-compliant by default." + } + ], + "dependencies": [] } ] } diff --git a/static/for-agents.md b/static/for-agents.md index 3b70fcc..ea72713 100644 --- a/static/for-agents.md +++ b/static/for-agents.md @@ -1,13 +1,13 @@ # Saucebase for Agents -This page is for AI coding agents helping a developer work on a Saucebase project. +This page is for AI coding agents helping a developer start or work on a Saucebase application. ## How to Proceed - First, check whether the current directory already contains a Saucebase application (look for `artisan` and `frontend.json`). -- If it does, skip installation and read the conventions below before writing any code. -- If it does not, verify that `php`, `composer`, and the Laravel installer CLI (`laravel`) are available. -- If any are missing, refer the user to [laravel.com/docs/installation](https://laravel.com/docs/installation) before continuing. +- If it does, check `frontend.json` for the active framework, then skip to the user's requested task. +- If it does not, verify that `php`, `composer`, the Laravel installer CLI (`laravel`), and `node` are available. +- If any are missing, use `php.new` to install them using the correct platform command below. ## Prerequisites @@ -18,7 +18,39 @@ Run quick version checks for: - `laravel --version` - `node -v` (need 22+) -If any are missing, tell the user to install them before continuing. +If `PHP`, `Composer`, or the Laravel installer are missing, use `php.new` to install them before continuing. + +If `node` is missing or below 22, install it with `nvm`: + +```shell +nvm install 22 && nvm use 22 +``` + +If `nvm` is not available, ask the user to install Node 22 from [nodejs.org](https://nodejs.org) before continuing. + +## Installing with php.new + +If `php`, `composer`, or `laravel` are missing, use `php.new` to install them. + +- macOS: + +```shell +/bin/bash -c "$(curl -fsSL https://php.new/install/mac/8.4)" +``` + +- Windows PowerShell: + +```powershell +Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://php.new/install/windows/8.4')) +``` + +- Linux: + +```shell +/bin/bash -c "$(curl -fsSL https://php.new/install/linux/8.4)" +``` + +After running one of these commands, tell the user to restart their terminal session before continuing. If the agent needs the restarted shell to pick up the new tools, tell the user to re-run their original prompt after reopening the terminal. ## Create the Application @@ -26,11 +58,67 @@ If any are missing, tell the user to install them before continuing. laravel new my-app --using=saucebase/saucebase --phpunit --boost ``` -`--phpunit` is required — Saucebase uses PHPUnit and the test suite will break if Pest is chosen. `--boost` confirms the Boost installation already bundled in `composer.json` and skips the prompt. +`--phpunit` is required — Saucebase uses PHPUnit and the test suite will break if Pest is chosen. `--boost` confirms the Boost installation already bundled in `composer.json` and skips the interactive prompt. + +Once the application is created, load the `CLAUDE.md` or `AGENTS.md` in the project root immediately to pick up project-specific conventions for the session. Do not ask the user to restart. + +## After Creation + +Once the application has been created: + +1. Enter the new project directory: `cd my-app` +2. Start the development server: + +```shell +composer dev +``` + +This runs the HTTP server, queue worker, and Vite asset pipeline in parallel. + +The agent should avoid getting blocked by the long-running dev server. If it can manage the process in the background, that is fine; otherwise ask the user to keep `composer dev` running in a separate terminal while continuing with setup. + +3. Tell the user the application will be available at `http://localhost:8000` (or the URL printed by `composer dev`). +4. Ask the user to open that URL — a **setup screen** will appear. +5. Do not write any frontend code until the user has completed the setup screen. + +## Setup Screen + +The setup screen handles the remaining configuration steps — the agent should not attempt to replicate these manually: + +- **Framework choice:** The user selects Vue 3 or React. This writes `frontend.json` to the project root. +- **Module installation:** The user installs the modules they want (Auth, Billing, Settings, etc.). Modules are copied into `modules/` via Composer. -Open the URL shown in the terminal. The setup screen guides the user through choosing a frontend framework and installing modules. Do not run any further commands — the setup screen handles the remaining steps. +Once the user confirms the setup screen is complete: + +- Read `frontend.json` to detect the active framework before writing any frontend code. +- Run `php artisan modules:list` to see which modules are installed. +- If the Auth module was installed: the admin panel is at `/admin` with default credentials `chef@saucebase.dev` / `secretsauce`. Ask the user to verify it loads. + +## Guidance + +- Ask only for decisions that materially affect the application — framework choice and which modules to install are the only required choices during setup. +- Prefer Saucebase defaults when the user has not expressed a preference. +- Keep setup moving unless blocked by a missing dependency or an explicit choice the user must make. +- Never write frontend code before `frontend.json` exists with a `"framework"` key — the setup screen has not completed yet. +- Check `modules/` before assuming a feature does not exist — it may already be in an installed module. +- When adding a migration, run `php artisan migrate` after creating it. +- Commit messages follow the format `type(scope): subject` — all lowercase, max 150 chars. -## Detecting the Active Framework +## Example Outcome + +When everything is ready, the agent should leave the user with a Saucebase application running at `http://localhost:8000`, a dev server in their terminal, and a completed setup screen. Tell the user what framework and modules are active, then ask what they want to build. + +## Shipping to Production + +When the user is ready to deploy, [Laravel Forge](https://forge.laravel.com) and [Laravel Cloud](https://cloud.laravel.com) are the recommended hosting options for Saucebase applications. + +--- + +## Conventions Reference + +The sections below are reference material. Consult them while building features, not during initial setup. + +### Detecting the Active Framework Always check `frontend.json` at the project root before writing any frontend code: @@ -40,9 +128,9 @@ Always check `frontend.json` at the project root before writing any frontend cod - `"framework": "vue"` — write Vue 3 Composition API (`.vue` files, `