Skip to main content

Database Setup

DentControl uses Laravel’s migration system to manage database schema. This guide covers database configuration, running migrations, and understanding the database structure.

Database Options

DentControl supports multiple database systems out of the box.

Supported Databases

SQLite

Default choiceSingle file database, perfect for development and small deployments. No server required.

MySQL

Production readyPopular relational database with excellent performance and wide hosting support.

PostgreSQL

Advanced featuresRobust database with advanced features and strong data integrity.

SQLite Setup (Default)

SQLite is the default database and requires minimal configuration.
1

Configure .env

Set the database connection in .env:
DB_CONNECTION=sqlite
2

Create database file

Create the SQLite database file:
touch database/database.sqlite
3

Set permissions

Ensure the database file is writable:
chmod 664 database/database.sqlite
chmod 775 database/
SQLite stores the entire database in a single file at database/database.sqlite.

MySQL Setup

1

Create database

Create a MySQL database:
CREATE DATABASE dentcontrol CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'dentcontrol'@'localhost' IDENTIFIED BY 'secure_password';
GRANT ALL PRIVILEGES ON dentcontrol.* TO 'dentcontrol'@'localhost';
FLUSH PRIVILEGES;
2

Configure .env

Update your .env file:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=dentcontrol
DB_USERNAME=dentcontrol
DB_PASSWORD=secure_password
3

Test connection

Test the database connection:
php artisan db:show

PostgreSQL Setup

1

Create database

Create a PostgreSQL database:
CREATE DATABASE dentcontrol;
CREATE USER dentcontrol WITH PASSWORD 'secure_password';
GRANT ALL PRIVILEGES ON DATABASE dentcontrol TO dentcontrol;
2

Configure .env

Update your .env file:
DB_CONNECTION=pgsql
DB_HOST=127.0.0.1
DB_PORT=5432
DB_DATABASE=dentcontrol
DB_USERNAME=dentcontrol
DB_PASSWORD=secure_password
3

Test connection

Verify the connection:
php artisan db:show

Running Migrations

Migrations create and modify database tables. DentControl includes all necessary migrations.

Initial Migration

Run migrations for the first time:
php artisan migrate
On production servers, Laravel requires the --force flag to run migrations:
php artisan migrate --force

Migration Commands

CommandDescription
php artisan migrateRun pending migrations
php artisan migrate:statusShow migration status
php artisan migrate:rollbackRollback last batch
php artisan migrate:resetRollback all migrations
php artisan migrate:refreshReset and re-run all migrations
php artisan migrate:freshDrop all tables and re-migrate
Use migrate:fresh with caution - it deletes all data!

Migration File Structure

DentControl includes the following migrations (in execution order):

Laravel System Tables

System Migrations
0001_01_01_000000_create_users_table.php       # Default Laravel users (not used)
0001_01_01_000001_create_cache_table.php       # Cache storage
0001_01_01_000002_create_jobs_table.php        # Queue jobs and batches

DentControl Application Tables

1

Clinica (Clinic)

File: 2026_02_23_084014_create_clinica_table.phpThe root table for multi-clinic support. Stores clinic information, address, and status.
Key Fields
- id_clinica (primary key)
- nombre (clinic name)
- rfc (tax ID, unique)
- Address fields (calle, ciudad, estado, etc.)
- telefono
- logo_ruta
- estatus (activo/baja)
2

Catalogo Servicios (Service Catalog)

File: 2026_02_23_085029_create_catalogo_servicios_table.phpServices offered by each clinic (e.g., “Limpieza”, “Ortodoncia”).
Key Fields
- id_cat_servicio (primary key)
- id_clinica (foreign key)
- nombre (service name, unique per clinic)
- descripcion
- duracion (duration in minutes)
- precio_sugerido
- estatus
3

Catalogo Tratamientos (Treatment Catalog)

File: 2026_02_23_085812_create_catalogo_tratamientos_table.phpTreatment types offered by clinics.
4

Paciente (Patient)

File: 2026_02_23_090302_create_paciente_table.phpPatient information and medical records.
Key Fields
- id_paciente (primary key)
- id_clinica (foreign key)
- Personal info (nombre, apellidos, fecha_nacimiento, sexo)
- curp (unique national ID)
- telefono, ocupacion, peso
- Address fields
- estatus
5

Usuario (User)

File: 2026_02_23_090927_create_usuario_table.phpSystem users (dentists, assistants, admins).
Key Fields
- id_usuario (primary key)
- id_clinica (foreign key)
- Personal info (nombre, apellidos)
- cedula_profesional (professional license, unique)
- nom_usuario (username, unique)
- password (hashed)
- rol (superadmin, dentista, asistente)
- estatus
- remember_token
6

Expediente Clinico (Clinical Record)

File: 2026_02_23_092325_create_expediente_clinico_table.phpPatient medical history and clinical information.
7

Tratamiento (Treatment)

