Datu-basea

pakAG-ek MySQL erabiltzen du (datu-basearen izena erronka da schema.sql arabera; .env.example-ek pakag dokumentatzen du, ikusi arrisku ezagunak).

Eskemaren egia-iturria: schema.sql monorepoaren erroan.

Taulak

addresses

Geokodetutako entrega helbideak. Paketea sortzeko fluxuak sortzen ditu (Google Geocoding API).

ZutabeaMotaOharrak
idINT UNSIGNED AUTO_INCREMENTPK
streetVARCHAR(255)
cityVARCHAR(100)
postal_codeVARCHAR(20)
countryVARCHAR(100)Default 'Espana'
latitudeDECIMAL(10,7)Google API-k geokodetua
longitudeDECIMAL(10,7)Google API-k geokodetua
created_atTIMESTAMP

[!NOTE] SQL kontsultek latitude/longitude aliasatzen dituzte lat/lng gisa TypeScript motetan. DB-ko zutabe izenak eta frontend motetako field izenak ez dira berdinak.


users

Sistemako erabiltzaileak: admin-ak eta banatzaileak.

ZutabeaMotaOharrak
idINT UNSIGNED AUTO_INCREMENTPK
nameVARCHAR(150)
emailVARCHAR(255) UNIQUE
password_hashVARCHAR(255)bcrypt
roleENUM('admin','distributor')Default 'distributor'
is_activeBOOLEANDefault TRUE. Erabiltzaile berriak inaktibo sortzen dira aktibazio fluxuaren bidez
created_atTIMESTAMP
updated_atTIMESTAMPErrenkada aldatzean automatikoki eguneratzen da

packages

Domeinuko entitate nagusia. Entregatu beharreko paketea adierazten du.

ZutabeaMotaOharrak
idINT UNSIGNED AUTO_INCREMENTPK
tracking_codeVARCHAR(50) UNIQUEGizakiek irakurtzeko kode laburra, adibidez PAK-20260001
recipient_nameVARCHAR(150)
recipient_emailVARCHAR(255)Egoera jakinarazpen emailak jasotzen ditu
weight_kgDECIMAL(6,3)
descriptionTEXT NULLAukerakoa
statusENUM(...)Ikusi egoera makina behean
estimated_deliveryDATE NULLRuta sortzean ezartzen da; ruta optimizatzean eguneratzen da
address_idINT UNSIGNEDFK -> addresses.id
assigned_toINT UNSIGNED NULLFK -> users.id. ON DELETE SET NULL
created_byINT UNSIGNEDFK -> users.id
created_atTIMESTAMP
updated_atTIMESTAMP

Pakete egoeren makina

pending -> assigned -> in_transit -> delivered
                           -> undelivered
                           -> failed

Trantsizio bakoitzak package_status_logs-en sarrera bat eta hartzailearentzako email bat sortzen du. Ikusi Domeinu eredua albo-efektuen taula osorako.


tokens

Sistemako token mota guztietarako taula bakarra.

ZutabeaMotaOharrak
idINT UNSIGNED AUTO_INCREMENTPK
tokenVARCHAR(512) UNIQUEToken balio opakoa (32 byte-ko hex edo JWT string-a)
typeENUM(...)refresh_token, tracking_token, reset_pwd_token, activate_account_token
user_idINT UNSIGNED NULLFK -> users.id. refresh_token-erako ezartzen da; ON DELETE CASCADE
package_idINT UNSIGNED NULLFK -> packages.id. tracking_token-erako ezartzen da; ON DELETE CASCADE
expires_atTIMESTAMP
revokedBOOLEANDefault FALSE. Erabiltzean edo logout egitean ezeztatzen da
created_atTIMESTAMP

Token bizitzak (env bidez konfiguratuta):

  • refresh_token: JWT_REFRESH_EXPIRES_DAYS (default 7 egun)
  • tracking_token: TRACKING_EXPIRES_DAYS (default 30 egun)
  • reset_pwd_token / activate_account_token: 24 ordu (hardcodeatuta)

package_status_logs

Pakete egoera aldaketa guztien historia osoa.

ZutabeaMotaOharrak
idINT UNSIGNED AUTO_INCREMENTPK
package_idINT UNSIGNEDFK -> packages.id. ON DELETE CASCADE
old_statusENUM NULLNULL hasierako egoera esleipenerako
new_statusENUM
changed_byINT UNSIGNEDFK -> users.id
notesTEXT NULL
changed_atTIMESTAMP

routes

Entrega ruta bat banatzaile eta egun natural bakoitzeko (constraint bakarrak bermatuta).

ZutabeaMotaOharrak
idINT UNSIGNED AUTO_INCREMENTPK
user_idINT UNSIGNEDFK -> users.id (distributor izan behar du)
route_dateDATE
statusENUM('planned','in_progress','completed')Default 'planned'
created_atTIMESTAMP
updated_atTIMESTAMP

Constraint bakarra: (user_id, route_date): banatzaile bakoitzeko ruta bat eguneko.


route_stops

Ruta baten barruko geldialdiak. Geldialdi bat = pakete entrega bat.

ZutabeaMotaOharrak
idINT UNSIGNED AUTO_INCREMENTPK
route_idINT UNSIGNEDFK -> routes.id. ON DELETE CASCADE
package_idINT UNSIGNEDFK -> packages.id. ON DELETE CASCADE
stop_orderSMALLINTGoogle Directions API-k optimizatua
estimated_arrivalTIME NULLRuta sortzean kalkulatua
actual_arrivalTIME NULLBanatzaileak iritsiera markatzean ezarria
created_atTIMESTAMP

Constraint bakarra: (route_id, stop_order): bi geldialdik ezin dute ordena bera partekatu ruta batean.


Erlazioak

users --- packages (assigned_to, created_by)
users --- routes (user_id)
users --- package_status_logs (changed_by)
users --- tokens (user_id)

packages --- addresses (address_id)
packages --- route_stops (package_id)
packages --- package_status_logs (package_id)
packages --- tokens (package_id, tracking_token-erako)

routes --- route_stops (route_id)

Indizeak

CREATE INDEX idx_packages_status      ON packages (status);
CREATE INDEX idx_packages_assigned_to ON packages (assigned_to);
CREATE INDEX idx_packages_created_at  ON packages (created_at);
CREATE INDEX idx_tokens_type_expires  ON tokens (type, expires_at, revoked);
CREATE INDEX idx_logs_package_date    ON package_status_logs (package_id, changed_at);
CREATE INDEX idx_routes_date          ON routes (route_date);

SQL konbentzioak

  • Kontsulta guztiek prepared statements erabiltzen dituzte (mysql2 ? placeholder-ekin). Ez dago string kateaketarik.
  • ID-ak: INT UNSIGNED AUTO_INCREMENT PRIMARY KEY.
  • Timestamp-ak: TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP.
  • Ez dago soft delete-rik packages taulan; egoera historikoa package_status_logs-en gordetzen da.
  • addresses ez dira ezabatzen pakete bat ezabatzean (Needs verification: ez dago ON DELETE CASCADE packages.address_id FK-an).

Arrisku ezagunak

ArriskuaXehetasuna
DB izenaren inkoherentziaschema.sql-ek DB-a erronka gisa sortzen du; .env.example-ek MYSQL_DATABASE=pakag dokumentatzen du. Migrazio aurretik egiaztatu produkzioan zein izen erabiltzen den.
Startup balidaziorik ezMYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE env aldagaiak undefined izan daitezke hasieran errorerik gabe. Pool-ak isilik huts egiten du lehen kontsultan.