Skip to main content

Overview

The Dashboard Dilemas database uses a relational MySQL schema with foreign key constraints to maintain data integrity across multi-tenant organizations. All tables use the de_app_ prefix for namespace isolation. Schema Characteristics:
  • Character Set: utf8mb4 with unicode collation
  • Storage Engine: InnoDB (ACID compliance, foreign keys)
  • Naming Convention: Snake_case for columns, PascalCase for legacy WordPress compatibility
  • ID Strategy: VARCHAR(50) for flexibility with custom identifiers

Entity-Relationship Diagram

The following ER diagram illustrates the core database structure and relationships:

Core Tables

de_app_clients

Stores client organizations (companies) that use the platform.
ColumnTypeConstraintsDescription
idVARCHAR(50)PRIMARY KEYUnique client identifier
nameVARCHAR(100)NOT NULLClient/company name
created_atDATETIMEDEFAULT CURRENT_TIMESTAMPRecord creation timestamp
Relationships:
  • One client has many areas (1:N with de_app_areas)
  • One client has many users (1:N with de_app_users)
  • One client has many games (1:N with de_app_games)
Example Data:
INSERT INTO de_app_clients (id, name) VALUES
('client_a', 'Acme Corporation'),
('client_b', 'Tech Innovators Inc.');

de_app_areas

Departments or organizational units within a client company.
ColumnTypeConstraintsDescription
idVARCHAR(50)PRIMARY KEYUnique area identifier
nameVARCHAR(100)NOT NULLArea/department name
colorVARCHAR(20)DEFAULT ‘#000000’UI color for visualization
Relationships:
  • Each area belongs to one client (via implicit client association)
  • One area has many users (1:N with de_app_users)
Example Data:
INSERT INTO de_app_areas (id, name, color) VALUES
('area_tech', 'Tecnología', '#3b82f6'),
('area_hr', 'Recursos Humanos', '#ef4444'),
('area_fin', 'Finanzas', '#10b981'),
('area_ops', 'Operaciones', '#f59e0b');
The color field uses hex color codes for consistent area visualization in analytics dashboards.

de_app_users

Participant users who engage with ethical dilemma scenarios.
ColumnTypeConstraintsDescription
idVARCHAR(50)PRIMARY KEYUnique user identifier
nameVARCHAR(100)NOT NULLFull name
emailVARCHAR(100)NOT NULLEmail address
avatarVARCHAR(10)DEFAULT ’👤‘Emoji avatar for UI
areaVARCHAR(100)NULLDepartment assignment
createdAtDATETIMEDEFAULT CURRENT_TIMESTAMPAccount creation
lastActiveDATETIMEDEFAULT CURRENT_TIMESTAMPLast activity timestamp
Relationships:
  • Each user belongs to one client (implicit via area or direct FK)
  • Each user belongs to one area (N:1 with de_app_areas)
  • One user has many sessions (1:N with de_app_sessions)
  • One user has many answers (1:N with de_app_answers)
Example Data:
INSERT INTO de_app_users (id, name, email, avatar, area) VALUES
('u1', 'Carlos Mendez', '[email protected]', '👨', 'Ventas'),
('u2', 'Ana Lopez', '[email protected]', '👩', 'Marketing');
The area column contains denormalized string values for performance. In a normalized design, this would be a foreign key to de_app_areas.id.

de_app_games

Ethical dilemma scenarios (gamified question sets).
ColumnTypeConstraintsDescription
idVARCHAR(50)PRIMARY KEYUnique game identifier
nameVARCHAR(100)NOT NULLGame/dilemma title
categoryVARCHAR(50)NOT NULLClassification (Logic, Tech, Business, etc.)
clientVARCHAR(100)NULLClient owner
areaVARCHAR(100)NULLTarget department
iconVARCHAR(50)DEFAULT ’🎮‘Emoji icon
clientLogoVARCHAR(255)NULLLogo URL
Relationships:
  • Each game belongs to one client
  • One game has many questions (1:N with de_app_game_questions)
  • One game has many sessions (1:N with de_app_sessions)
