Plataforma del Departamento de Educación de Puerto Rico

Descripción
Lideré el desarrollo completo y rediseño del sitio web oficial del Departamento de Educación de Puerto Rico (DEPR), una institución gubernamental clave responsable de la educación pública en todo Puerto Rico.
Este proyecto representó un desafío significativo ya que requirió trabajar en la nueva plataforma mientras simultáneamente se mantenía y actualizaba la versión anterior que estaba en producción. La migración desde el tema Avada a una solución WordPress personalizada implicó la transferencia cuidadosa de grandes volúmenes de contenido educativo, recursos para docentes, información administrativa y datos históricos.
La nueva plataforma fue diseñada con un enfoque en la accesibilidad, asegurando que todos los usuarios, incluidas las personas con discapacidades, pudieran acceder fácilmente a la información educativa crítica. Implementé características avanzadas como un sistema de búsqueda mejorado, integración con aplicaciones internas del departamento, y una arquitectura de información optimizada para facilitar la navegación a través de los numerosos programas y servicios ofrecidos por el DEPR.
El sitio también incorpora funcionalidades específicas para el sector educativo, como calendarios académicos interactivos, directorios de escuelas, acceso a recursos educativos digitales, y sistemas de citas en línea para servicios administrativos, todo ello manteniendo altos estándares de seguridad y cumplimiento con las normativas gubernamentales.
Tecnologías Utilizadas
WordPress
CMS principal para el desarrollo y gestión de contenidos
PHP
Desarrollo de funcionalidades personalizadas y plugins específicos
MySQL
Base de datos optimizada para alto rendimiento y seguridad
JavaScript
Interactividad y mejoras de experiencia de usuario
HTML5/CSS3
Maquetación semántica y diseño responsivo accesible
WCAG 2.1
Implementación de estándares de accesibilidad web
Desafíos
Desarrollo paralelo
Trabajar en la nueva plataforma mientras simultáneamente se mantenía y actualizaba la versión anterior en producción, garantizando la continuidad del servicio para estudiantes, padres y educadores.
Migración desde Avada
Migrar grandes volúmenes de contenido desde el tema Avada a una solución WordPress personalizada, preservando la integridad de los datos y la estructura de la información.
Accesibilidad universal
Asegurar que el sitio cumpliera con estrictos estándares de accesibilidad para servir a todos los ciudadanos, incluyendo personas con diversas discapacidades.
Integración de sistemas
Integrar el sitio web con múltiples aplicaciones internas y sistemas del departamento de educación, manteniendo la seguridad y la coherencia de los datos.
Soluciones
Estrategia de migración por fases
Implementé un enfoque de migración gradual que permitió transferir y validar el contenido por secciones, minimizando el riesgo y asegurando la continuidad del servicio.
Desarrollo de tema personalizado
Creé un tema WordPress completamente personalizado que se adaptaba exactamente a las necesidades específicas del departamento, superando las limitaciones del tema Avada anterior.
Implementación WCAG 2.1
Desarrollé el sitio siguiendo rigurosamente las pautas WCAG 2.1 nivel AA, incluyendo navegación por teclado, compatibilidad con lectores de pantalla y contraste de color adecuado.
Arquitectura de API
Diseñé una arquitectura de API robusta que permite la comunicación segura entre el sitio web público y los sistemas internos del departamento, facilitando la integración de servicios.
Galería

Página principal del Departamento de Educación de Puerto Rico

Versión móvil optimizada del sitio

Sección de servicios educativos
Ejemplo de Código
from django.db import models
from django.contrib.auth.models import User
from django.utils.text import slugify
from django.urls import reverse
import uuid
class Category(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
description = models.TextField(blank=True)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.name
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)
super().save(*args, **kwargs)
class Product(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
name = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="products")
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.PositiveIntegerField(default=0)
available = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
image = models.ImageField(upload_to='products/', blank=True, null=True)
featured = models.BooleanField(default=False)
class Meta:
ordering = ['-created_at']
def __str__(self):
return self.name
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)
super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('product_detail', kwargs={'slug': self.slug})
@property
def is_in_stock(self):
return self.stock > 0
class Order(models.Model):
STATUS_CHOICES = (
('pending', 'Pending'),
('processing', 'Processing'),
('shipped', 'Shipped'),
('delivered', 'Delivered'),
('cancelled', 'Cancelled'),
)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name="orders")
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
shipping_address = models.TextField()
total_amount = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return f"Order {self.id} - {self.user.username}"
@property
def order_items(self):
return self.items.all()
@property
def item_count(self):
return sum(item.quantity for item in self.order_items)
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name="items")
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
price = models.DecimalField(max_digits=10, decimal_places=2)
def __str__(self):
return f"{self.quantity} x {self.product.name}"
@property
def total_price(self):
return self.price * self.quantity
# Views example (in views.py)
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView
from .models import Product, Category
class ProductListView(ListView):
model = Product
template_name = 'shop/product_list.html'
context_object_name = 'products'
paginate_by = 12
def get_queryset(self):
queryset = Product.objects.filter(available=True)
category_slug = self.kwargs.get('category_slug')
if category_slug:
category = get_object_or_404(Category, slug=category_slug)
queryset = queryset.filter(category=category)
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['categories'] = Category.objects.all()
return context
class ProductDetailView(DetailView):
model = Product
template_name = 'shop/product_detail.html'
context_object_name = 'product'
slug_url_kwarg = 'slug'
Habilidades Python
¿Interesado en un proyecto similar?
Si estás buscando implementar una solución en Python o tienes un proyecto en mente que requiera habilidades de desarrollo similares, no dudes en contactarme para discutir cómo puedo ayudarte.
Contactar