Durant deu mòduls has tingut un exemple guiat: Nómada Tasques es construïa davant teu, lliçó a lliçó, i cada concepte nou arribava amb el seu tros de codi ja pensat. Això s'acaba aquí. En aquest mòdul construeixes el teu propi producte, sol, amb el mateix mètode i sense que ningú et doni el codi. Nómada Tasques no desapareix: passa a ser la referència —sis tasques, 48 hores, regles R1–R10, 124 proves, 58,3 kB en tres peticions, LCP d'1,9 s— contra la qual compararàs el que facis. I aquesta primera lliçó no escriu ni una línia de lògica de negoci a propòsit, perquè l'error més car d'un projecte propi no és un undefined inesperat: és començar a programar sense saber què s'està construint. Aquí aprendràs a convertir una idea en un pla defensable: triar el producte, retallar-lo fins a un MVP honest i escriure negre sobre blanc el que no faràs; redactar històries d'usuari amb criteris d'acceptació i prioritzar-les amb MoSCoW; dissenyar el model de dades i les regles de negoci —les noves R11 a R15— abans de tocar l'editor; decidir l'arquitectura per capes i les fronteres que no es creuen; muntar el repositori, la cadena d'eines i el flux de Git; planificar en fites amb un Gantt i una estimació que no t'enganyi; i fixar des del minut zero la Definició de Fet i el pressupost de rendiment i accessibilitat. En acabar tindràs tres lliurables reals: el document d'abast, el model de dades amb les seves regles, i un repositori inicialitzat i verd.

Contingut

  1. Què canvia a partir d'ara
  2. El producte per defecte: Òrbita
  3. Tres alternatives de domini amb el mateix mètode
  4. Delimitar l'abast: el MVP
  5. La llista del que NO es farà
  6. Històries d'usuari amb criteris d'acceptació
  7. Prioritzar amb MoSCoW
  8. El model de dades, escrit abans de programar
  9. Les regles de negoci noves: R11 a R15
  10. L'arquitectura per capes i les fronteres que no es creuen
  11. L'entorn: repositori i cadena d'eines
  12. L'estructura de carpetes de partida
  13. Git de debò: branques, commits i revisions
  14. Fites i estimació honesta
  15. La Definició de Fet
  16. El pressupost de rendiment i accessibilitat
  17. La plantilla de README.md
  18. Errors Habituals i Consells
  19. Exercicis
  20. Conclusió

  1. Què canvia a partir d'ara

Fins a la lliçó 10-06, el curs funcionava així: s'explicava un concepte, s'aplicava a Nómada Tasques, i el codi apareixia. Tu el llegies, l'entenies, l'adaptaves als exercicis. És la manera correcta d'aprendre els fonaments, i és exactament el que calia fer.

Però hi ha una diferència enorme entre entendre codi aliè i produir codi propi des de zero, i no se salva llegint més. Se salva construint. Aquest mòdul és aquesta construcció.

A partir d'aquí canvien tres coses:

Abans (M1–M10) Ara (M11)
El codi se't donava resolt El codi l'escrius tu; aquí reps mètode, plantilles i criteris
Els exercicis eren de pràctica Els exercicis són lliurables del projecte
Les solucions eren el codi correcte Les solucions són criteris d'acceptació i rúbriques
El projecte era Nómada Tasques El projecte és teu; Nómada Tasques és la referència
L'objectiu era aprendre un concepte L'objectiu és acabar un producte

Aquest últim punt mereix èmfasi. L'habilitat que separa qui sap JavaScript de qui és desenvolupador no és conèixer més mètodes d'array: és acabar coses. Acabar significa que funciona, que està provat, que es pot desplegar, que una altra persona ho entén i que tu pots defensar per què està fet així. Aquest és el llistó d'aquest mòdul.

I hi ha un advertiment honest que convé llegir a poc a poc. La part difícil d'un projecte propi no és tècnica. És que ningú no et diu quan has acabat, ningú no et corregeix l'abast quan creix, i ningú no t'avisa que portes tres dies polint una animació mentre la funcionalitat principal continua a mitges. El mètode d'aquesta lliçó existeix precisament per posar aquestes baranes abans que les necessitis.

  1. El producte per defecte: Òrbita

El producte per defecte d'aquest mòdul es diu Òrbita. És una aplicació de gestió de treball per a equips petits: la mateixa família que Nómada Tasques, però clarament més ambiciosa, amb sis extensions que al curs no es van implementar mai i que hauràs de resoldre pel teu compte.

Nota sobre les dades. Òrbita, els seus usuaris d'exemple i qualsevol organització que aparegui a les teves dades de prova han de ser ficticis. No facis servir noms, correus ni dades reals de companys, clients o familiars, ni tan sols «per provar»: així que això arriba a un repositori públic o a un desplegament, deixa de ser una prova i passa a ser un tractament de dades personals. A la lliçó 11-03 i a la 11-05 hi tornarem amb detall.

Les sis extensions sobre Nómada Tasques són aquestes:

# Extensió Què afegeix sobre Nómada Tasques Concepte del curs que reutilitza
E1 Usuaris i assignació Les persones deixen de ser un string i passen a ser entitats amb id, rol i permisos; responsable i revisor són referències 04-01, 05-02, 05-03
E2 Subtasques Una tasca es pot descompondre en un arbre de fins a tres nivells, amb hores i progrés agregats 03-07 (recursivitat)
E3 Etiquetes amb filtre múltiple Filtrar per diverses etiquetes alhora, amb mode I / O, combinable amb la resta de filtres 03-06, 04-05
E4 Vista de calendari Una graella mensual que situa les tasques per dataLimit, amb navegació entre mesos 04-04, 06-05, Intl de 07-06
E5 Informe de càrrega exportable Càrrega per persona i setmana, exportable a CSV i JSON descarregable des del navegador 04-05 (reduce), 07-06 (Blob)
E6 Historial de canvis Registre immutable de qui va canviar què i quan, amb vista d'auditoria per tasca 04-08, 05-03

Cap de les sis és decorativa. Cadascuna obliga a resoldre un problema real que Nómada Tasques esquivava:

  • E1 trenca la simplificació de responsable: 'Iván'. Així que hi ha entitats referenciades, apareixen la integritat referencial (què passa amb les tasques d'un usuari que s'esborra?) i els permisos.
  • E2 converteix una llista plana en un arbre. Tot el que era array.filter(...) passa a necessitar recorregut recursiu, i les hores totals deixen de ser una suma directa.
  • E3 sembla trivial i no ho és: combinar N filtres amb dues semàntiques diferents i mantenir-los a la URL (06-04, encaminador) exigeix pensar l'estat.
  • E4 és la primera vista que no és una llista, i per tant la primera que no pots resoldre copiant TaulerVista.
  • E5 és la primera funcionalitat que produeix un fitxer, amb tot el que això implica: format, codificació, noms, i el fet que un CSV mal escapat es trenca així que un títol porta una coma.
  • E6 introdueix dades immutables i creixents, que és exactament el tipus de dada que fa esclatar localStorage (lliçó 11-03).

Òrbita en una frase, que és com hauries de poder descriure qualsevol producte:

Òrbita és una aplicació web que permet a un equip petit planificar la seva feina en tasques i subtasques, veure qui està sobrecarregat i quan vencen les coses, i saber en tot moment qui va canviar què.

Si no pots escriure aquesta frase per al teu producte, encara no saps què estàs construint.

  1. Tres alternatives de domini amb el mateix mètode

Si el domini de les tasques t'avorreix —és una raó perfectament legítima; hi passaràs setmanes—, tria'n un altre. El mètode és idèntic i el mòdul sencer funciona igual. Aquestes són les tres alternatives proposades, cadascuna amb el mapatge de les sis extensions:

Extensió Òrbita (tasques) Aforament (reserves de sala) Ratxa (hàbits) Prestatgeria (inventari)
E1 · Usuaris Responsable i revisor Qui reserva i qui autoritza Persona i grup de suport Responsable de magatzem
E2 · Arbre Subtasques Sala → subespais (taula, cabina) Hàbit → passos diaris Categoria → subcategoria → article
E3 · Filtre múltiple Etiquetes Equipament (projector, pissarra) Àmbits (salut, estudi) Etiquetes de producte
E4 · Calendari Data límit La vista central: ocupació per franges Graella de constància mensual Caducitats i reposicions
E5 · Informe Càrrega per persona Ocupació per sala i setmana Ratxa i percentatge de compliment Valoració d'existències
E6 · Historial Qui va canviar què Canvis i cancel·lacions de reserva Registre diari (ja és historial) Moviments d'entrada i sortida
Regla dura característica No tancar amb subtasques obertes No encavalcar dues reserves a la mateixa sala Un registre per hàbit i dia L'estoc mai no pot ser negatiu

Fixa't en l'última fila: cada domini té una regla dura característica que és la que dona personalitat al model i la que més proves necessitarà. A Aforament és l'encavalcament d'intervals, que és un problema clàssic i força més subtil del que sembla. A Ratxa és la unicitat per dia, que obliga a pensar zones horàries. A Prestatgeria és una invariant numèrica que cal defensar a totes les operacions.

Criteri per triar, en ordre d'importància:

  1. Que t'importi. Hi dedicaràs moltes hores i ningú no t'hi obligarà. La motivació és un recurs de projecte tan real com el temps.
  2. Que el puguis ensenyar a algú. Si en una entrevista pots explicar el domini en trenta segons, serveix.
  3. Que tingui almenys una regla dura no trivial. Un CRUD sense regles no demostra res; és el projecte que fa tothom.
  4. Que hi càpiga. Si la teva idea és «com Jira però millor», no hi cap. Retalla-la fins que hi càpiga, que és justament l'apartat següent.

A la resta del mòdul faré servir Òrbita a tots els exemples, però cada plantilla és directament reutilitzable amb qualsevol dels altres tres dominis. Quan vegis una taula o una plantilla, substitueix-ne els noms i continua.

  1. Delimitar l'abast: el MVP

MVP són les sigles de Minimum Viable Product: producte mínim viable. Les dues paraules importen i gairebé sempre se n'entén malament una de les dues.

  • Mínim no vol dir «xusquer». Vol dir que no hi ha res que puguis treure sense que deixi de resoldre el problema.
  • Viable no vol dir «una demo». Vol dir que algú el podria fer servir de debò per al que promet.

Un MVP d'Òrbita que no permetés marcar una tasca com a feta seria mínim però no viable. Un que tingués temes de color, dreceres de teclat personalitzables i notificacions per correu seria viable però no mínim.

La prova que faig servir per decidir si una cosa entra al MVP és una sola pregunta:

