data-service
`data-service` is the only user-safe data access boundary for Vinova Backbone applications and microservices.
It exists to protect business data. Every request that reads or writes user-scoped application data must pass through this service so the authenticated user can be derived from the authentication token and every operation can be restricted to the data that user is allowed to access.
Data Access Boundary
Backbone separates raw persistence access from secure application data access:
- `datahub` exposes internal API access to all database tables. It is the
- `data-service` exposes authenticated, user-scoped APIs. It reads the
- `AdminInterface` is the only frontend allowed to access `datahub` directly,
- User-facing frontends and product microservices must access business data
persistence/data access layer and does not represent the user-facing security boundary.
authentication token, derives the logged-in user server-side, applies ownership/sharing rules, and only then calls `datahub`.
and only for administrative/operational data management flows.
through `data-service`, not through `datahub`.
This rule is mandatory because `datahub` can reach every table, while `data-service` enforces the security layer that prevents callers from selecting or modifying records owned by other users.
Browser clients and non-admin microservices must never send a trusted `userId` in the request body or query string. `data-service` must derive the effective user from the authentication token and build the authorization context itself.
The expected request flow is:
UserInterface / product service
-> data-service
-> validate authentication context
-> derive user and ownership scope
-> apply authorization filters
-> call datahub
-> return only allowed data
Direct `datahub` access is reserved for internal platform operations and AdminInterface tooling. It must not become a shortcut for application features.
Quick Start
# Development
npm run dev
# Production
npm start
Architecture
This service uses the centralized microservice framework:
- **BaseService** (modules/main.js): Business logic extends BaseService
- **serverFactory** (server.js): Express server with standard routes
- **No status.js**: Eliminated! Status routes provided by statusRouterFactory
`data-service` owns the authorization layer above `datahub`. Route handlers must keep business authorization close to the API surface and must call `datahub` only after the request has been associated with the authenticated user.
Analytics Boundary
UserInterface must call `data-service` for analytics data.
`data-service` must not implement analytics rules directly. It must:
- authenticate frontend analytics requests
- derive the logged-in user from the token
- enforce ownership and sharing filters
- build an `authorizationContext` from trusted server-side data
- call `analytic-service` internal APIs with an internal JWT
- return only analytics data the logged-in user is allowed to access
When calling `analytic-service`, `data-service` must not forward browser-provided `userId` values. If a user identifier is required, it must be placed under `authorizationContext.subject.userId` after being derived from the token.
Internal analytics calls target:
- `POST /internal/analytics/overview`
- `POST /internal/analytics/properties/:propertyId/summary`
- `POST /internal/analytics/contracts/:contractId/summary`
- `POST /internal/analytics/contracts/:contractId/health`
- `POST /internal/analytics/bank-accounts/:bankAccountId/summary`
- `POST /internal/analytics/report`
Frontend-facing analytics endpoints:
- `GET /analytics/overview`
- `GET /analytics/properties/:id/summary`
- `GET /analytics/contracts/:id/summary`
- `GET /analytics/contracts/:id/health`
- `GET /analytics/bank-accounts/:id/summary`
- `GET /analytics/report`
Through Traefik these are exposed under `/data-service/analytics/*`.
Each endpoint derives the user from `req.userCtx`, applies ownership/sharing checks through the shared access helpers, builds an internal `authorizationContext`, calls `analytic-service`, and returns the canonical payload received from the analytics boundary.
Internal token requirements:
- audience: `analytic-service`
- scope: `analytics:read`
- caller: `data-service`
Configuration:
- `ANALYTIC_SERVICE_URL`, fallback `http://analytic-service:3013`
Code Reduction
Traditional approach: ~650 lines (main.js + server.js + status.js) **This service: ~165 lines (75% reduction)**
Standard Endpoints
- `GET /status/health` - Health check
- `GET /status/info` - Service information
- `GET /release` - Release information
- `GET /settings` - Current settings
- `POST /settings/reload` - Reload settings from DB
Custom Endpoints
Administrative settings (authenticated platform administrators only):
- `GET /admin/settings` - Read settings metadata through `data-service`.
- `PUT /admin/settings/:key` - Persist a setting value in the database.
Add your custom routes in `server.js`:
routes: [
{ path: '/api', router: apiRouter, protected: true }
]
Development
Port: 5003
Access locally: http://localhost:5003
Documentation
- Shared infrastructure: `../../packages/backbone-shared`