Vecinly: un SaaS per a comunitats de veïns
Vecinly és la plataforma tot en un per gestionar comunitats de propietaris: incidències, reserves, comptabilitat, enquestes, proveïdors, tasques i comunicació. La vaig construir sencera i l’opero jo: l’API, la web, les dues apps i la infraestructura. És en producció, amb clients de pagament.
Veure vecinly.comLa web en producció, en 11 idiomesEn xifres
01
Context
El problema
Qui pateix la gestió d’una comunitat és el president, que no cobra per fer-ho, o l’administrador de finques, que porta desenes de comunitats alhora. Les incidències es perden en un grup de WhatsApp, els comptes viuen en un full que només entén qui el va fer i ningú no sap en quin punt és res sense preguntar.
Un producte per a això ha de servir perfils molt diferents (veïns, presidents, administradors, proveïdors i porters) sense que cap vegi el que no li toca. I com que guarda actes, quotes i dades personals de veïns d’11 països, la seguretat és el primer.
Què fa
Uns 50 dominis de negoci, dels quals sis sostenen el dia a dia d’una comunitat:
- IncidènciesEn un tauler per estats: s’obre, s’assigna i es tanca, i qui la va reportar veu en quin punt és.
- ComptabilitatMoviments amb les seves partides i el seu saldo, en lloc d’un full de càlcul.
- FacturacióFactures de la comunitat enllaçades amb la comptabilitat i amb el cobrament recurrent.
- XatVeïns, president, administrador i proveïdors parlen dins del producte, en temps real.
- Enquestes i juntesConsultes d’un clic, convocatòries i seguiment de les reunions.
- ReservesLa pista o la sala es reserven des de l’app, amb el calendari a la vista de tothom.
02
Arquitectura
Tres clients, una sola API
La web, l’app d’iOS i la d’Android parlen amb el mateix servei. Les regles de negoci i els permisos viuen en un únic lloc: una regla s’escriu una vegada i arriba als tres clients, i la web i les apps no es poden comportar de manera diferent.
Un monòlit hexagonal, per a aquesta fase
En un MVP, el que importa és validar la idea: que el desenvolupament sigui àgil, que desplegar sigui senzill i que els costos es mantinguin baixos. Un monòlit ben construït, amb les fronteres entre dominis clares, és una opció molt vàlida per a això: una sola base de codi, un sol desplegament i res de xarxa entre les peces. Els microserveis són la millor opció quan la situació ho requereix, i en aquesta fase hauria estat una mala idea: molta complexitat per a un producte que encara havia de demostrar que algú el volia.
| Capa | Què conté | Regla |
|---|---|---|
| Domini | Entitats i regles de negoci (~230 models) | Sense Spring ni base de dades |
| Casos d’ús | Les accions de l’aplicació (~590 en total) | Parlen amb l’exterior només per ports |
| Adaptadors | REST, WebSocket, PostgreSQL, Stripe, Holded, KMS | Implementen els ports; es canvien sense tocar el domini |
El preu és la disciplina: les fronteres entre dominis depenen del disseny i de la revisió, no de la xarxa, i hi ha tests d’arquitectura que les vigilen. Aquesta disciplina és també el que fa possible el pas següent.
El següent pas: cap als microserveis
La fase ha canviat. Ara els objectius són tres: guanyar usuaris, cosa que farà créixer el consum de recursos i el seu cost; obtenir ingressos, que permetran pagar una infraestructura millor; i ampliar el producte amb funcions que van més enllà de validar-lo. Amb aquests objectius sí que toca començar a moure’s cap als microserveis, i és el que estic plantejant.
La complexitat i la feina augmenten, però l’ús de recursos millora molt, sobretot en un entorn serverless. Amb un monòlit, tota l’aplicació escala com un bloc encara que la major part del que fa s’utilitzi poc. Separada, cada peça té la seva pròpia política: els serveis d’ús esporàdic escalen a zero i no costen res mentre ningú no els fa servir, i els que sempre han de respondre a l’instant, com l’inici de sessió o el xat, mantenen una instància encesa per evitar l’arrencada en fred. Com que cada domini ja parla amb la resta a través de ports, separar-ne un és canviar un adaptador, no reescriure’n la lògica.
Els casos d’ús, per àrees
Cada cas d’ús respon a una pregunta concreta d’un perfil concret: «registrar una incidència», «aprovar el pressupost d’un proveïdor», «convocar una junta». Es reparteixen així:
| Àrea | Casos d’ús principals | Operacions |
|---|---|---|
| Comunitat i altes | Crear la comunitat amb un assistent, donar forma a portals i habitatges, importar coeficients, convidar veïns i llogaters, assignar administrador | ~130 |
| Manteniment i proveïdors | Registrar i seguir incidències, assignar tasques, demanar treballs, rebre i aprovar pressupostos i factures de proveïdors | ~120 |
| Comptabilitat | Pressupost anual, quotes per coeficient, grups de despesa, moviments i saldo | ~65 |
| Subscripció i cobraments | Contractar un pla, canviar-lo o cancel·lar-lo, cobrar i emetre la factura | ~55 |
| Comunicació | Xat, comunicats, avisos d’emergència i moderació | ~40 |
| Juntes i decisions | Convocar juntes, votacions amb validesa legal i enquestes | ~35 |
| Documents | Carpetes de la comunitat i de cada propietari, documents legals | ~30 |
| Zones comunes | Reserves i places d’aparcament | ~20 |
| Porters | Alta, assignació a comunitats i el seu dia a dia | ~20 |
Xifres aproximades, comptades al codi l’octubre del 2026. Una operació és una acció de l’API; un cas d’ús en pot servir diverses.
No cal controlar-los tots al mateix nivell, però sí els essencials: quin perfil pot fer què, amb quines dades i què passa després. Aquests en són alguns:
Dues peces, per dins
Darrere de cada pantalla hi ha molts casos d’ús alhora. L’alta d’una comunitat és un flux que encadena país, tipus d’edifici, dades, estructura i pla, i en surten els habitatges, el tier i la subscripció. La comptabilitat és un panell on es creuen pressupost, quotes per coeficient, despeses i pagaments de cada habitatge.


