Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/GianlucaBessone/HDB-Service/llms.txt

Use this file to discover all available pages before exploring further.

Every record in HDB Service — dispensers, tickets, stock entries, maintenance schedules, and users — lives within a strict five-level hierarchy: Client → Plant → Sector → Location → Dispenser. This hierarchy exists to model real-world installations accurately (a company may run dozens of factories, each with distinct operational zones) and to enforce data isolation automatically: users always operate within the scope of their Client and, when relevant, their assigned Plants.

The five levels

Client

A Client represents an organization or company that contracts HDB Service for water dispenser fleet management. It is the top-level ownership boundary — every plant, dispenser, user, and SLA configuration belongs to exactly one Client.
FieldTypeNotes
idString (cuid)Primary key
nombreStringCompany name
emailString?Contact email
telefonoString?Contact phone
direccionString?Physical address
activeBooleanSoft-delete flag
Relationships downward: A Client owns many Plants and optionally has one SlaConfig that overrides platform defaults for all its tickets.

Plant

A Plant represents a physical facility or site belonging to a Client — a factory, office building, warehouse, or distribution centre. Each Plant is geo-tagged and can hold its own inventory stock.
FieldTypeNotes
idString (cuid)Primary key
clientIdStringForeign key → Client
nombreStringFacility name
direccionString?Address
lat / lngFloat?GPS coordinates
activeBooleanSoft-delete flag
Relationships: A Plant belongs to one Client, contains many Sectors (via PlantSector junction), many Locations, and has its own StockEntry records. The UserPlantAccess join table grants CLIENT_REQUESTER users access to specific Plants.

Sector

A Sector represents a functional or physical zone within a Plant — for example, Production, Office, or Warehouse. Sectors are defined globally and can be reused across multiple Plants through the PlantSector junction table.
FieldTypeNotes
idString (cuid)Primary key
nombreStringSector name
descripcionString?Optional description
activeBooleanSoft-delete flag
Relationships: A Sector is attached to one or more Plants via PlantSector, and contains many Locations. Because Sectors are reused across Plants, the Plant–Sector relationship is many-to-many.

Location

A Location is a specific physical spot within a Plant and Sector where a dispenser can be installed — a corridor, break room, or production line station. Each Location has a globally unique, user-defined ID that typically mirrors a physical label or QR code.
FieldTypeNotes
idStringUser-defined, globally unique
plantIdStringForeign key → Plant
sectorIdString?Optional FK → Sector
nombreStringDisplay name
pisoString?Floor
areaString?Area within the sector
descripcionString?Free-text notes
activeBooleanSoft-delete flag
Relationships: A Location belongs to one Plant (and optionally one Sector). Application logic enforces that at most one active Dispenser occupies a Location at any time. Location IDs are also used as QR code anchors for quick ticket creation.

Dispenser

A Dispenser is the core physical asset being managed — a water dispenser unit identified by a user-defined, globally unique ID (often matching the unit’s serial label). Dispensers carry full lifecycle, repair, consumable, and spare-parts history.
FieldTypeNotes
idStringUser-defined, globally unique
marcaStringBrand
modeloStringModel
statusDispenserStatusCurrent operational state
locationIdString?Current location (nullable)
plantIdString?Home plant
clientIdString?Owning client
lifecycleMonthsIntExpected service lifetime (default 60)
lifecycleStartDateDateTime?When active lifecycle began
lifecyclePausedAtDateTime?Set when status → BACKUP
lifecycleAccumulatedPauseDaysIntTotal days paused over lifetime
numeroSerieString?Manufacturer serial number
fechaCompraDateTime?Purchase date
Relationships: A Dispenser sits in one Location (or none), belongs to one Plant and Client, and aggregates history tables for location assignments, repairs, consumable installs, and spare-part replacements.

Hierarchy in practice

Consider AquaCorp S.A., a manufacturing company using HDB Service across two facilities:
1

Client: AquaCorp S.A.

The top-level entity. All plants, users, and the client-specific SLA configuration live here.
2

Plants: North Factory & South Office

Two physical sites registered under the AquaCorp client. Each has its own GPS coordinates, stock, and user access list.
3

Sectors per Plant

  • North FactoryProduction sector, Warehouse sector
  • South OfficeOffice Floor 1 sector, Office Floor 2 sector
Sectors are linked to each plant via the PlantSector junction table.
4

Locations per Sector

  • ProductionLOC-NF-001 (Assembly Line A), LOC-NF-002 (Assembly Line B)
  • WarehouseLOC-NF-010 (Loading Bay)
  • Office Floor 1LOC-SO-001 (Reception), LOC-SO-002 (Meeting Room)
5

Dispensers at Locations

Each active Location holds at most one Dispenser:
  • DISP-0042 (IN_SERVICE) → LOC-NF-001
  • DISP-0043 (IN_SERVICE) → LOC-NF-002
  • DISP-0099 (BACKUP) → no location assigned — held in reserve at North Factory

Dispenser lifecycle states

The DispenserStatus enum controls where a dispenser appears in operations, maintenance scheduling, and reporting.

IN_SERVICE

The dispenser is actively deployed at a location and available for normal operation. Tickets, maintenance schedules, and SLA tracking are fully active.

UNDER_REPAIR

The dispenser has been removed from service for repairs. It may not have a location assigned while in this state.

OUT_OF_SERVICE

The dispenser is permanently or temporarily decommissioned. It is excluded from active fleet reporting.

BLOCKED

The dispenser has been blocked and requires an OC (Order of Correction) release from a CLIENT_RESPONSIBLE user before it can return to service. The blockedReason and blockedAt fields are populated.

BACKUP

The dispenser is a reserve unit held in stock. Its lifecycle timer is paused — time spent in this state does not count toward the unit’s service lifetime. Accumulated pause time is tracked in lifecycleAccumulatedPauseDays.

IN_TECHNICAL_SERVICE

The dispenser is with technical service staff — deeper diagnostic or refurbishment work beyond a standard repair.

BLOCKED_WAITING_OC

A transitional blocked state indicating that an OC document is pending review. The unit remains offline until the OC is processed.

Data scoping

Every user in HDB Service is scoped to their data automatically — no route handler needs to manually filter by client or plant. This is achieved through two complementary mechanisms:
  • clientId on usersCLIENT_RESPONSIBLE and CLIENT_REQUESTER users have a clientId field linking them to their organization.
  • UserPlantAccess join tableCLIENT_REQUESTER users are granted access to a specific subset of Plants within their Client.
At every API route, getDataFilter() from lib/auth.ts is called with the current SessionUser and returns the appropriate Prisma WHERE clause:
// ADMIN / SUPERVISOR — no filter, see everything
getDataFilter(user)  // returns {}

// CLIENT_RESPONSIBLE — filtered to their client
getDataFilter(user, { clientIdField: 'clientId' })
// returns { clientId: user.clientId }

// CLIENT_REQUESTER — filtered to their assigned plants
getDataFilter(user, { plantIdField: 'plantId' })
// returns { plantId: { in: user.plantIds } }
This ensures that cross-client data leakage is structurally impossible at the database query layer.
A Dispenser can be in BACKUP status without a LocationlocationId is nullable for this reason. While in BACKUP, the dispenser’s lifecycle clock is paused: lifecyclePausedAt records when it entered backup, and lifecycleAccumulatedPauseDays accumulates the total number of days spent in reserve over the unit’s lifetime.

Build docs developers (and LLMs) love