Si això no hi fos, el producte continuaria servint per al que diu la seva frase?

Si la resposta és «sí, incòmode però serveix», no és MVP. Va a la versió 1.1.

Aplicat a Òrbita, aquest és el tall:

Funcionalitat MVP? Raó
Crear, editar i esborrar tasques Sense això no hi ha producte
Canviar d'estat amb les transicions vàlides (R6) És el flux de treball sencer
Assignar responsable (E1) «Qui fa què» és a la frase del producte
Subtasques d'un nivell (E2 parcial) La descomposició és el diferencial; tres nivells poden esperar
Filtre per responsable, estat i etiquetes (E3) Sense filtre, amb 60 tasques el tauler és inútil
Persistència local Un gestor que perd les dades en recarregar no és viable
Historial de canvis (E6) És una promesa explícita de la frase del producte
Informe de càrrega (E5) Sí, mínim La taula en pantalla sí; l'exportació a CSV, no
Vista de calendari (E4) No Útil, però la llista amb ordre per data cobreix la necessitat
Exportar a CSV/JSON No Comoditat, no necessitat
Tres nivells de subtasques No Un nivell demostra l'arbre; tres només afegeixen casos límit
Sincronització amb API No El MVP és d'un sol dispositiu; la 11-03 l'amplia
Temps real multiusuari No Cost altíssim, valor baix en un equip de tres persones
Rols i permisos complets No El MVP assumeix que tots els usuaris són de confiança
Mode fosc, temes, animacions No Cosmètic

De 15 candidats, 8 hi entren. Aquesta proporció (aproximadament la meitat) és normal i saludable. Si el teu MVP conté el 90 % del que se t'ha acudit, no has retallat: has fet una llista de desitjos.

Una regla pràctica de mida, contrastada: un MVP de projecte personal hauria de ser una cosa que puguis construir en 6 a 10 setmanes dedicant-hi entre 6 i 10 hores setmanals. Si la teva estimació honesta (apartat 14) dona més, retalla ara, perquè la teva estimació és optimista, no pessimista.

  1. La llista del que NO es farà

Aquesta és la secció del document d'abast que més gent es salta i la que més projectes salva. Un MVP definit només pel que inclou és ambigu: tot el que no s'esmenta queda en una zona grisa on, un dimarts a la tarda, et semblarà raonable afegir «només una coseta».

Escriure explícitament el que no es farà converteix cada afegit posterior en una decisió conscient en lloc d'una deriva.

La plantilla té tres columnes i s'escriu a docs/abast.md:

## Fora d'abast (v1.0)

| Què no es farà | Per què | Quan es reconsidera |
|---|---|---|
| Vista de calendari | La llista ordenada per data cobreix la necessitat principal | v1.1, després de la fita H5 |
| Exportació a CSV/JSON | Comoditat; cap criteri d'acceptació no en depèn | v1.1 |
| Subtasques de més d'un nivell | Un nivell ja demostra l'arbre; més nivells només afegeixen casos límit | v1.2, si un usuari real ho demana |
| Sincronització amb servidor | Requereix backend; el MVP és d'un dispositiu | v2.0 (la lliçó 11-03 prepara la frontera) |
| Temps real / col·laboració | Cost desproporcionat per a tres usuaris | No previst |
| Autenticació d'usuaris | No hi ha servidor; una autenticació només a client és teatre de seguretat | v2.0, juntament amb el backend |
| Notificacions per correu | Requereix servidor i un proveïdor de correu | No previst |
| Internacionalització a diversos idiomes | Un sol idioma; els formats sí que faran servir `Intl` | v1.2 |
| Aplicació mòbil nativa | La PWA cobreix el cas d'ús mòbil | No previst |
| Temes i personalització visual | Cosmètic; no afecta cap criteri d'acceptació | No previst |

Tres detalls de la plantilla que no són adorn:

  • La columna «Per què» et protegeix de tu mateix. D'aquí a tres setmanes no recordaràs el raonament, només la temptació.
  • «Quan es reconsidera» evita el «mai» rancuniós. Ajornar no és rebutjar, i dir-ho així fa molt més fàcil acceptar la retallada.
  • «No previst» és una resposta legítima i convé fer-la servir sense culpa. No tot allò ajornat ha de tornar.

Una nota específica sobre la línia d'autenticació, perquè és un error clàssic en projectes de portafoli: una pantalla d'inici de sessió sense servidor no protegeix res. Si les dades són a localStorage, qualsevol amb les eines de desenvolupament les veu. Posar-hi un formulari de contrasenya al davant és pitjor que no posar-l'hi, perquè comunica una seguretat que no existeix. Si el teu projecte necessita autenticació de debò, necessita servidor, i això és la versió 2.0 (lliçó 11-07).

  1. Històries d'usuari amb criteris d'acceptació

Una història d'usuari descriu una necessitat des del punt de vista de qui la té, no des del de qui la implementa. El seu valor no és el format bonic: és que t'obliga a dir per a qui i per a què, i aquestes dues paraules decideixen sovint el disseny tècnic.

La plantilla clàssica:

**Com a** <rol>
**vull** <acció>
**per** <benefici>

I el que de debò fa útil una història són els seus criteris d'acceptació: condicions verificables que permeten dir «fet» sense discussió. S'escriuen en format Donat / Quan / Llavors (Given / When / Then), que té un avantatge enorme i gens casual: es tradueix gairebé literalment a una prova de les que vas aprendre a 08-03 i 08-06.

Aquí tens tres històries reals d'Òrbita, completes.

6.1 Història H-04: descompondre una tasca

### H-04 · Descompondre una tasca en subtasques

**Com a** coordinadora de l'equip
**vull** dividir una tasca gran en subtasques
**per** repartir la feina entre diverses persones i veure l'avenç parcial

**Criteris d'acceptació**

1. **Donada** una tasca existent en estat `pendent` o `en-curs`,
   **quan** hi afegeixo una subtasca amb títol i hores,
   **llavors** la subtasca apareix imbricada sota la seva tasca mare
   **i** les hores de la mare passen a ser la suma de les de les seves subtasques.

2. **Donada** una tasca amb dues subtasques, una `feta` i una altra `pendent`,
   **quan** intento marcar la mare com a `feta`,
   **llavors** l'aplicació ho impedeix amb un missatge que anomena
   la subtasca oberta (regla R13).

3. **Donada** una tasca amb subtasques,
   **quan** en consulto el progrés,
   **llavors** veig el percentatge de subtasques acabades
   **i** aquest percentatge s'anuncia amb `aria-live` en canviar.

4. **Donada** una subtasca,
   **quan** intento convertir-la en mare de la seva pròpia tasca mare,
   **llavors** l'operació es rebutja amb `ErrorDeRegla` (sense cicles, R12).

**Notes tècniques**: el recorregut de l'arbre és recursiu (03-07).
La profunditat màxima és 3; el MVP només exposa 1 nivell.

Fixa't en el criteri 2. No diu «no es pot»: diu què passa exactament, amb quin missatge i citant la regla. Aquesta precisió és la que converteix el criteri en una prova de Jest de cinc línies.

I fixa't en el criteri 3: l'accessibilitat és dins del criteri d'acceptació, no en una llista a part que es revisa al final. És l'única manera que no s'oblidi. Hi tornaré a l'apartat 16 i a la lliçó 11-02.

6.2 Història H-07: filtrar per diverses etiquetes

### H-07 · Filtrar per diverses etiquetes alhora

**Com a** membre de l'equip
**vull** filtrar el tauler per diverses etiquetes combinades
**per** trobar ràpidament la feina d'un àmbit concret

**Criteris d'acceptació**

1. **Donat** un tauler amb tasques etiquetades,
   **quan** selecciono dues etiquetes en mode *qualsevol* (O),
   **llavors** veig les tasques que porten almenys una de les dues.

2. **Donada** la mateixa selecció en mode *totes* (I),
   **llavors** veig només les tasques que porten les dues.

3. **Donat** un filtre actiu,
   **quan** copio la URL i l'obro en una altra pestanya,
   **llavors** el filtre s'aplica igual (l'estat viu a la URL).

4. **Donat** un filtre que no retorna cap tasca,
   **llavors** veig un estat buit explicatiu amb un botó
   «Treure filtres», no una llista en blanc.

5. **Donat** qualsevol filtre,
   **quan** canvia el nombre de resultats,
   **llavors** s'anuncia per `aria-live` («12 tasques visibles de 47»).

El criteri 3 és el que té conseqüències arquitectòniques: obliga que el filtre formi part de l'estat de l'aplicació i de l'encaminador (06-04 i l'encaminador.js de Nómada Tasques), no que sigui una variable local de la vista. Un criteri d'acceptació ben escrit decideix disseny.

El criteri 4 és el que més s'oblida en projectes de portafoli: els estats buits. Una aplicació que mostra una zona en blanc quan no hi ha resultats sembla trencada encara que funcioni perfectament.

6.3 Història H-11: veure qui està sobrecarregat

### H-11 · Veure la càrrega de treball de l'equip

**Com a** coordinadora
**vull** veure quantes hores obertes té cada persona per setmana
**per** repartir la feina abans que algú se saturi

**Criteris d'acceptació**

1. **Donat** un tauler amb tasques assignades i amb data límit,
   **quan** obro l'informe de càrrega,
   **llavors** veig una taula de persones per setmanes ISO
   amb les hores obertes de cada cel·la.

2. **Donada** una persona amb més de 40 hores obertes en una setmana,
   **llavors** la seva cel·la es destaca visualment **i** amb text
   (no només amb color), i l'informe indica quantes persones estan
   per sobre del límit (R7 + R15).

3. **Donada** una tasca sense `dataLimit`,
   **llavors** les seves hores apareixen en una columna «Sense data»
   i mai no es reparteixen arbitràriament en una setmana.

4. **Donada** una tasca amb subtasques,
   **llavors** les seves hores es compten una sola vegada (les de les fulles),
   mai duplicades entre mare i filles (R12).

El criteri 4 és el que et costarà una tarda sencera si no l'escrius ara. La doble comptabilització d'hores en arbres és una d'aquelles errades que no trenca res visiblement: només fa que tots els números estiguin malament.

Quantes històries escriure. Per a un MVP com aquest, entre 12 i 18 històries és l'ordre de magnitud correcte. Menys de 10 acostuma a significar que les històries són massa gruixudes («com a usuari vull gestionar tasques» no és una història, és un mòdul). Més de 25 acostuma a significar que estàs descrivint la implementació en lloc de la necessitat.

  1. Prioritzar amb MoSCoW