File: 2026_02_23_092642_create_tratamiento_table.phpActive treatments for patients.
Key Fields
- id_tratamiento (primary key)
- id_paciente, id_usuario, id_clinica (foreign keys)
- id_cat_tratamientos (treatment type)
- diagnostico_inicial
- precio_final
- fecha_inicio, fecha_fin
- estatus (curso, finalizado, pausado)
8

Notas Evolucion (Clinical Notes)

File: 2026_02_23_093121_create_notas_evolucion_table.phpProgress notes for treatments.
9

Acceso Movil (Mobile Access)

File: 2026_02_23_093639_create_acceso_movil_table.phpMobile app access tokens.
10

Citas (Appointments)

File: 2026_03_01_231623_create_citas_table.phpPatient appointments with dentists.
Key Fields
- id_cita (primary key)
- id_paciente, id_usuario, id_clinica (foreign keys)
- id_cat_servicio (service type)
- id_tratamiento (optional, linked treatment)
- fecha (date)
- hora (time)
- motivo_consulta
- Unique constraint: (id_usuario, fecha, hora)

Database Schema Overview

Here’s how the main tables relate to each other:

Key Relationships

  1. Clinic-centric: All major entities belong to a clinic (id_clinica)
  2. User assignments: Users (dentists/assistants) are assigned to one clinic
  3. Patient records: Patients belong to a clinic and have multiple appointments
  4. Appointments: Link patients, users (dentists), services, and optionally treatments
  5. Treatments: Ongoing treatment plans with clinical notes
  6. Cascade deletes: Most tables use onDelete('cascade') for referential integrity

Seeding Data

Seeders populate the database with initial or test data.

Running Seeders

php artisan db:seed

Creating Custom Seeders

Create a seeder for initial data:
php artisan make:seeder ClinicaSeeder

Database Maintenance

Backup Database

cp database/database.sqlite database/backups/backup-$(date +%Y%m%d).sqlite

Restore Database

cp database/backups/backup-20260305.sqlite database/database.sqlite

Database Optimization

Optimize Database
# Clear old cache entries
php artisan cache:clear

# Clear old job records
php artisan queue:flush

# Optimize database (MySQL)
php artisan db:optimize

Database Inspection

Using Artisan Commands

php artisan db:show

Using Tinker

Interact with your database using Laravel Tinker:
php artisan tinker

Troubleshooting

This means migrations were partially run. Options:
  1. Check migration status:
    php artisan migrate:status
    
  2. Rollback and retry:
    php artisan migrate:rollback
    php artisan migrate
    
  3. Fresh start (destroys data!):
    php artisan migrate:fresh
    
SQLite locks the entire database during writes.Solutions:
  1. Close any database browser tools
  2. Stop any running queue workers
  3. Check file permissions:
    chmod 664 database/database.sqlite
    
  4. For production, consider MySQL or PostgreSQL
This occurs when trying to insert data without required parent records.Example: Creating a user without a clinic:
// This will fail:
Usuario::create(['id_clinica' => 999, ...]);

// First create the clinic:
$clinica = Clinica::create(['nombre' => 'My Clinic', ...]);

// Then create the user:
Usuario::create(['id_clinica' => $clinica->id_clinica, ...]);
Order matters! Create parent records first:
  1. Clinica
  2. CatalogoServicios, CatalogoTratamientos
  3. Usuario, Paciente
  4. ExpedienteClinico, Tratamiento
  5. Citas, NotasEvolucion
For large migrations, increase timeout:
// In migration file
public function up(): void
{
    DB::statement('SET SESSION max_execution_time = 600;');
    Schema::create('large_table', function (Blueprint $table) {
        // ...
    });
}
Or run migrations with higher limits:
php -d max_execution_time=600 artisan migrate
Check these common issues:
  1. Database server running?
    # MySQL
    sudo systemctl status mysql
    
    # PostgreSQL
    sudo systemctl status postgresql
    
  2. Credentials correct?
    • Verify .env settings
    • Test with database client
  3. Firewall blocking?
    # Check MySQL port
    sudo netstat -tlnp | grep 3306
    
    # Check PostgreSQL port  
    sudo netstat -tlnp | grep 5432
    
  4. Clear config cache:
    php artisan config:clear
    
Ensure UTF-8 encoding for proper Spanish character support:MySQL:
ALTER DATABASE dentcontrol CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
PostgreSQL:
-- Create database with UTF-8
CREATE DATABASE dentcontrol ENCODING 'UTF8';
SQLite: UTF-8 by default

Best Practices

  1. Always backup before migrations: Especially on production
  2. Test migrations locally first: Run on dev environment before production
  3. Use transactions: Migrations automatically wrap operations in transactions
  4. Version control migrations: Never modify existing migrations, create new ones
  5. Document custom migrations: Add comments explaining complex schema changes
  6. Regular backups: Automate daily database backups
  7. Monitor database size: Watch SQLite file size, consider MySQL/PostgreSQL for growth
  8. Use seeders for initial data: Keep test data consistent across environments

Next Steps

Configuration

Configure database connection settings

User Management

Create users and manage access

Deployment

Deploy your database to production

Build docs developers (and LLMs) love