Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/iamalexis689725/cole/llms.txt

Use this file to discover all available pages before exploring further.

Cole is a multi-tenant platform where every school operates as a fully isolated account called a tenant. Whether you are managing attendance records, agenda entries, or student data, every piece of information belongs to exactly one tenant and is never visible to another. This isolation is enforced at the database query level automatically — no manual filtering is required from controllers or services.

What is a Tenant?

A tenant represents a single school registered in Cole. It is identified by a numeric id and a human-readable slug. Every user, teacher, student, and resource created inside the platform belongs to one tenant. The tenants table stores four key fields:
ColumnTypeDescription
idintegerAuto-incremented primary key
namestringDisplay name of the school
slugstringUnique URL-safe identifier
is_activebooleanWhether the tenant account is enabled
// database/migrations/2026_04_01_173009_create_tenants_table.php
Schema::create('tenants', function (Blueprint $table) {
    $table->id();
    $table->string('name');        // nombre del colegio
    $table->string('slug')->unique(); // identificador
    $table->boolean('is_active')->default(true);
    $table->timestamps();
});
The Tenant Eloquent model exposes its enabled modules through a belongsToMany relationship that also carries the activo pivot flag:
// app/Models/Tenant.php
class Tenant extends Model
{
    protected $fillable = ['name', 'slug', 'logo'];

    public function modules()
    {
        return $this->belongsToMany(Module::class, 'tenant_modules')
            ->withPivot('activo')->withTimestamps();
    }
}

The BelongsToTenant Trait

The BelongsToTenant trait is the cornerstone of data isolation in Cole. Any Eloquent model that uses this trait receives two automatic behaviours registered in the booted() lifecycle hook.
// app/Traits/BelongsToTenant.php
trait BelongsToTenant
{
    protected static function booted()
    {
        // Auto asignar tenant
        static::creating(function ($model) {
            if (auth()->check()) {
                $model->tenant_id = auth()->user()->tenant_id;
            }
        });

        // Scope global
        static::addGlobalScope('tenant', function (Builder $builder) {
            if (auth()->check()) {
                $model = $builder->getModel();

                $builder->where(
                    $model->getTable() . '.tenant_id',
                    auth()->user()->tenant_id
                );
            }
        });
    }
}

Auto-assign on create

When a new record is saved, the creating hook automatically sets tenant_id from the authenticated user. No controller needs to pass it manually.

Global query scope

A global Eloquent scope named tenant appends a WHERE tenant_id = ? clause to every query on the model, using the authenticated user’s tenant_id.
Both behaviours are conditional on auth()->check(). Unauthenticated contexts — such as seeders or console commands — are unaffected and can operate across all tenants freely.

TenantMiddleware

The TenantMiddleware runs on every authenticated API route and binds the current user’s tenant_id into Laravel’s IoC container. This makes the tenant context available to any service-layer code that needs it outside of Eloquent models.
// app/Http/Middleware/TenantMiddleware.php
class TenantMiddleware
{
    public function handle(Request $request, Closure $next)
    {
        if (!auth()->check()) {
            return response()->json(['error' => 'Unauthorized'], 401);
        }

        $tenantId = auth()->user()->tenant_id;
        app()->instance('tenant_id', $tenantId);
        return $next($request);
    }
}
The middleware is registered in Kernel.php under the alias tenant and is applied to protected route groups:
// app/Http/Kernel.php
protected $routeMiddleware = [
    'tenant' => \App\Http\Middleware\TenantMiddleware::class,
    // ...
];
You can resolve the tenant ID anywhere in the application using app('tenant_id') after this middleware has run.

Tenant-Scoped Models

Every model listed below uses the BelongsToTenant trait. All queries against these models are automatically filtered to the authenticated user’s tenant, and all new records are automatically stamped with that tenant’s id.
ModelResource description
AcademicPeriodAcademic year / period definitions
AgendaAcademic agenda entries
AgendaArchivoFile attachments on agenda items
AnecdotarioTeacher anecdotal notes on students
AsignacionDocenteTeacher-to-course assignments
AsistenciaAttendance records
CircularSchool circulars / announcements
CriterioGrading criteria
CursoCourses / subjects
EntregaTareaStudent task submissions
EntregaTareaArchivoFiles attached to task submissions
EstudianteStudent profiles
HorarioAsignacionSchedule assignments
InscripcionCourse enrolments
NotaStudent grades
PadreEstudianteParent-to-student relationship records
PadreFamiliaParent / guardian profiles
ParaleloClass sections / parallels
PeriodoEvaluacionEvaluation periods
ProfesorTeacher profiles
ProfesorSubjectTeacher-to-subject assignments
SubjectSubject definitions
If you build a new Eloquent model that holds school-specific data, add use BelongsToTenant; to it. Without the trait, records from all tenants will be visible to every authenticated user.

Super-Admin and Cross-Tenant Access

The super-admin role is the only role whose tenant_id is null. The BelongsToTenant global scope fires whenever auth()->check() returns true — which includes super-admins — but because the authenticated user’s tenant_id is null, the appended WHERE tenant_id = NULL clause matches no rows in normal SQL comparison. In practice, super-admin queries should bypass tenant-scoped models entirely and use withoutGlobalScope('tenant') where cross-tenant access is required.
The CheckModule middleware also short-circuits for super-admin users, granting them access to every module endpoint regardless of a tenant’s module configuration. See Modules for details.

Creating a Tenant

Tenants are created by a super-admin via the Tenants API:
POST /api/tenants
Authorization: Bearer <super-admin-token>
Content-Type: application/json

{
  "name": "Colegio San Andrés",
  "slug": "san-andres"
}
Refer to the Tenants API reference for the full request schema, validation rules, and response format.

Build docs developers (and LLMs) love