Tenir històries no n'hi ha prou: cal saber en quin ordre. MoSCoW és un mètode de priorització simple i sorprenentment eficaç, el nom del qual ve de les inicials de les seves quatre categories:

Categoria Significat Regla d'ús
M · Must have Sense això no hi ha producte. Si falta, no es lliura Com a màxim el 60 % de l'esforç total
S · Should have Important, però el producte funciona sense això ~20 % de l'esforç
C · Could have Desitjable si sobra temps ~20 % de l'esforç
W · Won't have Explícitament fora d'aquesta versió És la llista de l'apartat 5

La regla del 60 % és la part important i la que gairebé tothom incompleix. Si els teus Must consumeixen el 100 % del temps disponible, no tens pla: tens una aposta. Qualsevol imprevist —i sempre n'hi ha— et deixa sense lliurar. El 40 % restant en Should i Could és el teu marge: quan el temps estreny, se sacrifiquen sense dolor i el producte continua sent lliurable.

Priorització completa del MVP d'Òrbita:

ID Història MoSCoW Est. (h) Fita Depèn de
H-01 Veure el tauler de tasques M 6 H2
H-02 Crear una tasca amb validació M 8 H2 H-01
H-03 Canviar l'estat amb transicions vàlides M 5 H2 H-01
H-04 Descompondre en subtasques M 10 H3 H-02
H-05 Assignar responsable M 4 H3 H-02
H-06 Editar i esborrar una tasca M 6 H3 H-02
H-07 Filtrar per diverses etiquetes M 7 H4 H-01
H-08 Filtrar per responsable i estat M 3 H4 H-07
H-09 Persistència local amb migracions M 8 H4 H-02
H-10 Historial de canvis per tasca S 9 H5 H-06
H-11 Informe de càrrega per persona i setmana S 8 H5 H-05
H-12 Estat buit i estats d'error S 4 H5 H-01
H-13 Recorregut complet per teclat S 5 H5 H-01
H-14 Exportar l'informe a CSV C 4 H6 H-11
H-15 Vista de calendari mensual C 12 H6 H-01
H-16 Instal·lable com a PWA sense connexió C 6 H6 H-09

Repartiment: Must 57 h (57 %), Should 26 h (26 %), Could 22 h (22 %). Total 105 h. La regla del 60 % es compleix amb folgança.

Dos advertiments sobre aquesta taula:

  • La columna «Depèn de» és la que defineix l'ordre real. MoSCoW diu què és important; les dependències diuen què és possible. No pots fer H-11 abans que H-05 encara que vulguis.
  • Les estimacions són de la lliçó 14, no sortides del no-res, i ja porten incorporat el factor de correcció que allà s'explica.

  1. El model de dades, escrit abans de programar

Aquí hi ha el consell més rendible de tota la lliçó: el model de dades s'escriu abans que el codi, en un document, i es revisa com es revisa un contracte. Canviar un camp en un document costa trenta segons. Canviar-lo quan ja és al domini, al repositori, a la vista, a les proves i a les dades desades dels usuaris costa una tarda i una migració (lliçó 11-03).

El model d'Òrbita amplia el de Nómada Tasques amb tres entitats noves.

8.1 Diagrama d'entitats

