- Python 50.7%
- HTML 35.9%
- CSS 12.7%
- Dockerfile 0.4%
- JavaScript 0.3%
- /admin sin barra final lo capturaba la ruta comodin /{locale} del sitio
publico y devolvia 404: se anade una redireccion explicita a /admin/.
- Sin sesion, require_user lanzaba un HTTPException 307 cuya cabecera
Location se perdia en el manejador global de errores, asi que el navegador
recibia una redireccion vacia. Ahora usa la excepcion LoginRequired y una
redireccion 303 a /admin/login.
|
||
|---|---|---|
| app | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| AYRE.jpg | ||
| docker-compose.yml | ||
| Dockerfile | ||
| README.md | ||
| requirements.txt | ||
Web de AYRE S.L. Ingenieros
Web corporativa multiidioma con panel de administración propio, pensada para desplegarse con Docker detrás de Nginx Proxy Manager.
- Front público: portada, proyectos (con ficha y filtros por categoría), servicios, sobre nosotros / equipo y contacto.
- Panel en
/admin: alta y edición de proyectos con fotos, servicios, equipo, categorías, datos de contacto, idiomas y bandeja de mensajes. - Idiomas: español e inglés de serie; añadir otro no requiere tocar la base de datos (ver más abajo).
- Formulario de contacto: guarda el mensaje en la base de datos y avisa por correo mediante el SMTP corporativo. Si el correo falla, el mensaje no se pierde.
Stack: FastAPI + Jinja2 + SQLAlchemy + PostgreSQL. Sin frameworks de JavaScript ni dependencias externas en el navegador (todo se sirve desde el propio dominio).
1. Puesta en marcha
cp .env.example .env
nano .env # rellena las claves (ver abajo)
docker compose up -d --build
La web queda escuchando en 127.0.0.1:8080 del servidor. El panel está en
http://<tu-dominio>/admin.
Valores del .env que hay que tocar sí o sí:
| Variable | Qué es |
|---|---|
SECRET_KEY |
Firma las cookies de sesión. Genérala con python -c "import secrets; print(secrets.token_urlsafe(48))" |
POSTGRES_PASSWORD |
Contraseña de la base de datos |
ADMIN_EMAIL / ADMIN_PASSWORD |
Usuario inicial del panel (solo se usa la primera vez) |
SITE_URL |
URL pública final, p. ej. https://www.ayreingenieria.com |
SMTP_* |
Datos del correo saliente |
2. Nginx Proxy Manager
Crea un Proxy Host con:
- Domain Names:
ayreingenieria.com,www.ayreingenieria.com - Scheme:
http· Forward Hostname/IP:127.0.0.1· Port:8080 - Block Common Exploits: sí · Websockets: no hace falta
- SSL: certificado Let's Encrypt + Force SSL + HTTP/2
- Advanced → pega esto (si no, las fotos de más de 1 MB darán error 413):
client_max_body_size 25m;
Si tu Nginx Proxy Manager corre en Docker y prefieres que hablen por red interna
en lugar de por el puerto del host: en docker-compose.yml comenta la línea de
ports, descomenta los bloques networks (poniendo el nombre real de la red de
NPM) y en el proxy host apunta a ayre-web puerto 8000.
3. Primeros pasos en el panel
- Entra en
/admincon el usuario de.envy cambia la contraseña en Mi cuenta. - Datos del sitio: teléfono, dirección, CIF, LinkedIn, horario, mapa y los textos de portada en cada idioma.
- Proyectos: borra los cuatro de ejemplo y sube los tuyos.
- Cuando ya no quieras contenido de ejemplo, pon
SEED_DEMO=falseen.envy reinicia (docker compose up -d).
Publicar un proyecto
Cada proyecto tiene una pestaña por idioma con título, resumen (lo que se ve en la tarjeta), descripción (los párrafos se separan con una línea en blanco) y alcance de los trabajos (una línea por punto). La ficha lateral se rellena con cliente, ubicación, año y categoría.
Las fotos se redimensionan y comprimen solas al guardar: sube el original tal cual. La de portada conviene que sea apaisada y de al menos 1200 px de ancho.
4. Añadir un idioma nuevo
- Panel → Idiomas → añade el código (
fr,pt...) y márcalo como activo. - Copia
app/locales/es.jsonaapp/locales/<código>.jsony traduce los textos fijos (menús, botones, etiquetas). La clave_pathsdefine los trozos de URL de cada sección en ese idioma. docker compose up -d --buildpara que el fichero entre en la imagen.- En cada proyecto/servicio aparecerá una pestaña nueva para traducir el contenido. Lo que dejes vacío se muestra en el idioma por defecto.
5. Correo
SMTP_TLS admite starttls (puerto 587, lo habitual), ssl (puerto 465) o
none. Si dejas SMTP_HOST vacío el envío queda desactivado y los mensajes
solo se ven en el panel — el escritorio te avisa de ello.
Con SEND_AUTOREPLY=true el visitante recibe además un acuse de recibo.
6. Copias de seguridad
# Base de datos
docker exec ayre-db pg_dump -U ayre ayre > backup_$(date +%F).sql
# Fotos
tar czf uploads_$(date +%F).tar.gz data/uploads
Restaurar: cat backup.sql | docker exec -i ayre-db psql -U ayre ayre
7. Actualizar
git pull # o edita los ficheros directamente
docker compose up -d --build
El esquema de la base de datos se crea solo al arrancar. Los datos y las fotos
viven en el volumen db_data y en data/uploads, así que sobreviven a las
reconstrucciones.
8. Estructura
app/
main.py arranque, rutas sueltas (sitemap, robots, 404)
config.py variables de entorno
models.py tablas; el contenido traducible vive en tablas *_translations
routers/public.py web pública
routers/admin.py panel
i18n.py textos fijos y slugs de las URL por idioma
utils.py imágenes, slugs, filtros de plantilla
mailer.py envío SMTP
seed.py idiomas, usuario inicial y contenido de ejemplo
locales/ es.json, en.json...
templates/ plantillas Jinja2 (public/ y admin/)
static/ CSS, JS y logotipos
data/uploads/ fotos subidas desde el panel (volumen Docker)
9. Notas
- El panel usa cookies de sesión firmadas y token CSRF en todos los formularios. Las contraseñas se guardan con PBKDF2-SHA256.
- El formulario de contacto lleva trampa antispam (campo oculto) y validación de servidor; no usa servicios de terceros ni cookies de seguimiento.
- La web no carga nada desde CDNs externos: tipografía del sistema, iconos SVG en línea y CSS propio. Sin cookies de terceros, sin banner de consentimiento.
- Rutas por idioma:
/es/proyectos/<slug>y/en/projects/<slug>, conhreflangysitemap.xmlgenerados automáticamente.