Example Data:
INSERT INTO de_app_games (id, name, category, client, icon, area) VALUES
('game_1', 'Dilema del Puente', 'Logic', 'Cliente A', '🌉', 'Ventas'),
('game_2', 'Ética en la IA', 'Tech', 'Cliente B', '🤖', 'Marketing');

de_app_game_questions

Individual questions within a game/dilemma scenario.
ColumnTypeConstraintsDescription
idINTPRIMARY KEY AUTO_INCREMENTQuestion ID
game_idVARCHAR(50)FOREIGN KEY → de_app_games.idParent game
question_textTEXTNOT NULLQuestion content
order_numINTNOT NULLDisplay sequence
difficultyVARCHAR(20)NULLDifficulty level
correct_answerTEXTNULLExpected answer
Relationships:
  • Each question belongs to one game (N:1 with de_app_games)
  • One question has many answers (1:N with de_app_answers)
Questions are ordered using order_num to control presentation sequence in the game flow.

de_app_sessions

User gameplay sessions tracking participation and performance.
ColumnTypeConstraintsDescription
idVARCHAR(50)PRIMARY KEYSession identifier
userIdVARCHAR(50)FOREIGN KEY → de_app_users.idParticipant
gameIdVARCHAR(50)FOREIGN KEY → de_app_games.idGame played
scoreINTDEFAULT 0Achieved score
durationINTDEFAULT 0Time spent (minutes)
startedAtDATETIMEDEFAULT CURRENT_TIMESTAMPSession start
endedAtDATETIMEDEFAULT CURRENT_TIMESTAMPSession end
Foreign Key Constraints:
CONSTRAINT fk_session_user FOREIGN KEY (userId) 
    REFERENCES de_app_users(id) ON DELETE CASCADE,
CONSTRAINT fk_session_game FOREIGN KEY (gameId) 
    REFERENCES de_app_games(id) ON DELETE CASCADE
Example Data:
INSERT INTO de_app_sessions (id, userId, gameId, score, duration) VALUES
('s1', 'u1', 'game_1', 850, 15),
('s2', 'u2', 'game_1', 920, 12);
The ON DELETE CASCADE constraint ensures session data is automatically cleaned up when users or games are deleted.

de_app_answers

Individual question responses from users during sessions.
ColumnTypeConstraintsDescription
idVARCHAR(50)PRIMARY KEYAnswer identifier
sessionIdVARCHAR(50)FOREIGN KEY → de_app_sessions.idSession context
questionIdINTNULLQuestion reference
responseValueINTNULLAnswer score/value
responseTimeINTNULLTime taken (seconds)
Relationships:
  • Each answer belongs to one session
  • Each answer relates to one question
Example Data:
INSERT INTO de_app_answers (id, sessionId, questionId, responseValue, responseTime) VALUES
('am_1', 'sm_1', 1, 100, 5),
('am_2', 'sm_7', 1, 40, 15);

Authentication Tables

These tables support WordPress-compatible authentication:

de_users

Core user authentication table (WordPress compatible).
ColumnTypeConstraintsDescription
IDBIGINTPRIMARY KEY AUTO_INCREMENTUser ID
user_loginVARCHAR(60)NOT NULL UNIQUEUsername
user_passVARCHAR(255)NOT NULLHashed password
user_emailVARCHAR(100)NOT NULLEmail address
display_nameVARCHAR(250)NOT NULLDisplay name
user_activation_keyVARCHAR(255)NULLPassword reset token
user_registeredDATETIMEDEFAULT CURRENT_TIMESTAMPRegistration date
Password Hashing:
  • Primary: WordPress Phpass (8 rounds)
  • Fallback: Bcrypt compatibility

de_usermeta