erDiagram
    USUARI ||--o{ TASCA : "es responsable de"
    USUARI ||--o{ TASCA : "revisa"
    USUARI ||--o{ CANVI : "realitza"
    TASCA ||--o{ TASCA : "es descompon en"
    TASCA ||--o{ CANVI : "acumula"
    TASCA }o--o{ ETIQUETA : "porta"
    TAULER ||--o{ TASCA : "conte"
    TAULER ||--o{ USUARI : "aplega"

    USUARI {
        string id PK
        string nom
        string inicials
        string rol "coordinacio|equip|convidat"
        boolean actiu
    }
    TASCA {
        number id PK
        string titol
        string responsableId FK "null permes"
        string revisorId FK "null permes"
        string prioritat "alta|mitjana|baixa"
        string estat "pendent|en-curs|feta"
        number horesEstimades
        string dataLimit "ISO o null"
        number tascaMareId FK "null si es arrel"
        string creadaEl "ISO"
    }
    ETIQUETA {
        string nom PK "minuscules"
    }
    CANVI {
        string id PK
        number tascaId FK
        string usuariId FK
        string data "ISO amb hora"
        string camp
        string abans
        string despres
    }

8.2 Les entitats, camp a camp

Usuari — l'entitat nova més important, perquè canvia el tipus de dos camps que portaves deu mòduls tractant com a text.

Camp Tipus Regles Nota
id string Únic, estable, no reutilitzable Text i no número: els usuaris poden venir d'un sistema extern a la v2.0
nom string No buit després de trim() Dada personal: vegeu l'advertiment al final de l'apartat
inicials string 1–3 caràcters, majúscules Per a l'avatar textual, sense imatges
rol string 'coordinacio' | 'equip' | 'convidat' Conjunt tancat, com prioritat
actiu boolean Per defecte true Mai no s'esborra un usuari: es desactiva. Vegeu 8.3

Tasca — conserva els vuit camps de Nómada Tasques i n'hi afegeix quatre:

Camp Canvi respecte a Nómada Tasques
responsableresponsableId Passa de string a referència a Usuari.id; continua admetent null (R8)
revisorrevisorId Ídem
tascaMareId Nou. null si és arrel; si no, id de la tasca mare (E2)
creadaEl Nou. Data ISO amb hora; necessària per a R4 i per ordenar l'historial
horesEstimades Ara és derivat si la tasca té filles: suma de les fulles (R12)
id Continua sent number correlatiu (R1), ara únic a tot l'arbre

Canvi — l'entitat de l'historial (E6). És append-only: s'hi afegeix, mai no es modifica ni s'esborra.

Camp Tipus Nota
id string Un identificador únic; pot ser crypto.randomUUID() (07-06)
tascaId number A quina tasca afecta
usuariId string Qui ho va fer
data string ISO amb hora Quan. Amb hora, a diferència de dataLimit
camp string Quin camp va canviar, o 'creacio' / 'esborrat'
abans / despres string | null Valors serialitzats a text perquè l'entrada sigui llegible sense context

Aquesta última decisió —serialitzar a text en lloc de desar el valor original— és deliberada i convé entendre'n el motiu: una entrada d'historial ha de continuar sent llegible d'aquí a dos anys, quan el model hagi canviat i prioritat potser ja no existeixi. Un historial que depèn del model actual per interpretar-se no és un historial: és una còpia parcial de l'estat.

8.3 Les tres decisions de modelatge que cal prendre ara

1 · Què passa quan s'esborra un usuari amb tasques assignades?

Tres opcions, i cal triar-ne una explícitament:

Opció Què fa Conseqüència
Esborrat en cascada Esborra les seves tasques Inacceptable: es perd feina de l'equip
Posar les tasques a null Les desassigna Acceptable, però es perd informació històrica
Desactivar (triada) actiu: false; les seves tasques conserven la referència Es conserva tot; la interfície mostra «(inactiu)»

L'opció triada és la tercera, i és la que es fa servir a gairebé tot el programari professional: l'esborrat real d'entitats referenciades gairebé mai no és el correcte. Aquesta decisió mereix un ADR (lliçó 11-06).

2 · Les etiquetes són una entitat o un array de textos?

A Nómada Tasques eren un array de textos normalitzats (R9). Per al MVP d'Òrbita es mantenen així, amb una funció que deriva el catàleg d'etiquetes del tauler. Convertir-les en entitat amb id propi només compensa si necessites reanomenar una etiqueta a totes les tasques alhora, i això és fora d'abast.

Anota-ho al document: una decisió que es pren explícitament i es justifica no és deute tècnic; és una decisió. El que crea deute és no adonar-se que hi havia una elecció.

3 · L'arbre es desa imbricat o pla amb referència?

Forma Com Avantatge Inconvenient
Imbricat tasca.subtasques = [...] Es llegeix i es pinta de manera natural Moure una subtasca implica tallar i enganxar en dos llocs; cercar per id obliga a recórrer-ho tot
Pla amb tascaMareId (triada) Llista plana; l'arbre es construeix en llegir Cercar per id és directe; moure és canviar un camp; es desa i es serialitza trivialment Cal construir l'arbre en memòria i detectar cicles

La forma plana és la que fan servir les bases de dades i la que t'estalviarà problemes a la lliçó 11-03. Construir l'arbre és una funció recursiva de quinze línies (03-07); mantenir sincronitzada una estructura imbricada duplicada és un problema permanent.

Avís de protecció de dades. Així que el teu model conté nom de persones, estàs modelant dades personals. En un projecte d'aprenentatge amb dades fictícies no hi ha cap problema legal, però adquireix l'hàbit ara: anota al document d'abast quins camps són personals, per a què es fan servir i quant de temps es conserven. Si algun dia aquest producte tractés dades de persones reals, el RGPD exigeix base legal, informació a la persona interessada, minimització i terminis de conservació — i això requereix assessorament legal específic, no una lliçó de JavaScript. Hi tornarem a 11-03 i 11-05.

  1. Les regles de negoci noves: R11 a R15

Les regles R1 a R10 de Nómada Tasques continuen vigents. Les repasso breument perquè són la base sobre la qual es recolzen les noves:

Regla Descripció
R1 L'id és únic i correlatiu; l'assigna l'aplicació, mai l'usuari
R2 El titol no pot estar buit ni contenir només espais
R3 horesEstimades més gran que 0 i no superior a 40
R4 dataLimit no pot ser anterior a la data de creació
R5 Una tasca nova neix sempre en estat 'pendent'
R6 Només es permeten les transicions d'estat vàlides
R7 Ningú no pot superar 40 hores estimades assignades la mateixa setmana
R8 Una tasca sense responsable fa servir null, mai ''
R9 Les etiquetes es desen en minúscules i sense duplicats
R10 Una tasca vençuda (dataLimit passada i estat diferent de 'feta') es destaca

I aquestes són les cinc noves, que són les que donen caràcter a Òrbita:

Regla Descripció On s'aplica Error que llança
R11 responsableId i revisorId s'han de referir a un usuari existent i actiu, o ser null. Una persona no pot ser responsable i revisora de la mateixa tasca Domini, en crear i en assignar ErrorDeValidacio amb .camp
R12 L'arbre de subtasques no admet cicles i té profunditat màxima 3. Les horesEstimades d'una tasca amb filles són la suma de les fulles, mai un valor propi Domini, en vincular i en calcular ErrorDeRegla
R13 Una tasca amb almenys una subtasca no tancada no pot passar a 'feta'. En tancar una tasca mare es registra el tancament de totes les seves fulles Domini, a canviarEstat ErrorDeRegla
R14 Tota modificació del domini genera una entrada d'historial immutable. L'historial no s'edita ni s'esborra; una correcció és una entrada nova Aplicació, després de cada mutació — (invariant, no validació)
R15 Un usuari amb rol 'convidat' només pot llegir. La càrrega de R7 es calcula per usuari i setmana ISO, comptant només tasques obertes i només les hores de les fulles Domini (càrrega) i aplicació (permisos) ErrorDeRegla

Cinc observacions sobre aquestes regles, perquè cadascuna amaga una decisió:

R11 i la integritat referencial. «Existent i actiu» és més fort que «existent». Vol dir que en desactivar un usuari cal decidir què passa amb les seves assignacions futures: la resposta triada és que les existents es conserven (són història) però no se'n poden crear de noves. Aquesta asimetria és intencionada i mereix una prova explícita.

R12 i la suma de les fulles. És la regla que evita la doble comptabilització del criteri 4 d'H-11. La seva conseqüència pràctica: horesEstimades deixa de ser un camp editable així que una tasca té filles, i la interfície ho ha de reflectir (camp deshabilitat amb explicació, no camp que accepta un valor que s'ignora en silenci).

R13 i el tancament en cascada. Prohibir tancar una mare amb filles obertes és l'estricte; permetre-ho tancant les filles automàticament és el còmode. La regla triada fa l'estricte per defecte i ofereix la cascada com a acció explícita («Tancar també les 3 subtasques pendents»). No facis mai la cascada en silenci: esborrar o tancar coses que l'usuari no ha mirat és la recepta de la desconfiança.

R14 i la immutabilitat. «Una correcció és una entrada nova» és el principi comptable de tota la vida, i és el que fa que un historial serveixi per a alguna cosa. Així que es pot editar, deixa de ser prova de res.

R15 i la setmana ISO. Triar la setmana ISO 8601 (dilluns a diumenge, amb la regla del dijous per a la setmana 1) en lloc de «els últims set dies» és una decisió amb conseqüències: cal implementar-la bé, i és un cas de prova preciós perquè l'1 de gener cau de vegades a la setmana 52 de l'any anterior. Anota-ho: serà una de les teves proves parametritzades de la lliçó 11-04.

On viuen les regles. Totes, sense excepció, a la capa de domini. La vista les pot anticipar per donar bona informació a l'usuari (deshabilitar un botó, avisar abans d'enviar), però la vista mai no és qui decideix. Si una regla només és al formulari, no existeix: n'hi ha prou de cridar el mètode des d'un altre lloc per saltar-se-la. Això és exactament el que 06-07 explicava sobre validació de client, i el mateix que la lliçó 11-05 repetirà sobre validació de servidor.

  1. L'arquitectura per capes i les fronteres que no es creuen

Nómada Tasques tenia quatre carpetes —model/, dades/, vista/, util/— i aquella organització no era estètica: era una arquitectura per capes, amb regles sobre qui pot cridar qui. Òrbita la formalitza amb quatre capes i una capa transversal.

flowchart TD
    subgraph APP["aplicacio/ — orquestra casos d'us"]
        A1["crearTasca()"]
        A2["canviarEstat()"]
        A3["generarInforme()"]
    end
    subgraph VISTA["vista/ — DOM, esdeveniments, accessibilitat"]
        V1["TaulerVista"]
        V2["FormulariTasca"]
        V3["InformeVista"]
    end
    subgraph DADES["dades/ — persistencia i xarxa"]
        D1["RepositoriMemoria"]
        D2["RepositoriLocal"]
        D3["RepositoriApi"]
    end
    subgraph DOM["domini/ — regles R1-R15, sense dependencies"]
        M1["Tasca"]
        M2["Tauler"]
        M3["Usuari"]
        M4["regles.js"]
    end

    VISTA -->|"esdeveniments"| APP
    APP -->|"llegeix i escriu"| DOM
    APP -->|"desa i carrega"| DADES
    DADES -->|"reconstrueix"| DOM
    APP -->|"notifica estat"| VISTA

    style DOM fill:#dcfce7,stroke:#16a34a
    style DADES fill:#dbeafe,stroke:#2563eb
    style VISTA fill:#fef3c7,stroke:#d97706
    style APP fill:#f3e8ff,stroke:#9333ea

Les quatre capes, amb la seva responsabilitat i les seves prohibicions:

Capa Responsabilitat Pot importar Mai no importa
domini/ Les entitats, les seves invariants i les regles R1–R15 Només util/ pur dades/, vista/, aplicacio/, fetch, document, localStorage
dades/ Desar, carregar, parlar amb la xarxa, migrar formats domini/, util/ vista/, aplicacio/
vista/ Pintar, escoltar esdeveniments, accessibilitat, focus util/, tipus del domini/ només per llegir dades/, aplicacio/ (rep funcions, no les importa)
aplicacio/ Casos d'ús: orquestra domini + dades + estat i avisa la vista Les tres anteriors
util/ Funcions pures: dates, format, debounce Res Tota la resta

Les tres fronteres que no es creuen, i què et passa si les creues:

  1. domini/ no sap que existeix un navegador. Ni document, ni localStorage, ni fetch, ni alert. Conseqüència pràctica immediata: el domini es prova a Node sense jsdom, en mil·lisegons, i això és el que fa possible tenir centenars de proves ràpides (11-04). Si un dia necessites Date.now() dins del domini, es passa com a paràmetre o com a rellotge injectat — mai no es crida directament, perquè llavors les proves depenen de quin dia les executis.

  2. vista/ no sap d'on vénen les dades. Rep un estat i unes funcions (enCrearTasca, enCanviarEstat) i les crida. No sap si al darrere hi ha memòria, localStorage o una API. Conseqüència pràctica: canviar l'emmagatzematge a la lliçó 11-03 no tocarà ni un fitxer de vista.

  3. dades/ no sap què es pinta. Retorna entitats del domini o llança errors tipats. No retorna HTML, ni missatges d'usuari, ni «cadenes llestes per mostrar». Conseqüència pràctica: la traducció d'un error a un text amable és responsabilitat de la vista, i per això el mateix ErrorDeRegla es pot mostrar de tres maneres diferents en tres pantalles.

Per què aquesta arquitectura, i no una altra. Dues referències del mateix curs:

  • 05-04 (mòduls) va ensenyar que un import és una dependència declarada: en escriure'l estàs dient «això no funciona sense allò». Una arquitectura per capes és, literalment, una regla sobre quins import estan permesos. I com que és una regla mecànica, es pot automatitzar: ESLint (08-02) té regles de restricció d'importacions que trenquen la compilació si algú escriu import { desar } from '../dades/...' dins de domini/. Configurar-ho és l'exercici 3.

  • 10-06 va demostrar amb dades que domini/regles.js va ser idèntic a les quatre versions de la mateixa pantalla (JavaScript pur, React, Vue i Angular). Aquest fet és l'argument definitiu: si el domini no depèn de la vista, sobreviu al canvi de vista. I les vistes canvien. Sempre.

Un apunt d'honestedat: per a un projecte de 100 hores, quatre capes poden semblar cerimònia. No ho són, per una raó molt concreta: el cost d'introduir-les al principi és d'una hora; el d'introduir-les quan ja hi ha 4.000 línies barrejades és d'una setmana. I en aquest projecte en particular les necessites, perquè la lliçó 11-03 substituirà la capa de dades sencera i la 11-04 provarà cada capa amb una tècnica diferent.

  1. L'entorn: repositori i cadena d'eines

Ara sí, teclat. L'objectiu d'aquest apartat és un repositori que, en executar una sola ordre, ho verifiqui tot i surti en verd.

11.1 Inicialitzar

# 1 · Carpeta i repositori
mkdir orbita && cd orbita
git init -b main

# 2 · package.json (sense preguntes)
npm init -y

# 3 · Entorn de desenvolupament i construcció
npm install --save-dev vite

# 4 · Qualitat de codi (08-02)
npm install --save-dev eslint @eslint/js prettier eslint-config-prettier

# 5 · Proves (08-03, 08-05)
npm install --save-dev jest jest-environment-jsdom \
  @testing-library/dom @testing-library/user-event @testing-library/jest-dom

# 6 · Extrem a extrem (08-06)
npm install --save-dev cypress

# 7 · Ganxos de Git
npm install --save-dev husky lint-staged
npx husky init

Cada línia, explicada:

  • git init -b main crea el repositori amb la branca principal anomenada main des del principi, que és el que espera GitHub i el que farà servir el flux de desplegament de la lliçó 11-05.
  • vite és el servidor de desenvolupament i l'empaquetador. Et dona recàrrega instantània en desar i, en producció, la compilació amb minificació i hashing que veuràs a 11-05. És l'eina que Nómada Tasques feia servir des del Mòdul 9.
  • ESLint i Prettier separen responsabilitats com explicava 08-02: ESLint busca errors, Prettier imposa format. eslint-config-prettier desactiva les regles d'ESLint que es barallarien amb Prettier.
  • Jest amb jsdom per a unitàries i integració; Testing Library per consultar el DOM per rol i per text, com una persona (08-05).
  • Cypress per als tres recorreguts d'extrem a extrem (08-06).
  • Husky i lint-staged executen les comprovacions abans de cada commit, sobre els fitxers que estàs confirmant. És la diferència entre «la CI ja m'avisarà» i «no puc confirmar codi trencat».

11.2 package.json complet

{
  "name": "orbita",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "description": "Gestor de treball per a equips petits. Projecte final del curs de JavaScript.",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "lint": "eslint .",
    "lint:fix": "eslint . --fix",
    "format": "prettier --write .",
    "format:check": "prettier --check .",
    "test": "jest",
    "test:watch": "jest --watch",
    "test:cov": "jest --coverage",
    "e2e": "cypress run",
    "e2e:obrir": "cypress open",
    "verificar": "npm run lint && npm run format:check && npm run test:cov && npm run build"
  },
  "lint-staged": {
    "*.js": ["eslint --fix", "prettier --write"],
    "*.{css,html,json,md}": ["prettier --write"]
  }
}

El guió clau és verificar. És el contracte del projecte en una línia: lint, format, proves amb cobertura i compilació. És exactament el que executarà la integració contínua (11-04) i el que has de poder llançar en qualsevol moment per saber si el projecte està sa. La regla associada és simple i no admet excepcions:

npm run verificar ha d'estar en verd abans de cada push. Sempre.

L'ordre dels quatre passos no és casual: van de més ràpid a més lent, perquè el primer que falli sigui el més barat de detectar.

11.3 Configuració d'ESLint amb les fronteres d'arquitectura

Aquest és el fitxer eslint.config.js, i conté la part que fa que l'arquitectura de l'apartat 10 es compleixi sola:

import js from '@eslint/js';
import prettier from 'eslint-config-prettier';

export default [
  js.configs.recommended,
  prettier,

  // Regles generals del projecte
  {
    files: ['src/**/*.js'],
    languageOptions: {
      ecmaVersion: 2023,
      sourceType: 'module',
      globals: { window: 'readonly', document: 'readonly', localStorage: 'readonly' }
    },
    rules: {
      'no-console': ['warn', { allow: ['warn', 'error'] }],
      'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
      eqeqeq: ['error', 'always'],
      'prefer-const': 'error'
    }
  },

  // FRONTERA 1: el domini no coneix el navegador ni les altres capes
  {
    files: ['src/domini/**/*.js'],
    languageOptions: {
      globals: {} // ni window, ni document, ni localStorage
    },
    rules: {
      'no-restricted-imports': ['error', {
        patterns: [
          { group: ['**/dades/**'], message: 'El domini no pot importar de dades/.' },
          { group: ['**/vista/**'], message: 'El domini no pot importar de vista/.' },
          { group: ['**/aplicacio/**'], message: 'El domini no pot importar de aplicacio/.' }
        ]
      }],
      'no-restricted-globals': ['error',
        { name: 'document', message: 'El domini no toca el DOM.' },
        { name: 'localStorage', message: 'El domini no persisteix; aixo es dades/.' },
        { name: 'fetch', message: 'El domini no parla per xarxa; aixo es dades/.' }
      ]
    }
  },

  // FRONTERA 2: la vista no coneix la persistència
  {
    files: ['src/vista/**/*.js'],
    rules: {
      'no-restricted-imports': ['error', {
        patterns: [
          { group: ['**/dades/**'], message: 'La vista rep dades, no les busca.' }
        ]
      }]
    }
  }
];

El que acabes de fer és important i mereix que ho vegis amb claredat: has convertit una decisió d'arquitectura en una regla automàtica. A partir d'ara, la frontera no depèn que te'n recordis un divendres a la tarda. Si algú —tu d'aquí a tres setmanes— escriu import { RepositoriLocal } from '../dades/repositori-local.js' dins de domini/tasca.js, npm run lint falla, el commit es rebutja i la CI es posa en vermell.

Les arquitectures que no es poden verificar automàticament s'erosionen sempre. No és qüestió de disciplina: és qüestió que ningú no recorda un document de fa dos mesos a les onze de la nit.

11.4 El ganxo de pre-commit

# .husky/pre-commit
npx lint-staged
npm test -- --onlyChanged --passWithNoTests

Dos passos: formatar i revisar només els fitxers que estàs confirmant (lint-staged), i executar només les proves afectades (--onlyChanged). Ràpid a propòsit: un ganxo lent és un ganxo que acabaràs saltant-te amb --no-verify, i un ganxo que se salta no serveix de res. La suite completa és responsabilitat de la CI.

  1. L'estructura de carpetes de partida

orbita/
├── .github/workflows/ci.yml       ← integració contínua (11-04)
├── .husky/pre-commit
├── cypress/
│   ├── e2e/                       ← els 3 recorreguts (11-04)
│   └── support/
├── docs/
│   ├── abast.md                   ← MVP + el que NO es farà
│   ├── model-dades.md             ← entitats + R1-R15
│   ├── histories.md               ← històries amb criteris
│   └── adr/                       ← decisions d'arquitectura (11-06)
│       └── 0001-arquitectura-per-capes.md
├── public/
│   ├── manifest.json
│   └── icones/
├── src/
│   ├── main.js                    ← únic punt d'entrada: ho munta tot
│   ├── estils/
│   │   ├── base.css
│   │   └── components.css
│   ├── domini/                    ← SENSE dependències externes
│   │   ├── tasca.js
│   │   ├── usuari.js
│   │   ├── tauler.js
│   │   ├── arbre.js               ← recorregut recursiu (03-07)
│   │   ├── historial.js
│   │   ├── regles.js              ← R1-R15 en un sol lloc
│   │   └── errors.js              ← ErrorDeValidacio, ErrorDeRegla, ErrorDeDades
│   ├── dades/
│   │   ├── repositori.js          ← el CONTRACTE (la frontera)
│   │   ├── repositori-memoria.js
│   │   ├── repositori-local.js
│   │   ├── migracions.js          ← (11-03)
│   │   └── llavor.js              ← dades fictícies d'exemple
│   ├── aplicacio/
│   │   ├── estat.js               ← única font de veritat
│   │   ├── casos-us.js
│   │   └── esdeveniments.js
│   ├── vista/
│   │   ├── dom.js                 ← crearElement, $, $$
│   │   ├── tauler-vista.js
│   │   ├── formulari-tasca.js
│   │   ├── informe-vista.js
│   │   ├── historial-vista.js
│   │   └── encaminador.js
│   └── util/
│       ├── dates.js               ← inclosa la setmana ISO de R15
│       ├── format.js              ← Intl
│       └── temps.js               ← debounce, throttle
├── test/
│   ├── domini/
│   ├── dades/
│   └── vista/
├── .gitignore
├── .prettierrc
├── eslint.config.js
├── index.html
├── jest.config.js
├── package.json
├── README.md
└── vite.config.js

Tres decisions de l'estructura, amb el seu perquè:

  • src/ com a arrel del codi. Separa el codi de la configuració, que a l'arrel ja són deu fitxers. Vite ho espera així per defecte.
  • docs/ versionat amb el codi. Si el document d'abast viu en una nota solta o en un servei extern, es desincronitza en dues setmanes. Dins del repositori, canvia al mateix commit que el codi que reflecteix.
  • test/ fora de src/, reflectint-ne l'estructura. Existeix l'alternativa de posar les proves al costat del codi (tasca.test.js al costat de tasca.js); les dues funcionen. L'avantatge de separar-les és que el build de producció no ha d'excloure res i la cobertura per capes es llegeix d'una ullada.

  1. Git de debò: branques, commits i revisions

Fins ara potser has fet servir Git com a còpia de seguretat: git add ., git commit -m "canvis", git push. Funciona fins que necessites respondre una d'aquestes preguntes, i llavors no funciona en absolut:

  • Quan va deixar de funcionar l'informe de càrrega i quin canvi el va trencar?
  • Per què està escrit així aquest tros estrany que no goso tocar?
  • Puc desfer la funcionalitat de subtasques sense desfer les tres de després?
  • Què va entrar exactament a la versió que vaig desplegar dimarts?

L'historial de Git és documentació que s'escriu sola si li dediques trenta segons per commit. Aquestes són les regles del projecte.

13.1 Branques curtes

Una branca per història d'usuari. Neix de main, viu entre unes hores i tres dies, i es fusiona.

git switch -c feat/h04-subtasques      # neix de main
# ... feina, diversos commits petits ...
npm run verificar                      # obligatori abans de pujar
git push -u origin feat/h04-subtasques
# revisió (13.3), fusió, i esborrat de la branca

Conveni de noms, amb el mateix prefix que els commits:

Prefix Per a què Exemple
feat/ Funcionalitat nova feat/h07-filtre-etiquetes
fix/ Correcció d'una errada fix/hores-duplicades-en-arbre
refactor/ Canvi intern sense canvi de comportament refactor/extreure-regles-carrega
docs/ Només documentació docs/adr-0003-repositori
chore/ Eines, dependències, configuració chore/actualitzar-vite

Per què curtes. Una branca de tres setmanes acumula conflictes, es desincronitza de main i arriba un moment en què fusionar-la fa por. Una branca de dos dies es fusiona sense pensar. Si una història no cap en tres dies, la història és massa gran: parteix-la (H-04 es pot partir en «crear subtasca», «agregar hores» i «regla de tancament R13»).

13.2 Commits convencionals

El format de Commits Convencionals és un estàndard àmpliament adoptat:

<tipus>(<àmbit opcional>): <descripció en imperatiu, minúscula, sense punt>

<cos opcional: el PERQUÈ, no el què>

<peu opcional: BREAKING CHANGE, referències>

Exemples reals d'aquest projecte, del pitjor al millor:

❌ arreglos
❌ Canvis al tauler
❌ fix bug

✅ feat(domini): afegir vinculació de subtasques amb detecció de cicles
✅ fix(informe): comptar només les hores de les fulles de l'arbre
✅ test(domini): cobrir R13 amb les quatre combinacions d'estat
✅ refactor(vista): extreure la construcció de files a filaTasca()
✅ docs(adr): registrar la decisió de repositori pla amb tascaMareId

I un commit amb cos, que és on hi ha el valor de debò:

fix(informe): comptar només les hores de les fulles de l'arbre

L'informe de càrrega sumava les hores de la tasca mare i també les de
les seves subtasques, duplicant el total. Amb el tauler d'exemple donava
71 h on el total real és 48 h.

La causa és que horesEstimades d'una mare és derivat (R12) però
acumularCarrega() recorria totes les tasques planes sense distingir fulles.

S'afegeix esFulla() a domini/arbre.js i es filtra abans d'acumular.
Prova de regressió a test/domini/carrega.test.js.

Refs: R12, H-11 criteri 4

Ningú no escriu això per lluir-se. S'escriu perquè d'aquí a sis mesos, quan l'informe torni a donar un número estrany, aquest missatge apareix a git log i t'estalvia dues hores. És el mateix argument de l'historial de canvis de la R14, aplicat al codi en lloc de a les dades.

La regla d'or de la mida del commit: si necessites la paraula «i» per descriure el que fa, són dos commits.

Què va a la descripció i què va al cos:

Part Contingut Pregunta que respon
Descripció Què canvia, en imperatiu, ≤ 72 caràcters Què
Cos Context, causa, alternatives descartades Per què
Peu Referències a històries, regles, incompatibilitats Amb què es relaciona

El què ja és al diff. El perquè només és al teu cap, i el teu cap no es pot consultar d'aquí a sis mesos.

13.3 Revisions, encara que treballis sol

«Reviso el meu propi codi» sona a teatre. No ho és, si es fa amb un procediment que forci el canvi de perspectiva:

  1. Obre una Pull Request contra main, sempre. Encara que l'aprovis tu.
  2. Deixa passar temps. Idealment fins l'endemà; com a mínim, una hora fent una altra cosa. La revisió immediata no veu res perquè el teu cap encara omple els buits.
  3. Llegeix el diff complet a la interfície web, no al teu editor. El canvi de context visual és sorprenentment eficaç: veuràs coses que al teu editor eren invisibles.
  4. Aplica la llista de comprovació de l'apartat següent i escriu els comentaris a la PR, no en un paper.
  5. Corregeix amb commits nous a la mateixa branca, no reescrivint. Que es vegi la correcció.

Llista de comprovació de revisió (l'ampliarem a 11-02 i 11-06):

# Pregunta Si la resposta és «no»…
1 El canvi fa una cosa? Parteix-lo
2 Hi ha una prova que falla sense aquest canvi? Escriu-la primer
3 Respecta les fronteres de capes? ESLint ja t'ho ha dit; fes-li cas
4 Els noms diuen el que fan? Reanomena; ara és barat
5 Hi ha codi comentat, console.log o TODO sense data? Esborra-ho
6 Es gestionen els casos límit (buit, null, error)? Afegeix-los
7 És accessible per teclat i amb lector de pantalla? Torna a l'apartat d'accessibilitat
8 El missatge de commit explica el perquè? Reescriu-lo

I una regla que val or quan algú altre revisa el teu codi o tu revises el d'altres: critica el codi, mai la persona. «Aquesta funció fa tres coses» en lloc de «has fet un embolic». Aplica-ho també amb tu mateix: l'objectiu és un producte millor, no un judici.

  1. Fites i estimació honesta

14.1 El problema de l'estimació

Tothom estima malament i sempre en la mateixa direcció: per defecte. La causa està ben estudiada i es diu fal·làcia de la planificació: en estimar imaginem el camí en què tot surt bé, perquè és l'únic que podem imaginar amb detall. Els imprevistos, per definició, no es poden enumerar.

El mètode honest té tres passos:

  1. Estima cada història en hores de treball efectiu, suposant que no hi ha interrupcions i que en saps.
  2. Multiplica per un factor de correcció segons com de conegut et resulti el problema.
  3. Afegeix un 20 % de reserva al total del projecte per al que no és a cap història (configurar coses, arreglar el desplegament, una errada rara de Jest).
Nivell de familiaritat Factor Exemple a Òrbita
Ho he fet diverses vegades × 1,3 Formulari amb validació (06-07)
Ho he fet una vegada guiat × 2 Persistència amb migracions (07-01, però les migracions són noves)
Ho entenc però no ho he fet mai sol × 3 Arbre de subtasques amb regles R12/R13
No sé per on començar × 4 o investiga primer Exportació a CSV amb caràcters especials

Un exemple complet, la història H-04:

Concepte Hores
Estimació ingènua («un arbre, mig dia») 4
Factor × 3 (mai no has implementat un arbre amb regles de negoci) 12
Ajust a la baixa: el MVP només exposa un nivell 10

Les 10 hores de la taula de l'apartat 7 surten d'aquí, no d'una intuïció.

Total d'Òrbita: 105 h d'històries + 21 h de reserva (20 %) = 126 hores. A 8 hores setmanals, unes 16 setmanes. Si això et sembla molt, tens dues sortides legítimes: dedicar-hi més hores per setmana, o retallar els Could (22 h) i quedar-te en 13 setmanes. El que no és una sortida és decidir que en realitat seran 60 hores.

14.2 Les fites

Una fita no és una data: és un estat del producte que es pot ensenyar. Cadascuna acaba amb alguna cosa demostrable.

Fita Què es pot ensenyar en acabar Històries Hores Lliçó
H1 · Fonaments Repositori verd: npm run verificar passa, amb una prova trivial i la pàgina buida desplegable 10 11-01
H2 · Domini viu El domini amb R1–R15 i les seves proves en verd, exercitable des de la consola H-01…H-03 25 11-02
H3 · Vertical completa Crear, veure, assignar i descompondre una tasca de punta a punta al navegador H-04…H-06 24 11-02
H4 · Dades que duren Filtres i persistència local amb migracions; recarregar no perd res H-07…H-09 22 11-03
H5 · Producte usable Historial, informe, estats buits i recorregut per teclat H-10…H-13 26 11-04
H6 · Publicat Desplegat amb HTTPS, CI en verd, README i demo H-14…H-16 19 11-05, 11-06
gantt
    title Òrbita — pla de 16 setmanes a 8 h/setmana
    dateFormat YYYY-MM-DD
    axisFormat S%W

    section Fonaments
    H1 · Repositori, eines, CI             :h1, 2026-09-21, 10d
    section Domini
    H2 · Entitats, regles R11-R15, TDD     :h2, after h1, 22d
    section Producte
    H3 · Vertical completa punta a punta   :h3, after h2, 21d
    H4 · Filtres i persistència            :h4, after h3, 19d
    H5 · Historial, informe, accessibilitat :h5, after h4, 23d
    section Lliurament
    H6 · Desplegament i documentació       :h6, after h5, 17d
    Reserva del 20 %                       :res, after h6, 21d

Dues observacions sobre el Gantt:

  • La reserva apareix al diagrama. Si la reserva no està dibuixada, no existeix: se la menjarà el primer imprevist i donaràs el pla per perdut. Dibuixada, és una part del pla que s'està consumint, i ho veus.
  • Les fites no s'encavalquen. És temptador dibuixar tasques en paral·lel, però treballes sol: el paral·lelisme és una il·lusió que només serveix perquè el pla sembli més curt.

Com es fa servir el pla. No com una promesa, sinó com un instrument de mesura. Al final de cada setmana anota hores dedicades i històries tancades. Si en acabar H2 portes un 40 % més de temps del previst, el teu factor de correcció és baix: puja'l per a la resta del pla en comptes d'esperar recuperar-lo. Recuperar temps perdut gairebé mai no passa; ajustar el model, sí.

  1. La Definició de Fet

La Definició de Fet (Definition of Done) respon una pregunta que sembla tonta i no ho és: quan està acabada una història? Sense una resposta escrita, «fet» significa «funciona a la meva màquina quan faig el que espero», i aquest és l'origen del 80 % del deute d'un projecte personal.

S'escriu una vegada, al principi, i s'aplica a totes les històries sense excepció:

## Definició de Fet (v1.0)

Una història està FETA quan tot el següent és cert:

### Funcionalitat
- [ ] Tots els seus criteris d'acceptació es compleixen i s'han comprovat a mà
- [ ] Els casos límit tenen comportament definit: llista buida, valor
      `null`, text molt llarg, número fora de rang, error de xarxa
- [ ] Els estats buit, de càrrega i d'error estan implementats

### Codi
- [ ] `npm run verificar` en verd
- [ ] Respecta les fronteres de capes (ESLint no protesta)
- [ ] Sense `console.log`, sense codi comentat, sense `TODO` sense data
- [ ] Els noms són en l'idioma del projecte i són coherents

### Proves
- [ ] Proves unitàries del domini afectat
- [ ] Almenys una prova d'integració per criteri d'acceptació
      que impliqui interfície
- [ ] Totes les regles de negoci tocades tenen prova del cas que
      SÍ que passa i del cas que NO
- [ ] La cobertura del domini no baixa del 90 %

### Accessibilitat
- [ ] Recorregut complet amb teclat, amb focus sempre visible
- [ ] Elements semàntics correctes (res de `<div>` clicable)
- [ ] Els canvis rellevants s'anuncien amb `aria-live`
- [ ] Contrast mínim 4,5:1 en text normal
- [ ] axe no reporta cap incidència de nivell greu

### Rendiment
- [ ] Dins del pressupost de l'apartat 16
- [ ] Sense fuites de memòria en entrar i sortir de la pantalla tres vegades

### Documentació
- [ ] README actualitzat si canvia la instal·lació o l'ús
- [ ] ADR escrit si s'ha pres una decisió d'arquitectura
- [ ] Missatge de commit amb el perquè

Sí, és llarga. I sí, es compleix, per dos motius:

  1. La majoria de les caselles les verifica una màquina: npm run verificar en cobreix set. Només unes poques exigeixen que tu facis alguna cosa a mà.
  2. És més barata que l'alternativa. Cada casella d'aquesta llista representa un problema real que apareix si no es comprova, i tots són més cars d'arreglar després.

Un consell pràctic: desa-la com a plantilla de Pull Request a .github/pull_request_template.md. Així apareix sola, marcada com a llista de tasques, cada vegada que obres una PR. El que no apareix sol, no es fa.

  1. El pressupost de rendiment i accessibilitat

La lliçó 09-01 va deixar una idea que cal aplicar ara, no al final: mesurar abans d'optimitzar. I el seu corol·lari, que és el que fa aquest apartat: un objectiu sense número no és un objectiu.

Nómada Tasques va mesurar la seva línia base al final, amb l'aplicació ja construïda, i va trobar deu problemes de cop. Tu ho faràs al revés: fixes el pressupost ara, amb l'aplicació buida, i la CI el vigila des del primer dia. La diferència és enorme: un pressupost fixat al principi s'incompleix el dia que es trenca, amb un sol canvi sospitós; fixat al final, s'incompleix per l'acumulació de trenta canvis i ningú no sap quin va ser.

16.1 Pressupost de rendiment

La columna de referència són els números mesurats de Nómada Tasques a la lliçó 09-01 (línia base amb 600 tasques, després de les optimitzacions de tot el Mòdul 9):

# Mètrica Com es mesura Pressupost d'Òrbita Nómada Tasques (ref.)
1 JS inicial (comprimit) Vite build / Network ≤ 60 kB 58,3 kB
2 Peticions per a la primera pantalla Network ≤ 4 3
3 LCP (mòbil simulat, Slow 4G, CPU 4×) Lighthouse CI ≤ 2,5 s 1,9 s
4 CLS Lighthouse CI ≤ 0,1 0,02
5 INP en filtrar Performance, Interactions ≤ 200 ms 42 ms
6 render() amb 500 tasques User Timing ≤ 50 ms 31 ms (600 tasques)
7 Nodes DOM del document Performance, comptador ≤ 1.500 1.194
8 Memòria retinguda després de 3 cicles de navegació Memory, 3 instantànies ≈ 0 sense fuites
9 Puntuació de rendiment de Lighthouse Lighthouse CI ≥ 90

Els pressupostos són una mica més laxos que els números de Nómada Tasques, i això és deliberat: Òrbita té més pantalles i més funcionalitat. Un pressupost impossible s'ignora a la primera setmana; un d'assolible però exigent es respecta.

La regla del pressupost: si un canvi l'incompleix, hi ha tres sortides legítimes — optimitzar el canvi, renunciar a la funcionalitat, o pujar el pressupost conscientment i anotar per què. La quarta sortida, «ja ho miraré més endavant», és la que produeix aplicacions de 2 MB.

16.2 Pressupost d'accessibilitat

# Criteri Com es comprova Llindar
1 Sense incidències greus d'axe axe automatitzat a la CI 0
2 Puntuació d'accessibilitat de Lighthouse Lighthouse CI ≥ 95
3 Tot assolible amb teclat Manual, per pantalla 100 %
4 Focus sempre visible Manual + CSS :focus-visible Sempre
5 Contrast de text normal axe / DevTools ≥ 4,5:1
6 Contrast de text gran i elements d'interfície axe / DevTools ≥ 3:1
7 Usable amb zoom al 200 % Manual Sense pèrdua de contingut ni de funció
8 Canvis importants anunciats Manual amb lector de pantalla aria-live present
9 Cap informació només per color Revisió manual 0 casos

El criteri 9 té una conseqüència immediata a Òrbita i convé veure-la ara: la tasca vençuda de la R10 no es pot destacar només en vermell, i la cel·la sobrecarregada de la R7 no es pot destacar només en ambre. Totes dues necessiten text o icona amb text alternatiu. Si ho saps ara, ho dissenyes bé; si ho descobreixes a la revisió d'accessibilitat, ho refaràs.

Els llindars 1, 2, 5 i 6 els verifica la màquina. La resta són manuals i van a la Definició de Fet. La lliçó 11-04 munta l'automatització completa.

  1. La plantilla de README.md

El README.md és el primer que veu qualsevol que arribi al teu repositori: un revisor, un reclutador, o tu mateix d'aquí a un any. Es crea ara, amb buits, i s'omple a mesura que el projecte avança. Un README que s'escriu l'últim dia es nota, i no es nota bé.

# Òrbita

Gestor de treball per a equips petits: tasques, subtasques, càrrega per
persona i historial de canvis. Projecte final del curs de JavaScript,
construït **sense frameworks**.

🔗 **Demo:** https://<usuari>.github.io/orbita/
📸 *(captura o GIF curt de 10 s aquí)*

---

## Quin problema resol

Un equip de tres o quatre persones necessita saber qui fa què, què
està bloquejat i qui està sobrecarregat. Les eines grans
sobren; un full de càlcul es queda curt així que hi ha regles.

## Què fa

- Tasques amb estat, prioritat, etiquetes, responsable i data límit
- **Subtasques** amb hores i progrés agregats
- **Filtre múltiple** per etiquetes (mode *totes* / *qualsevol*),
  responsable i estat, amb el filtre desat a la URL
- **Informe de càrrega** per persona i setmana ISO, amb avís de sobrecàrrega
- **Historial immutable** de tots els canvis
- Funciona **sense connexió** i instal·lable com a PWA

## Decisions tècniques

| Decisió | Per què | ADR |
|---|---|---|
| Sense framework | El producte és una única SPA amb lògica de domini rica; el cost de mantenir la infraestructura pròpia és assumible | [ADR-0002](docs/adr/0002-sense-framework.md) |
| Arquitectura per capes | El domini ha de poder provar-se sense navegador i sobreviure a un canvi de vista | [ADR-0001](docs/adr/0001-arquitectura-per-capes.md) |
| Arbre pla amb `tascaMareId` | Cercar i moure són O(1); serialitza trivialment | [ADR-0003](docs/adr/0003-arbre-pla.md) |
| `localStorage` amb migracions numerades | Volum previst < 1 MB; migrar sense perdre dades | [ADR-0004](docs/adr/0004-persistencia.md) |

## Com executar-lo

git clone https://github.com//orbita.git cd orbita npm install npm run dev # http://localhost:5173

## Com provar-lo

npm test # unitàries i integració npm run test:cov # amb informe de cobertura npm run e2e # recorreguts d'extrem a extrem npm run verificar # tot l'anterior + lint + build

## Arquitectura

src/domini/ Regles R1-R15. Sense dependències. Es prova a Node. src/dades/ Persistència i xarxa. Una interfície, tres implementacions. src/vista/ DOM, esdeveniments i accessibilitat. No sap d'on vénen les dades. src/aplicacio/ Casos d'ús i estat. Uneix les tres anteriors.

## Limitacions conegudes

- Un sol dispositiu: sense sincronització entre navegadors (v2.0)
- Sense autenticació: les dades viuen al navegador i **no són privades**
- Profunditat de subtasques limitada a un nivell a la interfície
- Provat a Chrome, Firefox i Safari recents; sense suport d'IE

## Full de ruta

- [ ] v1.1 · Vista de calendari i exportació a CSV
- [ ] v1.2 · Tres nivells de subtasques
- [ ] v2.0 · Backend amb autenticació i sincronització

## Llicència

MIT — vegeu [LICENSE](LICENSE).

Les seccions que gairebé ningú no escriu i que més impressionen qui revisa són «Decisions tècniques» i «Limitacions conegudes». La primera demostra criteri; la segona demostra honestedat i consciència dels límits de la pròpia feina, que és exactament el que es busca en algú amb qui treballaràs. La lliçó 11-06 desenvolupa el README a fons.

Errors Habituals i Consells

Començar a programar abans de tenir el model de dades escrit. És l'error més car de tots, perquè no fa mal al principi: fa mal a la setmana quatre, quan descobreixes que responsable havia de ser una referència i ja és en vint llocs. Mitja hora de document estalvia dos dies de refactorització. Escriu el model, llegeix-lo en veu alta, i només llavors obre l'editor.

Confondre MVP amb «versió xusquera». Un MVP té menys funcionalitats, no menys qualitat. Les que hi són, hi són acabades: provades, accessibles i amb els seus estats buit i d'error. Una aplicació amb tres funcionalitats impecables demostra moltíssim més que una amb dotze a mitges — i en una entrevista, la segona juga en contra teva.

No escriure la llista del que NO es farà. Sense aquesta llista, cada idea nova sembla raonable perquè res no diu el contrari. Amb la llista, afegir alguna cosa exigeix ratllar-la explícitament, i aquest petit acte de fricció filtra el 90 % de les idees de dimarts a la tarda.

Estimar en el millor cas. La teva estimació ingènua és el temps que trigaries si tot sortís bé i ja en sabessis. Multiplica pel factor de la taula de l'apartat 14 sense negociar amb tu mateix, i afegeix la reserva del 20 %. Un pla que es compleix motiva; un que s'incompleix des de la segona setmana s'abandona.

Deixar l'arquitectura com una intenció. «Ja aniré amb compte de no importar dades/ des de domini/» és una frase que caduca en dues setmanes. Configura la regla d'ESLint de l'apartat 11.3 el primer dia: converteix la teva bona intenció en un error de compilació, que és l'única cosa que no s'oblida.

Ajornar l'accessibilitat a «quan funcioni». Afegir accessibilitat al final és refer la meitat de la vista: els <div> clicables cal convertir-los en <button>, el focus cal gestionar-lo, els anuncis cal introduir-los. Fet des del principi no costa pràcticament res, perquè gairebé tot es redueix a fer servir l'element HTML correcte.

Un README buit durant mesos. Escriu avui la primera versió, encara que la meitat siguin buits. Cada vegada que prenguis una decisió, afegeix una fila a la taula de decisions tècniques. Reconstruir el perquè de vint decisions l'últim dia és impossible: no les recordaràs.

Branques llargues. Una branca de tres setmanes és un projecte paral·lel que un dia hauràs de reconciliar. Si una història no cap en tres dies, parteix-la. Si no saps com partir-la, és senyal que encara no l'entens bé — i això també és informació valuosa.

Consell · Escriu el document d'abast per «al tu d'aquí a tres mesos». Aquest lector no recorda res, no té context i només té deu minuts. Si el document li serveix, et serveix a tu i li servirà a qualsevol.

Consell · Fixa un dia i una hora de treball, i protegeix-los. La causa número u d'abandonament de projectes personals no és la dificultat tècnica: és la pèrdua de ritme. Dues sessions setmanals fixes de tres hores rendeixen moltíssim més que «quan pugui».

Consell · Fes el primer desplegament amb l'aplicació buida. A la fita H1, abans d'escriure lògica. Descobriràs els problemes de configuració quan no costen res, en lloc de l'última setmana amb tot en joc. És el mateix principi que la fase pilot de les migracions de 10-06.

Exercicis

Aquests tres exercicis són la fita H1 del teu projecte. En acabar-los tindràs el document d'abast, el model de dades i un repositori verd: tot el necessari per començar a construir a la lliçó següent.

Exercici 1 — El document d'abast.

Crea docs/abast.md al teu repositori amb aquestes set seccions:

  1. El producte en una frase (format de l'apartat 2): qui el fa servir, què fa, quin problema resol.
  2. El MVP: la taula de funcionalitats amb la columna «MVP?» i la seva raó. Mínim 12 candidates, i almenys 5 amb «No».
  3. Fora d'abast: la taula de tres columnes de l'apartat 5, amb almenys 8 files.
  4. Històries d'usuari: entre 12 i 18, amb la plantilla Com a / vull / per. Almenys quatre desenvolupades completament amb criteris Donat / Quan / Llavors (mínim 3 criteris cadascuna), incloent-hi almenys un criteri d'accessibilitat.
  5. Priorització MoSCoW: la taula de l'apartat 7 amb estimació, fita i dependències. Verifica la regla del 60 %.
  6. Pla de fites: les sis fites amb el seu lliurable demostrable i el seu diagrama de Gantt en Mermaid, amb la reserva dibuixada.
  7. Definició de Fet: adaptada al teu projecte, amb almenys 18 caselles repartides entre les sis categories.

Exercici 2 — El model de dades i les regles.

Crea docs/model-dades.md amb:

  1. Un diagrama d'entitats en Mermaid (erDiagram) amb totes les teves entitats i les seves relacions.
  2. Una taula per entitat amb camp, tipus, si admet null, regles i una nota justificant el tipus triat.
  3. La taula de regles R1–R15 (o les que corresponguin al teu domini, si n'has triat un altre) amb: descripció, capa on s'aplica i error que llança.
  4. Les tres decisions de modelatge de l'apartat 8.3 aplicades al teu domini, cadascuna amb les seves alternatives descartades i el perquè.
  5. Un exemple complet de dades fictícies en JSON amb almenys 8 entitats, incloent-hi un cas límit de cada regla nova.
  6. Una secció «Dades personals» que enumeri quins camps ho són, per a què es fan servir i quant es conserven.

Exercici 3 — El repositori verd.

Deixa el repositori en l'estat exacte del qual parteix la lliçó 11-02:

  1. Repositori amb main, primer commit convencional i .gitignore correcte (node_modules, dist, .env, coverage, cypress/videos).
  2. package.json amb els deu guions de l'apartat 11.2, inclòs verificar.
  3. eslint.config.js amb les dues fronteres d'arquitectura configurades i comprovades.
  4. .prettierrc, jest.config.js (amb testEnvironment: 'jsdom' i llindars de cobertura) i vite.config.js.
  5. Ganxo de pre-commit amb Husky i lint-staged, verificat amb un commit real.
  6. L'estructura de carpetes de l'apartat 12, amb un .gitkeep a les buides.
  7. Una prova que demostri que les fronteres funcionen: escriu src/domini/prova-frontera.js amb import ... from '../dades/repositori.js', comprova que npm run lint falla amb el teu missatge personalitzat, i esborra'l. Documenta el resultat a l'ADR-0001.
  8. README.md amb la plantilla de l'apartat 17 (els buits s'omplen després).
  9. npm run verificar en verd.

Solucions

No hi ha solucions en forma de codi, perquè el projecte és teu. Aquestes són les rúbriques amb les quals s'avalua cada lliurable. Puntua't honestament: l'objectiu no és la nota, és detectar el que falta abans que et surti car.

Rúbrica de l'exercici 1 — Document d'abast (30 punts)

Criteri 0 · Insuficient 1 · Acceptable 2 · Bo 3 · Excel·lent
Frase del producte No existeix o descriu la implementació Diu què fa Diu qui, què i per a què A més distingeix d'alternatives òbvies
Retallada del MVP Tot és MVP Es descarta alguna cosa ≥ 5 «No» raonats Cada «No» passa la prova de la pregunta de l'apartat 4
Fora d'abast No existeix Llista de coses Taula amb perquè A més amb «quan es reconsidera» realista
Històries Vagues o descrites com a tasques tècniques Format correcte ≥ 4 amb criteris verificables Els criteris es tradueixen directament a proves
Accessibilitat en criteris Absent Esmentada a part ≥ 1 criteri d'acceptació Present a totes les històries amb interfície
MoSCoW Sense prioritzar Categoritzat Amb estimació i dependències Compleix la regla del 60 % i ho demostra amb el càlcul
Estimació Sense factor de correcció Amb factor uniforme Factor per familiaritat A més amb reserva del 20 % dibuixada al Gantt
Fites Només dates Amb lliurables Cada fita és demostrable Ordenades per dependència real, sense encavalcaments falsos
Definició de Fet No existeix Llista curta ≥ 18 caselles en 6 categories La majoria verificables per màquina
Utilitat per a un tercer Incomprensible sense tu S'entén amb esforç S'entén sol Algú el podria continuar sense parlar amb tu

Llindar d'aprovació: 20/30, amb almenys 2 punts a «Retallada del MVP» i a «Històries». Si hi falles, tota la resta es construeix sobre sorra.

Rúbrica de l'exercici 2 — Model de dades (24 punts)

Criteri Insuficient (0) Acceptable (1) Bo (2) Excel·lent (3)
Entitats Falten relacions Totes presents Amb cardinalitats correctes Diagrama Mermaid llegible i comentat
Tipus Ambigus o «string» per a tot Definits Amb justificació A més amb conjunts tancats explícits
Nul·labilitat Sense especificar Marcada Amb criteri consistent Distingeix «no aplica» de «desconegut»
Regles noves Menys de 3 5 regles enunciades Amb capa i error assignats Cadascuna amb el seu cas límit documentat
Decisió d'esborrat No contemplada Triada Amb alternatives descartades Amb conseqüències a la interfície descrites
Estructura de l'arbre Sense decidir Triada Justificada Amb el cost de les operacions analitzat
Dades d'exemple Absents Presents Amb casos límit Reutilitzables directament com a llavor de proves
Dades personals No esmentades Identificades Amb finalitat A més amb termini de conservació i minimització

Senyal d'alarma inequívoc: si la teva taula de regles té menys de cinc regles noves pròpies del domini, el teu producte és un CRUD. Afegeix-hi regles dures — són el que fa interessant el domini, el que dona sentit a les proves de 11-04 i el que s'explica bé en una entrevista.

Rúbrica de l'exercici 3 — Repositori (verificació binària)

Aquí no hi ha grisos: cada punt es compleix o no es compleix.

# Comprovació Ordre Esperat
1 El repositori existeix i té main git branch --show-current main
2 El primer commit és convencional git log --oneline -1 Comença per chore: o feat:
3 .gitignore és correcte git status --short Sense node_modules/ ni dist/
4 Els guions existeixen npm run Els 10 de l'apartat 11.2
5 El lint passa npm run lint Sense errors
6 El format està aplicat npm run format:check Sense diferències
7 Les proves passen npm test Almenys 1 prova, 0 errades
8 La compilació funciona npm run build dist/ generat
9 El ganxo es dispara commit amb una errada de lint El commit es rebutja
10 La frontera funciona afegir l'import prohibit npm run lint falla amb el teu missatge
11 Tot junt npm run verificar Verd

El punt 10 és el que de debò importa i el que gairebé ningú no comprova. Una regla d'ESLint mal configurada no falla: simplement no fa res, i tu et creus que estàs protegit durant tres mesos. Provoca l'error a propòsit, comprova el missatge, i només llavors esborra'l.

Autoavaluació final de la fita H1. Respon amb sinceritat abans de passar a la lliçó següent:

Pregunta Sí / No
Puc descriure el meu producte en una frase sense dubtar?
Sé exactament què NO construiré?
Podria escriure avui la primera prova d'una regla sense inventar-me el model?
El meu pla té reserva, o he suposat que tot sortirà bé?
npm run verificar està en verd ara mateix?
Sabria explicar les meves fronteres de capes a una altra persona en dos minuts?

Sis «sí» i pots continuar. Un sol «no» i val la pena tornar enrere abans d'escriure codi, perquè cadascun d'aquests «no» es multiplica per setmanes de feina més endavant.

Conclusió

Has fet el que gairebé ningú no fa en un projecte personal: planificar abans de programar. I no amb un pla decoratiu, sinó amb instruments que es faran servir cada setmana del mòdul.

Saps que a partir d'aquí el codi l'escrius tu: Nómada Tasques deixa de ser l'exemple que se't dona resolt i passa a ser la referència contra la qual comparar, amb les seves sis tasques, les seves 48 hores, les seves regles R1–R10 i els seus números mesurats. Tens un producte per defecte —Òrbita— amb sis extensions que obliguen a resoldre problemes que el curs esquivava: usuaris com a entitats, un arbre de subtasques, filtre múltiple, una vista que no és una llista, un informe que produeix un fitxer i un historial immutable que creix sense parar. I tens tres alternatives de domini —Aforament, Ratxa, Prestatgeria— amb el mapatge complet de les sis extensions, perquè el mètode és el mateix i el que importa és que t'importi.

Saps retallar: el MVP és el que no es pot treure sense trencar la frase del producte, i la prova és una sola pregunta. De quinze candidates n'hi van entrar vuit. I saps que la meitat que es queda fora cal escriure-la, amb el seu perquè i el seu quan es reconsidera, perquè una funcionalitat que no és a cap llista és una funcionalitat que apareixerà un dimarts a la tarda.

Saps escriure històries d'usuari que diuen per a qui i per a què, amb criteris Donat / Quan / Llavors tan precisos que es tradueixen en proves gairebé paraula per paraula — inclosos els criteris d'accessibilitat, que van dins de la història i no en una llista a part que es revisa al final. I saps prioritzar-les amb MoSCoW respectant la regla del 60 %, que és la que converteix un pla en un pla i no en una aposta.

Tens el model de dades escrit abans que el codi, amb el seu diagrama d'entitats, els seus tipus justificats i les tres decisions que calia prendre explícitament: desactivar usuaris en lloc d'esborrar-los, etiquetes com a text normalitzat, i arbre pla amb tascaMareId en comptes d'imbricat. I tens les regles noves R11 a R15 —integritat referencial amb usuaris actius, arbre sense cicles amb hores per fulles, tancament bloquejat per subtasques obertes, historial immutable, i permisos amb càrrega per setmana ISO— vivint totes al domini, perquè una regla que només és al formulari no existeix.

Tens una arquitectura per capes amb tres fronteres que no es creuen —el domini no sap que hi ha navegador, la vista no sap d'on vénen les dades, les dades no saben què es pinta— i, el que és més important, les tens verificades per ESLint: has convertit una intenció en un error de compilació, que és l'única cosa que no s'erosiona. L'argument no és teòric: a 10-06, domini/regles.js va ser idèntic a les quatre versions de la mateixa pantalla.

Tens l'entorn muntat: Vite, ESLint i Prettier, Jest amb jsdom i Testing Library, Cypress, Husky i lint-staged, amb un guió verificar que resumeix el contracte del projecte en una línia i una regla sense excepcions. Tens Git de debò: branques curtes per història, commits convencionals el cos dels quals explica el perquè —l'única cosa que el diff no et pot explicar d'aquí a sis mesos— i revisions del teu propi codi amb distància, a la interfície web i amb llista de comprovació.

Tens un pla honest: 105 hores d'històries, factor de correcció per familiaritat, 20 % de reserva dibuixat al Gantt, sis fites que acaben cadascuna en alguna cosa que es pot ensenyar. Tens una Definició de Fet de la qual la majoria de caselles les verifica una màquina, desada com a plantilla de Pull Request perquè aparegui sola. I tens el pressupost de rendiment i accessibilitat fixat al principi, amb els números de Nómada Tasques com a referència: ≤ 60 kB, LCP ≤ 2,5 s, ≤ 1.500 nodes, 0 incidències greus d'axe, contrast 4,5:1 i res comunicat només per color.

La fita H1 està tancada: document d'abast, model de dades amb les seves regles, i un repositori que respon en verd. La pàgina és buida, i això és exactament el correcte, perquè ara saps què hi posaràs i per què.

El següent és posar-ho. I hi ha una manera de fer-ho que no és la intuïtiva —de dins cap a fora, començant per les regles i acabant pels píxels, i una funcionalitat completa abans que totes a mitges—: és Construcció del Projecte.

Curs de JavaScript: De Principiant a Avançat

Mòdul 1: Introducció a JavaScript

Mòdul 2: Estructures de Control

Mòdul 3: Funcions

Mòdul 4: Objectes i Arrays

Mòdul 5: Objectes i Funcions Avançades

Mòdul 6: El Model d'Objectes del Document (DOM)

Mòdul 7: APIs del Navegador i Temes Avançats

Mòdul 8: Proves i Depuració

Mòdul 9: Rendiment i Optimització

Mòdul 10: Frameworks i Llibreries de JavaScript

Mòdul 11: Projecte Final

© Copyright 2026. Tots els drets reservats