Overview
Core Projects is a construction management SaaS platform built on a modern, full-stack architecture that combines Laravel’s robust backend capabilities with Vue.js’s reactive frontend, seamlessly connected through Inertia.js.
Technology Stack
Backend Layer
Laravel Framework MVC architecture with Eloquent ORM for database operations
MySQL Database Relational database for structured project and sales data
Service Layer Business logic encapsulation through dedicated service classes
Middleware Role-based access control and request handling
Frontend Layer
Vue 3 Component-based reactive user interface
Inertia.js SPA-like experience without building an API
Tailwind CSS Utility-first CSS framework for styling
Vite Fast build tool and development server
Directory Structure
core-projects/
├── app/
│ ├── Http/
│ │ ├── Controllers/ # Request handlers
│ │ │ ├── Admin/ # Admin-specific controllers
│ │ │ ├── Ventas/ # Sales module controllers
│ │ │ ├── Gerencia/ # Management controllers
│ │ │ └── Contabilidad/ # Accounting controllers
│ │ └── Middleware/ # Request/response filters
│ ├── Models/ # Eloquent ORM models
│ └── Services/ # Business logic layer
│ ├── VentaService.php
│ ├── ProyectoPricingService.php
│ └── PriceEngine.php
├── database/
│ └── migrations/ # Database schema definitions
├── resources/
│ └── js/
│ ├── Pages/ # Inertia.js page components
│ │ ├── Admin/
│ │ ├── Ventas/
│ │ ├── Gerencia/
│ │ └── Contabilidad/
│ ├── Components/ # Reusable Vue components
│ └── Layouts/ # Page layout templates
└── routes/
└── web.php # Application routes
Database Schema Overview
Core Projects uses a normalized relational database structure organized into logical domains:
Core Entities
Key Tables
proyectos - Construction projects
torres - Towers within projects
pisos_torre - Floors in towers
ubicaciones - Geographic locations
estados - Project states
apartamentos - Apartment units
locales - Commercial spaces
parqueaderos - Parking spots
zonas_sociales - Social areas
tipos_apartamento - Apartment types
estados_inmueble - Property availability states
ventas - Sales and separations
clientes - Customer information
pagos - Payment transactions
plan_amortizacion_venta - Amortization plans
plan_amortizacion_cuota - Payment installments
formas_pago - Payment methods
politicas_precio_proyecto - Dynamic pricing policies
politicas_comision - Commission structures
proyectos_metas_comerciales - Sales targets
empleados - Employee accounts
cargos - Job positions/roles
dependencias - Departments
login_logs - Authentication audit trail
Design Patterns
Model-View-Controller (MVC)
Core Projects follows Laravel’s MVC pattern:
Models - Eloquent ORM classes representing database entities:
class Proyecto extends Model
{
protected $table = 'proyectos' ;
protected $primaryKey = 'id_proyecto' ;
// Relationships
public function torres ()
{
return $this -> hasMany ( Torre :: class , 'id_proyecto' , 'id_proyecto' );
}
public function politicaVigente ()
{
return $this -> hasOne ( PoliticaPrecioProyecto :: class , 'id_proyecto' , 'id_proyecto' )
-> where ( 'estado' , true )
-> where ( function ( $query ) {
$query -> whereNull ( 'aplica_desde' )
-> orWhere ( 'aplica_desde' , '<=' , now ());
})
-> latest ( 'aplica_desde' );
}
}
Controllers - Handle HTTP requests and return Inertia responses:
app/Http/Controllers/Admin/ProyectoController.php
public function index ()
{
$proyectos = Proyecto :: with ([ 'estado_proyecto' , 'ubicacion' , 'torres' ])
-> paginate ( 10 );
return Inertia :: render ( 'Admin/Proyectos/Index' , [
'proyectos' => $proyectos
]);
}
Views - Vue 3 components rendered by Inertia:
resources/js/Pages/Admin/Proyectos/Index.vue
< script setup >
import { defineProps } from 'vue' ;
const props = defineProps ({
proyectos: Object
});
</ script >
< template >
< div class = "container" >
<!-- Project list UI -->
</ div >
</ template >
Service Layer Pattern
Complex business logic is encapsulated in service classes to keep controllers thin:
app/Services/VentaService.php
class VentaService
{
public function crearOperacion ( array $data ) : Venta
{
return DB :: transaction ( function () use ( $data ) {
// 1. Lock and verify property availability
// 2. Validate business rules
// 3. Calculate pricing
// 4. Create sale record
// 5. Update property state
// 6. Generate payment plan
// 7. Recalculate project pricing
});
}
}
Service classes handle multi-step operations that span multiple models, ensuring data consistency through database transactions.
Repository Pattern (Eloquent)
Eloquent acts as an implementation of the Repository pattern:
// Query scopes for reusable queries
public function scopeActivos ( $query )
{
return $query -> where ( 'activo' , true );
}
// Usage in controllers
$proyectos = Proyecto :: activos () -> get ();
Middleware Pattern
Request filtering and authentication through middleware:
app/Http/Middleware/CheckCargo.php
class CheckCargo
{
public function handle ( Request $request , Closure $next , ... $cargosPermitidos )
{
$empleado = Auth :: guard ( 'web' ) -> user ();
if ( ! $empleado ||
! $empleado -> cargo ||
! in_array ( $empleado -> cargo -> nombre , $cargosPermitidos )) {
abort ( 403 , 'No tienes permiso para acceder a esta sección.' );
}
return $next ( $request );
}
}
Request Flow
The typical request lifecycle in Core Projects:
Inertia.js Integration
Inertia.js creates a seamless SPA experience without building a REST API:
Server-Side
// Return Inertia response with props
return Inertia :: render ( 'Ventas/Index' , [
'ventas' => $ventas ,
'filters' => $filters
]);
Client-Side
< script setup >
import { router } from '@inertiajs/vue3' ;
const props = defineProps ({
ventas: Object ,
filters: Object
});
// Navigate without full page reload
const editVenta = ( id ) => {
router . visit ( `/ventas/ ${ id } /edit` );
};
</ script >
Inertia automatically handles form submissions, validation errors, and preserves scroll position without writing API endpoints.
Authentication & Authorization
Core Projects uses Laravel’s authentication with custom employee model:
class Empleado extends Authenticatable
{
use HasApiTokens , HasFactory , Notifiable ;
protected $table = 'empleados' ;
protected $guard = 'web' ;
public function cargo ()
{
return $this -> belongsTo ( Cargo :: class , 'id_cargo' , 'id_cargo' );
}
}
Route Protection
// Admin and Manager routes
Route :: middleware ([ 'auth' , 'check.cargo:Gerente,Administrador' ]) -> group ( function () {
Route :: get ( '/dashboard' , [ DashboardController :: class , 'index' ]);
Route :: resource ( 'proyectos' , ProyectoController :: class );
});
// Sales team routes
Route :: middleware ([ 'auth' , 'check.cargo:Directora Comercial,Asesora Comercial,Gerente,Administrador' ])
-> group ( function () {
Route :: resource ( 'ventas' , VentaWebController :: class );
Route :: get ( '/catalogo' , [ CatalogoWebController :: class , 'index' ]);
});
Eager Loading
Prevent N+1 queries with relationship eager loading:
$proyectos = Proyecto :: with ([
'torres.apartamentos.estadoInmueble' ,
'politicaVigente' ,
'ubicacion'
]) -> get ();
Database Transactions
Ensure data consistency for complex operations:
DB :: transaction ( function () {
// All operations succeed or all fail
});
Pessimistic Locking
Prevent race conditions in concurrent sales:
$inmueble = Apartamento :: where ( 'id_apartamento' , $id )
-> lockForUpdate ()
-> firstOrFail ();
User Roles Learn about role-based access control
Projects Understanding project structure
Properties Property types and management
Sales Workflow Sales process and operations