34 KiB
Growup Pro - Krayin CRM Whitelabel Multi-tenant
Project Overview
Growup Pro is a whitelabel implementation of Krayin Laravel CRM with multi-tenancy support. The platform allows multiple companies/organizations to use the same CRM instance with complete data isolation through subdomain-based tenancy.
CURRENT STATUS: DEBUGGING PHASE
- Multi-tenancy implementation: Installed but encountering issues.
- Issue 1:
localhostnot recognized as central domain (TenantCouldNotBeIdentifiedOnDomainException). - Issue 2: Tenant instances (
tenant1.localhost) load but missing CSS (Asset 404). - Goal: Fix central domain detection and static asset serving for tenants.
Key Differentiators from Krayin
- Rebranding: Complete visual overhaul with Growup Pro branding
- Multi-tenancy: Isolated environments per client organization
- Localization: Full Portuguese (pt-BR) translation
- White-label ready: Easy customization per tenant
Tech Stack
- Framework: Laravel (check composer.json for exact version)
- Base CRM: Krayin Laravel CRM
- Database: MySQL/PostgreSQL
- Multi-tenancy Package: Tenancy for Laravel (v3)
- Frontend: Blade templates with Alpine.js (Krayin default)
- PHP Version: 8.1+
- Containerization: Docker with Docker Compose
- Orchestration: Docker Swarm
- Management: Portainer
- CI/CD: Gitea Actions (GitHub Actions compatible)
- Error Tracking: Sentry for Laravel
- Code Quality: PHPStan (static analysis) + Laravel Pint (code formatter)
- CDN: Cloudflare (caching and DDoS protection) - PRODUCTION ONLY
Project Structure
.
├── .gitea/
│ └── workflows/ # Gitea Actions CI/CD pipelines
│ ├── deploy.yml # Production deployment
│ ├── deploy-staging.yml # Staging environment deployment
│ └── tests.yml # Automated testing pipeline
├── .husky/ # Git hooks (pre-commit, pre-push)
├── Makefile # Common development commands
├── app/
│ ├── Models/ # Eloquent models (tenant-scoped)
│ ├── Http/
│ │ ├── Controllers/ # Application controllers
│ │ └── Middleware/ # Custom middleware (tenant identification)
│ └── Providers/ # Service providers
├── config/
│ └── tenancy.php # Tenancy for Laravel configuration
├── database/
│ ├── migrations/ # Database migrations
│ │ ├── tenant/ # Tenant-specific migrations
│ │ └── landlord/ # Central database migrations
│ └── seeders/ # Seeders for tenants and central data
│ ├── DemoTenantSeeder.php # Creates demo tenants for testing
│ └── ProductionSeeder.php # Production data seeding
├── docker/
│ ├── Dockerfile # Application container definition
│ ├── docker-compose.yml # Local development orchestration
│ └── docker-compose.prod.yml # Production stack definition
├── packages/ # Krayin core packages
│ └── Webkul/
│ └── ...
├── public/
│ └── assets/ # Growup Pro assets (logos, images)
├── resources/
│ ├── lang/
│ │ └── pt_BR/ # Portuguese translations
│ └── views/ # Blade templates (Growup Pro customized)
└── routes/
├── web.php # Central app routes
├── tenant.php # Tenant-specific routes
├── admin.php # Admin dashboard routes (tenant management)
└── api.php # API routes
Multi-tenancy Configuration
Package: Tenancy for Laravel
We use Tenancy for Laravel v3 for robust multi-tenant architecture with automatic database switching and tenant identification.
Tenant Identification Strategy
- Method: Subdomain-based identification
- Domain:
growuppro.com.br - Pattern:
{tenant}.growuppro.com.br - Examples:
empresa1.growuppro.com.br→ Tenant: empresa1empresa2.growuppro.com.br→ Tenant: empresa2demo.growuppro.com.br→ Tenant: demo
Data Isolation
- Approach: Separate database per tenant (recommended by Tenancy for Laravel)
- Database naming:
tenant_{tenant_id}(e.g.,tenant_empresa1) - Central database:
growuppro_central(stores tenant metadata, domains, users) - Automatic tenant context switching via middleware
- Models automatically scoped to current tenant
Tenant Features
Each tenant has isolated:
- Data: Leads, contacts, deals, products, activities
- Users: Separate user base with roles/permissions
- Settings: Email configuration, notifications, workflows
- Customization: Optional CSS overrides, email templates
Branding & Localization
Growup Pro Visual Identity
- Application Name: Growup Pro (replacing all Krayin mentions)
- Logo: Custom Growup Pro logo in all interfaces
- Color Scheme: [Define primary/secondary colors when ready]
- Typography: [Define font family when ready]
- UI/UX: Modern, clean interface aligned with Growup Pro brand
Translation (pt-BR)
- All user-facing text translated to Portuguese (Brazil)
- Language files in
resources/lang/pt_BR/ - Default locale:
pt_BR(set inconfig/app.php) - Maintain translation keys for easy updates
- Include tenant-customizable text snippets
Customization Locations
- Logo:
public/assets/images/logo.png(central) and tenant-specific storage - Translations:
resources/lang/pt_BR/ - Views:
resources/views/(customized Krayin templates) - Styles:
public/assets/css/custom.css(Growup Pro overrides) - Config:
config/growuppro.php(application-specific settings)
Docker & Deployment Architecture
Container Strategy
The application runs in Docker containers orchestrated by Docker Swarm and managed through Portainer.
Docker Compose Structure
- Development:
docker-compose.yml(local development with hot-reload) - Production:
docker-compose.prod.yml(optimized for Swarm deployment)
Services
Typical stack includes:
- app: PHP-FPM application container (Growup Pro)
- nginx-proxy-manager: Nginx Proxy Manager for reverse proxy, SSL, and domain management (managed via Portainer)
- database: MySQL/PostgreSQL (central + tenants)
- redis: Session and cache storage
- queue: Laravel queue worker for background jobs
- scheduler: Laravel scheduler (cron jobs)
Image Management
- Registry: GitHub Container Registry (GHCR)
- Image naming:
ghcr.io/cauefaleiros/growup-pro:latest - Tagging strategy: Git commit SHA and semantic versioning
- Tags:
latest(production),dev(development),v{version}(releases)
CI/CD Pipeline with Gitea Actions
About Gitea Actions
Gitea Actions (available since Gitea 1.19) is a built-in CI/CD solution similar and mostly compatible with GitHub Actions. It uses the same YAML workflow format and is compatible with most GitHub Actions marketplace plugins.
Key Components:
- Gitea Server: Hosts repositories and triggers workflows
- act_runner: Standalone runner program (written in Go) that executes jobs, based on a fork of nektos/act
- Workflows: YAML files stored in
.gitea/workflows/directory (compatible with GitHub Actions syntax)
Compatibility:
- Same YAML syntax as GitHub Actions
- Can use most actions from GitHub marketplace (e.g.,
actions/checkout@v4,actions/setup-node@v4) - Workflows are portable between GitHub and Gitea with minimal changes
Deployment Flow
Developer pushes code to GitHub
↓
GitHub Actions workflow triggered
↓
1. Run tests (PHPUnit, Pest)
2. Build Docker image
3. Tag image with commit SHA
↓
Push image to GitHub Container Registry (GHCR)
↓
Call Portainer API (webhook or direct API)
↓
Portainer updates Docker Stack definition
↓
Docker Swarm pulls new image
↓
Swarm performs rolling update (zero-downtime)
↓
Health checks verify deployment
↓
Old containers removed
GitHub Actions Workflow
Location: .github/workflows/deploy.yml
Key steps:
- Checkout code
- Setup PHP & dependencies (Composer install)
- Run code quality checks (PHPStan, Pint)
- Run tests (PHPUnit/Pest - ensure code quality)
- Build Docker image with build args
- Login to GHCR using GitHub token
- Push image with appropriate tags
- Trigger Portainer via API to update stack
- Verify deployment (health check endpoint)
- Notify team (Slack/Discord webhook on success/failure)
Environment Variables
Managed through:
- GitHub Secrets: Sensitive data (API keys, tokens, Sentry DSN)
- Portainer: Stack environment variables
- Docker Swarm Secrets: Database credentials, API keys
Portainer Integration
- Portainer URL:
https://148.230.76.122:9443 - API Endpoint:
https://148.230.76.122:9443/api - Authentication: API token (stored in GitHub Secrets)
- Stack Management: Update existing stack with new image tag
- Webhooks: Optional webhook for automated redeploy
- Nginx Proxy Manager: Managed through Portainer for SSL certificates and domain routing
Coding Conventions
Models
All tenant-scoped models automatically inherit tenant context through Tenancy for Laravel:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Lead extends Model
{
// Tenancy for Laravel handles scoping automatically
// No manual trait needed for tenant models
protected $fillable = ['title', 'value', 'status'];
}
Central Models
Models that exist in the central database (tenant metadata, etc.):
<?php
namespace App\Models;
use Stancl\Tenancy\Database\Models\Tenant as BaseTenant;
class Tenant extends BaseTenant
{
// Custom tenant attributes
protected $fillable = [
'id', 'company_name', 'subdomain', 'logo_url', 'primary_color'
];
}
Controllers
- Follow Krayin's controller structure
- Tenant context is automatic (no manual checking needed)
- Use dependency injection and repository pattern
- Keep business logic in Service classes
Migrations
Tenancy for Laravel separates migrations:
// database/migrations/tenant/2024_xx_xx_create_leads_table.php
Schema::create('leads', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->decimal('value', 10, 2);
// No tenant_id needed - separate databases per tenant
$table->timestamps();
});
// database/migrations/2024_xx_xx_create_tenants_table.php (central)
Schema::create('tenants', function (Blueprint $table) {
$table->string('id')->primary();
$table->string('company_name');
$table->string('subdomain')->unique();
$table->timestamps();
});
Routes
// routes/tenant.php - Runs in tenant context
Route::middleware(['tenant'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
Route::resource('leads', LeadController::class);
});
// routes/web.php - Central app (tenant selection, etc.)
Route::get('/', [HomeController::class, 'index']);
Route::post('/register-tenant', [TenantController::class, 'register']);
Important Files to Know
Configuration
config/app.php- Application configuration (locale: pt_BR)config/tenancy.php- Tenancy for Laravel settingsconfig/growuppro.php- Custom Growup Pro configurationapp/Http/Kernel.php- Middleware registration
Krayin Core
packages/Webkul/- Krayin core packages (never modify directly)- Extend functionality through Laravel's standard practices (service providers, custom packages)
Docker & Deployment
docker/Dockerfile- Application container definitiondocker-compose.yml- Local development environmentdocker-compose.prod.yml- Production stack for Swarm.github/workflows/deploy.yml- CI/CD pipeline
Branding
public/assets/images/logo.png- Growup Pro logoresources/lang/pt_BR/- Portuguese translationsresources/views/layouts/app.blade.php- Main layout (branded)
CRITICAL: Krayin Authentication Issues (MUST RESOLVE BEFORE MULTI-TENANCY)
IMPORTANT: Multi-tenancy implementation is ON HOLD until we stabilize Krayin's base authentication system. We have experienced critical login issues that must be resolved first.
Known Authentication Problems
Problem 1: Error 419 - CSRF Token Mismatch
Symptoms:
- User enters credentials
- Form submission returns 419 error
- Login fails even with correct credentials
Possible Causes:
- Session driver misconfiguration (
filevsredisvsdatabase) - Session cookie not being set properly
- Domain/subdomain mismatch in session configuration
APP_URLmismatch with actual access URL- CSRF token expiration (session timeout too short)
- Reverse proxy stripping session cookies
Debug Steps:
# Check current session driver
grep SESSION_DRIVER .env
# Clear all caches
php artisan cache:clear
php artisan config:clear
php artisan route:clear
php artisan view:clear
# Check session files (if using file driver)
ls -la storage/framework/sessions/
# Test session configuration
php artisan tinker
>>> session()->put('test', 'value');
>>> session()->get('test'); # Should return 'value'
Potential Fixes:
-
Ensure APP_URL matches access URL exactly:
# If accessing via localhost:8000 APP_URL=http://localhost:8000 # If accessing via IP APP_URL=http://192.168.1.100:8000 -
Check session configuration (
config/session.php):'domain' => env('SESSION_DOMAIN', null), // Should match your domain 'secure' => env('SESSION_SECURE_COOKIE', false), // false for HTTP, true for HTTPS 'same_site' => 'lax', // Not 'strict' - can cause issues -
Verify CSRF middleware is present in
app/Http/Kernel.php:protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, // THIS IS CRITICAL // ... ], ]; -
Check CSRF exceptions (if login route needs to be excluded):
// app/Http/Middleware/VerifyCsrfToken.php protected $except = [ // Add routes here ONLY as last resort ];
Problem 2: Tenant Database Connection Issues
Symptoms:
- Login attempt fails silently
- Database connection errors in logs
- Can't authenticate against tenant-specific users table
Possible Causes:
- Tenant database doesn't exist yet
- Database migrations not run on tenant database
- Wrong database being queried (central vs tenant)
- Tenant context not initialized before authentication attempt
Debug Steps:
# List all databases
php artisan tinker
>>> DB::select('SHOW DATABASES');
# Check which database Laravel is connected to
>>> DB::connection()->getDatabaseName();
# Verify users table exists in tenant DB
>>> Schema::connection('tenant')->hasTable('users');
Critical Notes for Multi-tenancy:
- Authentication MUST work in single-tenant (non-multi-tenant) mode FIRST
- Only after stable authentication should we add tenant context switching
- Tenant middleware should NOT interfere with session/CSRF handling
Problem 3: Infinite Login Redirect Loop (CRITICAL - UNRESOLVED)
Symptoms:
- User enters valid credentials
- Form submits successfully (no 419 error)
- Page redirects back to login page
- User is never authenticated
- Dashboard never loads
- No error messages displayed
This is the MOST CRITICAL issue and must be debugged thoroughly.
Possible Causes:
-
Session not persisting after authentication:
- Session written but immediately destroyed
- Session driver issue (file permissions, Redis connection)
- Session ID regeneration failing
-
Authentication middleware misconfigured:
Authmiddleware blocking authenticated users- Wrong guard being checked
- Middleware order issues in Kernel.php
-
Redirect logic broken:
redirectToproperty in LoginController pointing to login route- Intended destination not being preserved
- Route name/path mismatch
-
Auth guard misconfigured:
- Wrong guard specified in
config/auth.php - Provider not finding users correctly
- User model relationship issues
- Wrong guard specified in
-
Cookie domain/path mismatch:
- Session cookie being set but not read back
- Domain attribute too restrictive
- Path attribute incorrect
Detailed Debug Steps:
# 1. Enable query logging to see what's happening
# Add to AppServiceProvider boot():
DB::listen(function ($query) {
Log::info('Query: ' . $query->sql . ' - Bindings: ' . json_encode($query->bindings));
});
# 2. Add extensive logging to login process
# In LoginController or wherever authentication happens:
Log::info('Login attempt for: ' . request()->email);
Log::info('Session ID before auth: ' . session()->getId());
# After Auth::attempt():
Log::info('Auth attempt result: ' . (Auth::check() ? 'success' : 'failed'));
Log::info('Session ID after auth: ' . session()->getId());
Log::info('Authenticated user: ' . (Auth::user() ? Auth::user()->id : 'none'));
# 3. Check session files directly
# If using file driver:
tail -f storage/logs/laravel.log &
# Make login attempt
# Check if session file is created and contains auth data:
cat storage/framework/sessions/*
# 4. Test authentication in Tinker
php artisan tinker
>>> $user = User::first();
>>> Auth::login($user);
>>> Auth::check(); # Should return true
>>> session()->all(); # Check session data
>>> session()->save(); # Manually save session
Configuration Files to Check:
-
config/auth.php
'defaults' => [ 'guard' => 'web', // Verify this matches your usage 'passwords' => 'users', ], 'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], ], 'providers' => [ 'users' => [ 'driver' => 'eloquent', 'model' => App\Models\User::class, // Verify model path ], ], -
config/session.php
'driver' => env('SESSION_DRIVER', 'file'), 'lifetime' => env('SESSION_LIFETIME', 120), 'expire_on_close' => false, 'encrypt' => false, 'files' => storage_path('framework/sessions'), 'connection' => env('SESSION_CONNECTION', null), 'table' => 'sessions', 'store' => env('SESSION_STORE', null), 'lottery' => [2, 100], 'cookie' => env('SESSION_COOKIE', Str::slug(env('APP_NAME', 'laravel'), '_').'_session'), 'path' => '/', 'domain' => env('SESSION_DOMAIN', null), // Should be NULL for localhost 'secure' => env('SESSION_SECURE_COOKIE', false), // FALSE for HTTP 'http_only' => true, 'same_site' => 'lax', // NOT 'strict' -
Verify LoginController redirect logic:
// Typical Laravel LoginController protected $redirectTo = '/dashboard'; // NOT '/login'! // Or method: protected function redirectTo() { return '/dashboard'; // Verify this route exists and is accessible } // Check authenticated() method isn't causing issues: protected function authenticated(Request $request, $user) { // Should NOT return redirect to login Log::info('User authenticated: ' . $user->id); } -
Check middleware in routes:
// routes/web.php Route::middleware(['auth'])->group(function () { Route::get('/dashboard', [DashboardController::class, 'index']); }); // Verify 'auth' middleware is defined in Kernel.php // and uses the correct guard
Testing Methodology:
-
Isolate the problem:
# Create a minimal test route Route::get('/test-auth', function () { Auth::login(User::first()); return [ 'authenticated' => Auth::check(), 'user_id' => Auth::id(), 'session_id' => session()->getId(), 'session_data' => session()->all(), ]; }); -
Test session persistence separately:
Route::get('/test-session-write', function () { session(['test_key' => 'test_value_' . time()]); return 'Session written: ' . session('test_key'); }); Route::get('/test-session-read', function () { return 'Session read: ' . session('test_key', 'NOT FOUND'); }); -
Test authentication without redirect:
Route::post('/test-login', function (Request $request) { $credentials = $request->only('email', 'password'); if (Auth::attempt($credentials)) { return [ 'status' => 'success', 'user' => Auth::user()->only(['id', 'email']), 'session_id' => session()->getId(), ]; } return ['status' => 'failed']; });
Critical Checklist Before Multi-tenancy:
- Session driver works correctly (can write and read session data)
- CSRF protection works (no 419 errors)
- Auth::attempt() returns true for valid credentials
- Auth::check() returns true immediately after Auth::attempt()
- Session persists across requests (test with simple session()->put/get)
- User can access protected routes after authentication
- No infinite redirect loops
- Login process completes in browser devtools Network tab (check for redirect chains)
- Session cookie is set and sent back with subsequent requests (check devtools Application/Storage)
DO NOT proceed with multi-tenancy until ALL checklist items pass.
Debugging Tools
# Enable debug mode
APP_DEBUG=true
# Tail logs in real-time
tail -f storage/logs/laravel.log
# Check Redis connection (if using Redis sessions)
redis-cli ping
# Check MySQL connection
php artisan tinker
>>> DB::connection()->getPdo();
# Dump session driver configuration
php artisan tinker
>>> config('session.driver');
>>> config('session.files');
>>> config('session.connection');
# Test file permissions
ls -la storage/framework/sessions/
# Should be writable by web server user
Next Steps After Resolving Authentication
- Document the exact fix that resolved the issue
- Create test cases to prevent regression
- Only then begin multi-tenancy implementation
- Add monitoring/logging to detect authentication issues early
Development Workflow
Development Environments
The project uses multiple environments for safe deployment:
-
Local Development (
localhost)- Docker Compose for local stack
- Hot reload enabled
- Debug mode on
-
Staging Environment (
staging.growuppro.com.br)- Production-like environment
- Deployed from
stagingbranch - Used for testing before production
- Same infrastructure as production
-
Production Environment (
growuppro.com.br)- Live environment
- Deployed from
mainbranch - Zero-downtime deployments
Local Development
- Clone repository
- Copy
.env.exampleto.envand configure - Run
docker-compose up -d - Access:
http://localhostor configured local domain - Create test tenants:
php artisan tenants:create
Making Changes
- Never modify Krayin core - extend via Laravel patterns
- Test with multiple tenants - always verify isolation
- Follow PSR-12 coding standards (enforced by Pint)
- Run quality checks before committing:
make lint # Run PHPStan + Pint make test # Run test suite - Write tests for new features (PHPUnit/Pest)
- Update translations when adding UI text
- Document breaking changes in pull requests
- Use pre-commit hooks to catch issues early
Testing Strategy
- Unit Tests: Core business logic, services
- Feature Tests: Tenant isolation, API endpoints
- Browser Tests: Multi-tenant user flows (Dusk)
- Database Tests: Migration rollback/forward
- Test with at least 2-3 active tenants
- CI/CD Integration: All tests run automatically on push
- Coverage Goal: Minimum 70% code coverage
Deployment Process
- Create feature branch from
main - Develop and test locally
- Push to
stagingbranch for staging deployment - Test on staging environment (
staging.growuppro.com.br) - Create Pull Request to
main(after PR approval) - Merge to
main- GitHub Actions runs automatically - Monitor deployment in Portainer
- Verify health checks pass
- Test critical flows on production
- Sentry monitors for runtime errors
Common Tasks
Quick Development Commands (Makefile)
make dev # Start local development environment
make prod # Start production-like local environment
make test # Run test suite
make lint # Run PHPStan + Pint checks
make fix # Auto-fix code style issues
make deploy-staging # Deploy to staging
make deploy-prod # Deploy to production
make logs # Show application logs
make shell # Enter application container shell
make db-fresh # Fresh database with seeders
make tenant-create # Create a new demo tenant
Creating a tenant-scoped feature
- Create migration in
database/migrations/tenant/ - Run migrations:
php artisan tenants:migrate - Create model (no special traits needed)
- Add routes in
routes/tenant.php - Build controller with tenant-aware logic
Adding a new translation
- Edit
resources/lang/pt_BR/{file}.php - Add translation key and Portuguese text
- Use in Blade:
{{ __('messages.welcome') }} - Test across different tenant contexts
Customizing tenant branding
- Store settings in Tenant model (JSON or relations)
- Load in middleware or service provider
- Pass to views via view composer
- Cache for performance:
tenant()->cache('branding')
Updating Docker image
- Modify
docker/Dockerfileas needed - Test locally:
make buildordocker-compose build app - Push changes to GitHub
- CI/CD handles the rest automatically
Creating demo tenants for testing
# Using artisan command
php artisan tenants:seed
# Or via Makefile
make tenant-create
# Specify tenant details
php artisan tenants:create \
--domain=demo.growuppro.com.br \
--name="Empresa Demo" \
--email=admin@demo.com
Managing code quality
# Run static analysis
./vendor/bin/phpstan analyse
# Check code style
./vendor/bin/pint --test
# Auto-fix code style
./vendor/bin/pint
# Or use Makefile shortcuts
make lint # Check only
make fix # Auto-fix
Setting up pre-commit hooks
# Install Husky (or similar)
npm install --save-dev husky
# Initialize hooks
npx husky init
# Add pre-commit hook
echo "make lint && make test" > .husky/pre-commit
chmod +x .husky/pre-commit
Environment Variables
Required Variables
# Application
APP_NAME="Growup Pro"
APP_ENV=production
APP_KEY=base64:...
APP_URL=https://growuppro.com.br
APP_LOCALE=pt_BR
APP_DEBUG=false
# Database (Central)
DB_CONNECTION=mysql
DB_HOST=database
DB_PORT=3306
DB_DATABASE=growuppro_central
DB_USERNAME=growuppro
DB_PASSWORD=secure_password
# Tenancy
TENANCY_DATABASE_PREFIX=tenant_
CENTRAL_DOMAINS=growuppro.com.br
# Redis
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379
# Cache & Queue
CACHE_DRIVER=redis
QUEUE_CONNECTION=redis
SESSION_DRIVER=redis
# Sentry (Error Tracking)
SENTRY_LARAVEL_DSN=https://xxx@sentry.io/xxx
SENTRY_TRACES_SAMPLE_RATE=0.2
SENTRY_PROFILES_SAMPLE_RATE=0.2
# Gitea Container Registry (or GitHub Container Registry as fallback)
REGISTRY_URL=gitea.yourdomain.com
REGISTRY_USERNAME=cauefaleiros
REGISTRY_PASSWORD=... # Or use token
# GitHub Container Registry (GHCR) - if using as fallback
GHCR_TOKEN=ghp_...
GHCR_USERNAME=cauefaleiros
GHCR_IMAGE=ghcr.io/cauefaleiros/growup-pro
# Portainer
PORTAINER_URL=https://148.230.76.122:9443
PORTAINER_API_TOKEN=ptr_...
PORTAINER_STACK_ID=...
# Cloudflare (Optional - for API integration)
CLOUDFLARE_API_TOKEN=...
CLOUDFLARE_ZONE_ID=...
Admin Dashboard for Tenant Management
The platform includes a comprehensive admin dashboard for managing tenants and monitoring platform health.
Dashboard Features
Tenant Management:
- View all active tenants with key metrics
- Create/edit/delete tenant accounts
- Suspend or activate tenant access
- View tenant resource usage (storage, bandwidth, users)
- Manage tenant subscriptions and billing
Analytics & Monitoring:
- Total active tenants count
- Growth metrics (new tenants per month)
- Resource utilization per tenant
- Most active tenants (by usage)
- Revenue tracking (if applicable)
- System health overview
Tenant Details View:
- Company information and contact details
- Subdomain and custom domain settings
- User count and activity logs
- Storage usage and database size
- Last login and activity timestamps
- Custom branding settings (logo, colors)
Bulk Operations:
- Bulk tenant creation via CSV import
- Batch notifications to multiple tenants
- Mass configuration updates
- Export tenant data for reporting
System Settings:
- Default tenant configurations
- Resource limits and quotas
- Email templates for tenant communications
- Feature flags management
- Maintenance mode per tenant
Access Control
- Admin dashboard accessible only to super admins
- Route:
/admin(protected bySuperAdminmiddleware) - Audit logs for all admin actions
- Two-factor authentication required
Implementation Notes
- Built with Filament Admin Panel (recommended) or custom Blade views
- Real-time updates using Livewire
- Caching for performance (tenant list, metrics)
- API endpoints for programmatic access
- Webhooks for tenant lifecycle events (created, suspended, deleted)
Notes for Gemini AI Assistant
Context Awareness
- This is Growup Pro, not Krayin - always use correct branding
- All text should be in Portuguese (pt-BR) when user-facing
- Consider tenant context in all suggestions
- Respect Docker/Swarm constraints in infrastructure suggestions
Code Suggestions
- Prefer extending over modifying Krayin core
- Ensure tenant isolation in all data operations
- Follow Tenancy for Laravel best practices
- Include proper error handling (tenant not found, DB connection issues)
- Suggest Docker-compatible solutions (env vars, volumes, etc.)
- Always consider Sentry error tracking when suggesting error handling
- Recommend testable code (dependency injection, mockable services)
- Suggest code quality improvements when reviewing code (PHPStan compliance)
Infrastructure Suggestions
- Consider Docker Swarm constraints (secrets, configs, networks)
- Suggest zero-downtime deployment strategies
- Include health checks in Docker configurations
- Recommend scalable solutions (horizontal scaling, load balancing)
Translation Reminders
- Always provide Portuguese translations for new strings
- Check existing translation files before adding new keys
- Maintain consistent terminology across the application
Quality Assurance & Best Practices
Code Quality Tools
The project enforces code quality through automated tools:
PHPStan (Static Analysis):
- Level 5 minimum (configurable in
phpstan.neon) - Catches type errors, undefined variables, incorrect method calls
- Runs on every commit (pre-commit hook)
- Must pass before deployment
Laravel Pint (Code Formatter):
- PSR-12 coding standard enforcement
- Automatic code formatting
- Consistent code style across the team
- Can auto-fix issues:
./vendor/bin/pint
Pre-commit Hooks:
- Automatically run before every commit
- Prevents committing code that doesn't pass quality checks
- Fast feedback loop for developers
- Configured via Husky or similar
Error Tracking with Sentry
Setup:
composer require sentry/sentry-laravel
php artisan sentry:publish --dsn
Features:
- Real-time error notifications
- Complete stack traces with context
- User tracking (which tenant experienced the error)
- Performance monitoring
- Release tracking (know which deployment introduced bugs)
Configuration:
// config/sentry.php
'dsn' => env('SENTRY_LARAVEL_DSN'),
'environment' => env('APP_ENV'),
'traces_sample_rate' => 0.2, // 20% of requests
'profiles_sample_rate' => 0.2,
Tenant Context: Always include tenant information in Sentry reports:
\Sentry\configureScope(function (\Sentry\State\Scope $scope): void {
$scope->setTag('tenant_id', tenant('id'));
$scope->setContext('tenant', [
'name' => tenant('name'),
'domain' => tenant('domain'),
]);
});
Testing Standards
- Coverage minimum: 70% code coverage
- Test pyramid: More unit tests, fewer integration/feature tests
- Tenant isolation tests: Critical - must verify data doesn't leak
- Performance tests: Ensure queries are optimized (N+1 detection)
- CI enforcement: All tests must pass before merge
Resources & Documentation
Project Specific
Infrastructure
- Docker Documentation
- Docker Compose Reference
- Docker Swarm Guide
- Portainer Documentation
- Portainer API Reference
CI/CD
- Gitea Actions Documentation
- Gitea Actions Quickstart
- act_runner Documentation
- GitHub Actions (for compatibility reference)
- GitHub Container Registry
- Docker Build Actions
Laravel & PHP
Project: Growup Pro
Base: Krayin Laravel CRM (Whitelabel)
Current Phase: Initial setup - multi-tenancy integration and Docker infrastructure
Domain: growuppro.com.br
Language: Portuguese (pt-BR)
Deployment: Docker Swarm + Portainer + GitHub Actions CI/CD