Arquitectura

Como esta organizado el codigo y por que cambiar de proveedor no obliga a reescribir el producto.

ApisKit usa arquitectura hexagonal, tambien llamada puertos y adaptadores. En una frase: el corazon de tu negocio no sabe que existe Firebase, ni Stripe, ni Next.js. Sabe que existe un contrato, y alguien lo cumple.

Eso no es purismo academico. Es lo que hace que cambiar de proveedor sea escribir un fichero nuevo en vez de reescribir el producto.

Las capas

src/
  core/          el dominio, sin nada de fuera
    entities/    objetos del negocio (User, SupportTicket, Trial,
                 CreditPurchase, Payment, DocPage)
    ports/       contratos que el exterior debe cumplir
                 (AuthPort, UserPort, PaymentPort, StoragePort, DocsPort)
  adapters/      quien cumple esos contratos de verdad
    database/    Firebase y Firestore (y uno en memoria, para las pruebas)
    payment/     Stripe
  app/           rutas, API y paginas de Next.js: aqui se enchufa todo
  presentation/  componentes de React
  lib/           utilidades transversales (sesion, correo, errores, SEO,
                 limites de peticiones, pintado de documentacion)
  config/        product.ts (identidad), idiomas, tema, firebase, precios
  locales/       traducciones es/ y en/

La regla de dependencia

Las dependencias apuntan hacia dentro, nunca hacia fuera:

  • core/ no importa nada del exterior. Ni una libreria. Define interfaces.
  • adapters/ conocen a core y a los SDK de fuera, y los conectan. Los proveedores viven aqui y en ningun otro sitio.
  • app/ y presentation/ usan core y los adaptadores, nunca al reves.

Si algun dia buscas "stripe" en src/core/, no debe aparecer. El dia que aparezca, la ventaja se ha perdido.

Un puerto tambien se parte por permisos

El uso normal de un puerto es cambiar de proveedor. Hay otro que se aprovecha menos y evita fallos silenciosos: partirlo segun lo que cada llamante tiene permitido hacer.

DocsPort son dos interfaces, no una:

  • DocsReadPort, que solo sabe leer paginas publicadas.
  • DocsAdminPort, que lo puede todo, borradores incluidos.

A la pagina publica se le entrega el puerto de lectura. Asi no es que no deba pedir un borrador: es que no tiene ningun metodo para pedirlo. La fuga no se evita con disciplina ni con una revision, se evita porque no se puede escribir.

Usa el mismo truco donde una fuga seria silenciosa.

La consecuencia practica

Cambiar de base de datos o de pasarela de pago es escribir un adaptador nuevo contra el mismo puerto y cambiar donde se enchufa. Tus reglas de negocio no se tocan.

Es tambien lo que permite que piezas enteras, como el sistema de soporte, se puedan sacar y llevar a otra aplicacion: hablan con el resto solo a traves de un contrato pequeno y escrito.

Identidad y configuracion

src/config/product.ts es la fuente unica de la identidad: nombre, empresa, direcciones, correo de soporte. Se valida con Zod al cargar el modulo, asi que una configuracion mal puesta falla al arrancar en vez de desplegarse rota.

De ahi beben el SEO, los correos, los datos estructurados, la cabecera, el pie y los textos traducidos. Por eso se re-marca con un comando: solo hay un sitio que cambiar.

Los dos idiomas

src/config/i18n da el proveedor y la funcion t(). Las traducciones estan en src/locales/{es,en}/<espacio>.json. Los distintivos de identidad ({brand}, {company}, {supportEmail}, {baseUrl}) se inyectan en cada texto, para que nadie escriba el nombre de la marca a mano.

npm run verify:i18n comprueba que espanol e ingles son simetricos y que cada t() apunta a una clave que existe.

Donde va tu producto

Tu dominio son entidades y puertos nuevos en core/, con sus adaptadores en adapters/, expuestos por rutas en app/ y componentes en presentation/.

Si adaptar tu producto te obliga a cambiar codigo que ya estaba en core/, tratalo como un fallo de la plantilla y arreglalo ahi, no como un parche para tu caso. Esa es la diferencia entre una base que aguanta y una que se pudre.