03
Aïllar cada comunitat
Una base de dades per a totes, quatre capes d’aïllament
Centenars de comunitats comparteixen base de dades, i un veí no ha de veure mai res d’una altra. Una base o un esquema per client multiplicaria les migracions i les connexions per cada comunitat nova. Per això l’aïllament és lògic, per comunitat, i se sosté en quatre capes:
| Capa | Com |
|---|---|
| Autorització | Cada ruta declara quin rol i quin pla la permeten; el que no declara res, es denega |
| Consultes | Cada consulta va acotada a una comunitat, i els índexs estan pensats per a això |
| Xifratge | Pràcticament tot es desa xifrat, amb la clau de la seva comunitat |
| Temps real | Les subscripcions al xat i als avisos es deneguen per defecte |
Una clau de xifratge per comunitat
Es xifra pràcticament tota la informació, també la que la normativa europea no obliga a xifrar: dades personals, converses, documents, comptes. Només queda sense xifrar el que de debò no té cap importància. Una clau mestra que no surt mai del KMS embolcalla les claus de dades, i cada comunitat té la seva. L’identificador de la comunitat entra al xifratge com a dada associada: un text xifrat no serveix en una altra comunitat.
Si la clau no arriba del KMS, l’aplicació es nega a arrencar: falla tancada. I per poder cercar una dada xifrada sense desxifrar-la, s’hi desa al costat una empremta criptogràfica (un índex cec): les cerques i la unicitat passen per aquesta empremta.
El cicle d’una petició
Cada petició passa diverses comprovacions abans de tocar una dada, i la clau de la comunitat només es carrega del KMS quan cal.
04
Cobraments
Stripe cobra, Holded factura
Vecinly cobra subscripcions per trams d’habitatges en diversos països de la UE i ha d’emetre factures legals. El cobrament el fa Stripe, amb Stripe Tax. La factura la genera l’aplicació a Holded quan es confirma el pagament, amb l’IVA exacte que va cobrar Stripe, per complir VeriFactu. Les targetes no passen mai pel meu servidor.
Cobrar una sola vegada
Stripe reintenta els seus avisos de pagament i els pot enviar desordenats. Així que, quan se’n rep un, només se’n verifica la signatura, es desa amb clau única i es respon de seguida; la feina real va a part, per una cua.
En processar-lo, es comprova si ja s’havia processat i es marca com a processat en la mateixa transacció que aplica el canvi, perquè una fallada a mitges no deixi un pagament a mitges. I si la subscripció deixa d’estar sana, la comunitat torna al pla gratuït.
05
L’app
Un codi, dues apps
Veïns i presidents necessiten una app; administradors, proveïdors i porters, una altra de molt diferent. Totes dues surten d’un únic codi en Expo i React Native: Vecinly i Vecinly Pro, a iOS i Android, amb el mateix inici de sessió. Les apps no venen res, per les normes de les botigues: el pagament i la creació de comunitats es fan a la web.
Com arriben els avisos
Qualsevol cosa que passa en una comunitat pot generar un avís. El recorregut és sempre el mateix: l’API executa el cas d’ús i desa el canvi a la base de dades; només quan està desat publica un esdeveniment en una cua. Així qui ha fet l’acció no espera que s’enviï res, i mai no arriba un avís d’una cosa que no ha quedat registrada.
Un consumidor recull l’esdeveniment a part, decideix a qui d’aquella comunitat li toca assabentar-se’n i per quin canal ho prefereix cadascú, i el lliura: notificació push a través de Firebase, correu o a l’instant pel canal en directe si té l’app oberta. Si alguna cosa falla, l’esdeveniment es queda a la cua i es reintenta.
06
Producció
Desplegar només amb una etiqueta
Un desplegament equivocat afecta dades reals de comunitats. Per això producció només es desplega des d’una versió etiquetada, i els tests s’executen sobre aquesta mateixa versió. Tornar enrere és desplegar l’etiqueta anterior.
| Què | Com |
|---|---|
| Tests | ~4.680; els d’integració, contra PostgreSQL real en contenidors, mai contra una base simulada |
| Abans de desplegar | Els unitaris i els d’integració crítics: diners, subscripcions, permisos i la comptabilitat |
| Mutation testing | Sobre subscripcions i domini, amb un llindar mínim que no es pot abaixar sense que falli el build |
| Base de dades | Fora de la infraestructura com a codi: cap canvi d’infraestructura no la pot recrear ni esborrar |
| Esquema | Es valida en arrencar contra el codi; si no coincideix, l’aplicació no arrenca |
Migracions sense aturar el servei
Les migracions són sempre idempotents, i expandir i contraure van en versions diferents: primer s’afegeix i s’emplena, i la restricció arriba a la versió següent, perquè una restricció que falla bloqueja tots els desplegaments posteriors.
07
Conclusions
- L’arquitectura acompanya la fase. Un monòlit ben partit per dins era l’adequat per validar el producte; aquestes mateixes fronteres són les que ara permeten repartir-lo en serveis quan créixer ho requereix.
- Aïllar sense multiplicar bases. Quatre capes i una clau per comunitat donen aïllament real sense operar centenars de bases de dades.
- Cobrar és un problema d’idempotència. El doble cobrament no l’evita la passarel·la: l’eviten la clau única, la transacció i els escombratges.
- Fallar tancat. Sense clau no arrenca, sense regla es denega i sense subscripció sana es baixa al pla gratuït.