User metadata for roles and capabilities.
ColumnTypeConstraintsDescription
umeta_idBIGINTPRIMARY KEY AUTO_INCREMENTMeta ID
user_idBIGINTFOREIGN KEY → de_users.IDUser reference
meta_keyVARCHAR(255)NOT NULLMetadata key
meta_valueLONGTEXTNULLSerialized value
Common Meta Keys:
  • de_capabilities: Serialized role array
  • wp_capabilities: WordPress roles (fallback)
Example Capabilities:
a:1:{s:13:"administrator";b:1;}
// Unserializes to: ['administrator' => true]

Indexes and Performance

Primary Indexes

All tables use primary keys for efficient row lookup:
PRIMARY KEY (id)  -- Most tables
PRIMARY KEY (ID)  -- WordPress-compatible tables

Foreign Key Indexes

Automatic indexes on foreign key columns:
KEY userId (userId)  -- de_app_sessions
KEY gameId (gameId)  -- de_app_sessions
For production optimization:
-- User lookups by email
CREATE INDEX idx_user_email ON de_app_users(email);

-- Session queries by date range
CREATE INDEX idx_session_dates ON de_app_sessions(startedAt, endedAt);

-- Game filtering by client
CREATE INDEX idx_game_client ON de_app_games(client);

Data Integrity

Foreign Key Constraints

The schema enforces referential integrity:
  • CASCADE DELETE: Sessions are deleted when users or games are removed
  • RESTRICT: Prevents deletion of areas with assigned users (implementation-specific)

Data Validation

Application Layer:
  • Email format validation via PHP filter functions
  • Username uniqueness enforced by UNIQUE constraint
  • Required fields validated before INSERT
Database Layer:
  • NOT NULL constraints on critical columns
  • DEFAULT values for timestamps and UI elements
  • CHECK constraints for value ranges (MySQL 8.0+)

Schema Migration

The database includes conditional schema updates:
-- Add column only if it doesn't exist
SET @preparedStatement = (SELECT IF(
  (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS
   WHERE table_name = 'de_app_users' AND column_name = 'area') > 0,
  "SELECT 1",
  "ALTER TABLE de_app_users ADD area VARCHAR(100) DEFAULT NULL;"
));
PREPARE alterIfNotExists FROM @preparedStatement;
EXECUTE alterIfNotExists;
This pattern allows safe re-execution of migration scripts without duplicate column errors.

Sample Queries

Get User Participation Summary

SELECT 
    u.name,
    u.email,
    u.area,
    COUNT(s.id) as sessions_completed,
    AVG(s.score) as average_score,
    SUM(s.duration) as total_minutes
FROM de_app_users u
LEFT JOIN de_app_sessions s ON u.id = s.userId
GROUP BY u.id
ORDER BY average_score DESC;

Game Performance by Area

SELECT 
    g.name as game_name,
    u.area,
    COUNT(s.id) as participants,
    AVG(s.score) as avg_score,
    AVG(s.duration) as avg_duration
FROM de_app_sessions s
JOIN de_app_games g ON s.gameId = g.id
JOIN de_app_users u ON s.userId = u.id
GROUP BY g.id, u.area
ORDER BY g.name, avg_score DESC;

Find Users with Failed Questions

SELECT 
    u.name,
    a.questionId,
    a.responseValue,
    a.responseTime
FROM de_app_answers a
JOIN de_app_sessions s ON a.sessionId = s.id
JOIN de_app_users u ON s.userId = u.id
WHERE a.responseValue < 70  -- Below passing threshold
ORDER BY u.name, a.questionId;

Database Initialization

To set up the database:
  1. Create Database:
    CREATE DATABASE dilemas CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
    
  2. Import Schema:
    mysql -u root -p dilemas < sql/database.sql
    
  3. Import Users (Optional):
    mysql -u root -p dilemas < sql/users.sql
    
  4. Apply Area Schema:
    mysql -u root -p dilemas < sql/areas_schema.sql
    

Next Steps

Build docs developers (and LLMs) love