1069 lines
34 KiB
Markdown
1069 lines
34 KiB
Markdown
# Growup Pro - Krayin CRM Whitelabel Multi-tenant
|
|
|
|
## Project Overview
|
|
|
|
**Growup Pro** is a whitelabel implementation of [Krayin Laravel CRM](https://github.com/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**: `localhost` not 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](https://tenancyforlaravel.com/docs/v3/introduction) (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: empresa1
|
|
- `empresa2.growuppro.com.br` → Tenant: empresa2
|
|
- `demo.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 in `config/app.php`)
|
|
- Maintain translation keys for easy updates
|
|
- Include tenant-customizable text snippets
|
|
|
|
### Customization Locations
|
|
1. **Logo**: `public/assets/images/logo.png` (central) and tenant-specific storage
|
|
2. **Translations**: `resources/lang/pt_BR/`
|
|
3. **Views**: `resources/views/` (customized Krayin templates)
|
|
4. **Styles**: `public/assets/css/custom.css` (Growup Pro overrides)
|
|
5. **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:
|
|
1. **Checkout code**
|
|
2. **Setup PHP & dependencies** (Composer install)
|
|
3. **Run code quality checks** (PHPStan, Pint)
|
|
4. **Run tests** (PHPUnit/Pest - ensure code quality)
|
|
5. **Build Docker image** with build args
|
|
6. **Login to GHCR** using GitHub token
|
|
7. **Push image** with appropriate tags
|
|
8. **Trigger Portainer** via API to update stack
|
|
9. **Verify deployment** (health check endpoint)
|
|
10. **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
|
|
<?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
|
|
<?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:
|
|
|
|
```php
|
|
// 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
|
|
```php
|
|
// 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 settings
|
|
- `config/growuppro.php` - Custom Growup Pro configuration
|
|
- `app/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 definition
|
|
- `docker-compose.yml` - Local development environment
|
|
- `docker-compose.prod.yml` - Production stack for Swarm
|
|
- `.github/workflows/deploy.yml` - CI/CD pipeline
|
|
|
|
### Branding
|
|
- `public/assets/images/logo.png` - Growup Pro logo
|
|
- `resources/lang/pt_BR/` - Portuguese translations
|
|
- `resources/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 (`file` vs `redis` vs `database`)
|
|
- Session cookie not being set properly
|
|
- Domain/subdomain mismatch in session configuration
|
|
- `APP_URL` mismatch with actual access URL
|
|
- CSRF token expiration (session timeout too short)
|
|
- Reverse proxy stripping session cookies
|
|
|
|
**Debug Steps:**
|
|
```bash
|
|
# 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:**
|
|
1. **Ensure APP_URL matches access URL exactly:**
|
|
```env
|
|
# If accessing via localhost:8000
|
|
APP_URL=http://localhost:8000
|
|
|
|
# If accessing via IP
|
|
APP_URL=http://192.168.1.100:8000
|
|
```
|
|
|
|
2. **Check session configuration** (`config/session.php`):
|
|
```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
|
|
```
|
|
|
|
3. **Verify CSRF middleware** is present in `app/Http/Kernel.php`:
|
|
```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
|
|
// ...
|
|
],
|
|
];
|
|
```
|
|
|
|
4. **Check CSRF exceptions** (if login route needs to be excluded):
|
|
```php
|
|
// 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:**
|
|
```bash
|
|
# 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:**
|
|
1. **Session not persisting after authentication:**
|
|
- Session written but immediately destroyed
|
|
- Session driver issue (file permissions, Redis connection)
|
|
- Session ID regeneration failing
|
|
|
|
2. **Authentication middleware misconfigured:**
|
|
- `Auth` middleware blocking authenticated users
|
|
- Wrong guard being checked
|
|
- Middleware order issues in Kernel.php
|
|
|
|
3. **Redirect logic broken:**
|
|
- `redirectTo` property in LoginController pointing to login route
|
|
- Intended destination not being preserved
|
|
- Route name/path mismatch
|
|
|
|
4. **Auth guard misconfigured:**
|
|
- Wrong guard specified in `config/auth.php`
|
|
- Provider not finding users correctly
|
|
- User model relationship issues
|
|
|
|
5. **Cookie domain/path mismatch:**
|
|
- Session cookie being set but not read back
|
|
- Domain attribute too restrictive
|
|
- Path attribute incorrect
|
|
|
|
**Detailed Debug Steps:**
|
|
|
|
```bash
|
|
# 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:**
|
|
|
|
1. **config/auth.php**
|
|
```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
|
|
],
|
|
],
|
|
```
|
|
|
|
2. **config/session.php**
|
|
```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'
|
|
```
|
|
|
|
3. **Verify LoginController redirect logic:**
|
|
```php
|
|
// 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);
|
|
}
|
|
```
|
|
|
|
4. **Check middleware in routes:**
|
|
```php
|
|
// 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:**
|
|
|
|
1. **Isolate the problem:**
|
|
```bash
|
|
# 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(),
|
|
];
|
|
});
|
|
```
|
|
|
|
2. **Test session persistence separately:**
|
|
```bash
|
|
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');
|
|
});
|
|
```
|
|
|
|
3. **Test authentication without redirect:**
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
1. Document the exact fix that resolved the issue
|
|
2. Create test cases to prevent regression
|
|
3. Only then begin multi-tenancy implementation
|
|
4. Add monitoring/logging to detect authentication issues early
|
|
|
|
---
|
|
|
|
## Development Workflow
|
|
|
|
### Development Environments
|
|
The project uses multiple environments for safe deployment:
|
|
|
|
1. **Local Development** (`localhost`)
|
|
- Docker Compose for local stack
|
|
- Hot reload enabled
|
|
- Debug mode on
|
|
|
|
2. **Staging Environment** (`staging.growuppro.com.br`)
|
|
- Production-like environment
|
|
- Deployed from `staging` branch
|
|
- Used for testing before production
|
|
- Same infrastructure as production
|
|
|
|
3. **Production Environment** (`growuppro.com.br`)
|
|
- Live environment
|
|
- Deployed from `main` branch
|
|
- Zero-downtime deployments
|
|
|
|
### Local Development
|
|
1. Clone repository
|
|
2. Copy `.env.example` to `.env` and configure
|
|
3. Run `docker-compose up -d`
|
|
4. Access: `http://localhost` or configured local domain
|
|
5. Create test tenants: `php artisan tenants:create`
|
|
|
|
### Making Changes
|
|
1. **Never modify Krayin core** - extend via Laravel patterns
|
|
2. **Test with multiple tenants** - always verify isolation
|
|
3. **Follow PSR-12** coding standards (enforced by Pint)
|
|
4. **Run quality checks** before committing:
|
|
```bash
|
|
make lint # Run PHPStan + Pint
|
|
make test # Run test suite
|
|
```
|
|
5. **Write tests** for new features (PHPUnit/Pest)
|
|
6. **Update translations** when adding UI text
|
|
7. **Document breaking changes** in pull requests
|
|
8. **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
|
|
1. **Create feature branch** from `main`
|
|
2. **Develop and test locally**
|
|
3. **Push to `staging` branch** for staging deployment
|
|
4. **Test on staging environment** (`staging.growuppro.com.br`)
|
|
5. **Create Pull Request** to `main` (after PR approval)
|
|
6. **Merge to `main`** - GitHub Actions runs automatically
|
|
7. **Monitor deployment** in Portainer
|
|
8. **Verify health checks** pass
|
|
9. **Test critical flows** on production
|
|
10. **Sentry** monitors for runtime errors
|
|
|
|
## Common Tasks
|
|
|
|
### Quick Development Commands (Makefile)
|
|
```bash
|
|
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
|
|
1. Create migration in `database/migrations/tenant/`
|
|
2. Run migrations: `php artisan tenants:migrate`
|
|
3. Create model (no special traits needed)
|
|
4. Add routes in `routes/tenant.php`
|
|
5. Build controller with tenant-aware logic
|
|
|
|
### Adding a new translation
|
|
1. Edit `resources/lang/pt_BR/{file}.php`
|
|
2. Add translation key and Portuguese text
|
|
3. Use in Blade: `{{ __('messages.welcome') }}`
|
|
4. Test across different tenant contexts
|
|
|
|
### Customizing tenant branding
|
|
1. Store settings in Tenant model (JSON or relations)
|
|
2. Load in middleware or service provider
|
|
3. Pass to views via view composer
|
|
4. Cache for performance: `tenant()->cache('branding')`
|
|
|
|
### Updating Docker image
|
|
1. Modify `docker/Dockerfile` as needed
|
|
2. Test locally: `make build` or `docker-compose build app`
|
|
3. Push changes to GitHub
|
|
4. CI/CD handles the rest automatically
|
|
|
|
### Creating demo tenants for testing
|
|
```bash
|
|
# 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
|
|
```bash
|
|
# 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
|
|
```bash
|
|
# 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
|
|
```env
|
|
# 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 by `SuperAdmin` middleware)
|
|
- 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:**
|
|
```bash
|
|
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:**
|
|
```php
|
|
// 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:
|
|
```php
|
|
\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
|
|
- [Krayin CRM Docs](https://devdocs.krayincrm.com/)
|
|
- [Krayin GitHub](https://github.com/krayin/laravel-crm)
|
|
- [Tenancy for Laravel Docs](https://tenancyforlaravel.com/docs/v3/introduction)
|
|
|
|
### Infrastructure
|
|
- [Docker Documentation](https://docs.docker.com/)
|
|
- [Docker Compose Reference](https://docs.docker.com/compose/compose-file/)
|
|
- [Docker Swarm Guide](https://docs.docker.com/engine/swarm/)
|
|
- [Portainer Documentation](https://docs.portainer.io/)
|
|
- [Portainer API Reference](https://docs.portainer.io/api/docs)
|
|
|
|
### CI/CD
|
|
- [Gitea Actions Documentation](https://docs.gitea.com/usage/actions/overview)
|
|
- [Gitea Actions Quickstart](https://docs.gitea.com/usage/actions/quickstart)
|
|
- [act_runner Documentation](https://gitea.com/gitea/act_runner)
|
|
- [GitHub Actions (for compatibility reference)](https://docs.github.com/en/actions)
|
|
- [GitHub Container Registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry)
|
|
- [Docker Build Actions](https://github.com/docker/build-push-action)
|
|
|
|
### Laravel & PHP
|
|
- [Laravel Documentation](https://laravel.com/docs)
|
|
- [Laravel Multi-tenancy Patterns](https://laravel-news.com/multi-tenancy)
|
|
- [PSR-12 Coding Standard](https://www.php-fig.org/psr/psr-12/)
|
|
|
|
---
|
|
|
|
**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
|