SERVICE_OVERVIEW — analytics-service
Bundle index: SERVICE_OVERVIEW · DOMAIN_MODEL · APPLICATION_LOGIC · API_CONTRACTS · EVENT_SCHEMAS · DATA_MODEL · SYNC_CONTRACT · AI_INTEGRATION · SECURITY_MODEL · OBSERVABILITY · TESTING_STRATEGY · DEPLOYMENT_TOPOLOGY · FAILURE_MODES · LOCAL_DEV_SETUP · SERVICE_READINESS · SERVICE_RISK_REGISTER · MIGRATION_PLAN
Strategic anchors: 02 Enterprise Architecture · 04 Event-Driven Architecture · 05 API Design · 06 Data Models · 07 Security/Compliance/Tenancy · 08 AI Architecture
1. Purpose
analytics-service is the read-side analytics platform of Ghasi Melmastoon. It turns the firehose of platform domain events into:
- Trustworthy facts in BigQuery curated tables (
fact_*,dim_*). - Defined metrics with frozen SQL semantics (occupancy %, ADR, RevPAR, ALOS, cancellation rate, no-show rate, channel mix, AI-suggestion-acceptance rate).
- Composable dashboards (KPI tiles, time-series, breakdown, funnel, heatmap) for hotel staff, managers, and tenant admins.
- Aggregated signals that
ai-orchestrator-serviceingests (occupancy curves, lead-time distributions, day-of-week and seasonality features) and writes back as forecasts.
It does not compute UI; the BFF (bff-backoffice-service) and Looker Studio render. It does not generate documents; reporting-service does. It does not run inference; ai-orchestrator-service does.
2. Bounded context
Analytics — Supporting bounded context in the platform context map (02 §3).
Public-facing because tenant admins author dashboards and view widgets, and Looker Studio is a paid power-user surface; otherwise its primary consumers are internal services.
3. Aggregates owned
| Aggregate | One-line | Storage |
|---|---|---|
AnalyticsEvent | Raw event landing in BigQuery (immutable) | BigQuery events_raw.* |
Projection | Curated table definition (target schema, source query, refresh policy, freshness SLO, version) | Cloud SQL analytics.projections |
MetricDefinition | Frozen-SQL metric with dimensions, units, allowed filters | Cloud SQL analytics.metric_definitions |
Dashboard | Tenant-admin-authored composition of widgets | Cloud SQL analytics.dashboards |
Widget | One visual element bound to a metric or query | Cloud SQL analytics.widgets |
Query | Saved curated query (named, parameterized) | Cloud SQL analytics.queries |
ETLJob | Scheduled or on-demand refresh of one or more projections | Cloud SQL analytics.etl_jobs |
DataQualityCheck | Definition + most recent result for one quality assertion | Cloud SQL analytics.dq_checks, history in BigQuery dq_results |
Detailed structure & invariants in DOMAIN_MODEL.
4. Responsibilities
- Event landing. Pub/Sub-to-BigQuery managed subscriptions land every
melmastoon.*event intoevents_raw.<topic_unsuffixed>with envelope + payload columns. - Curated layer ETL. Scheduled jobs (Cloud Workflows + Cloud Run Jobs) MERGE incremental rows from raw to curated tables; clustered & partitioned per DATA_MODEL §3.
- Metric definitions registry. Versioned, frozen-SQL metrics with explicit dimension/grain.
- Query API. Authenticated REST API to run pre-defined queries and read widget data, with byte caps and slot routing.
- Dashboard authoring. CRUD on dashboards & widgets; per-tenant scope; sharing via Looker Studio embed tokens.
- Data quality. Row-count drift, freshness lag, null rate, distinct-count, business-rule checks; results published as events.
- AI pipeline. Publish
metric.computed.v1for occupancy/forecasting features; consumeai.forecast.produced.v1to writefact_demand_forecast. - Tenant isolation. Per-tenant authorized views; managed service account never executes raw SQL on behalf of tenants without view-binding.
5. Context map
| Direction | Counterpart | Relationship |
|---|---|---|
| Upstream consumer | every emitting service | Pub/Sub conformist |
| Downstream | reporting-service | Reads curated tables; we expose stable schemas with version pins |
| Downstream | bff-backoffice-service | Customer/Supplier; we are supplier of widget data |
| Downstream | ai-orchestrator-service | Customer/Supplier (bidirectional): we publish signals, consume forecasts |
| Downstream | Looker Studio | Open Host Service via authorized views |
| Peer | tenant-service | Conformist for residency, deletion, region change |
| Peer | audit-service | Anti-corruption layer for DQ alert audit trail |
| Peer | iam-service | Conformist for permissions and JWT |
6. End-to-end pipeline (sketch)
[Pub/Sub topic melmastoon.*]
│
▼
[Pub/Sub-to-BigQuery subscription]
│ (raw envelope + payload JSON)
▼
events_raw.<topic> (partition by ingestion_ts, cluster by tenant_id)
│
│ scheduled (5 min hot, 15 min cold)
▼
[ETLJob: merge_curated_<domain>]
│ reads: events_raw.<…>, dim_*, prior fact_*
│ writes: fact_<domain> (incremental MERGE)
▼
[fact_reservation, fact_payment, fact_housekeeping_task, fact_lock_action, …]
│
├──▶ Query API ──▶ Widget data ──▶ Electron desktop dashboard
├──▶ Authorized View ──▶ Looker Studio
├──▶ reporting-service (read-only)
└──▶ MetricDefinition.compute() ──▶ metric.computed.v1 ──▶ ai-orchestrator
│
▼
ai.forecast.produced.v1 → fact_demand_forecast
7. Domain invariants
- Immutable raw.
events_raw.*rows are never updated or deleted by analytics jobs except viatenant.deletedpurge. - Curated is idempotent. Re-running a curated MERGE for the same window must produce the same rows (deterministic source query + stable hash keys).
- Tenant scoping. Every curated row carries
tenant_id. Authorized views always restrict toWHERE tenant_id IN (SELECT tenant_id FROM session_tenant_scope()). - Metric reproducibility. A metric value at a given
(window, filters, version)must be reproducible from raw events for the retention window. - Schema versioning. Curated tables carry
_schema_version; consumers pin to a major version; breaking changes ship as a new table (e.g.,fact_reservation_v2) with a coexistence window of one quarter.
8. Hot read paths
| Path | Latency target | Notes |
|---|---|---|
| Widget data (cached) | p95 ≤ 250 ms | Memorystore Redis cache keyed by (widgetId, paramsHash, asOfWindow) |
| Widget data (cold) | p95 ≤ 800 ms | BigQuery curated read with byte cap |
| Ad-hoc query (curated) | p95 ≤ 3 s | ≤ 1 GB scanned; per-tenant slot reservation |
| Ad-hoc query (raw) | gated to admins | up to 30 s |
| Metric compute (window) | p95 ≤ 5 s | scheduled batch path; ad-hoc allowed for tenant.admin |
9. Cost & scale envelope
| Dimension | Phase 1 |
|---|---|
| Tenants | 1k pilots → 50k SMB hotels |
| Events ingested/day | 1M (early) → 200M (mid) |
| Curated tables | 10 fact + 8 dim |
| BigQuery slots | reservation 200 (baseline), autoscale 800 |
| Cloud SQL (metadata) | 4 vCPU / 16 GiB regional HA |
| Memorystore Redis | 5 GiB tier |
| Per-tenant cost cap | configurable; default 50 USD / month equivalent of slot ms + bytes scanned |
10. Key dependencies
- NestJS (TypeScript) — API and worker layout per APPLICATION_LOGIC §1.
- Drizzle — Cloud SQL Postgres for metadata.
@google-cloud/bigquery,@google-cloud/pubsub,@google-cloud/storage,@google-cloud/scheduler,@google-cloud/workflows.@google-cloud/dataform(optional) for SQL workflow definitions; otherwise plain SQL files inetl/executed via the Workflows runner.- OpenTelemetry SDK; SigNoz + Cloud Monitoring.
- Cloud KMS (CMEK) for any small staging buckets we own.
- Looker Studio as a downstream consumer (no SDK dependency on our side; we expose authorized views).
11. Decision log anchors
- ADR-0001 Core architecture & tech stack — establishes BigQuery as analytics warehouse and TypeScript/NestJS for application services.
- ADR-0002 Multi-tenancy model — defines per-tenant authorized view RLS for BigQuery analytics access.
- ADR-0003 Electron offline-first desktop — defines KPI snapshot pull contract for desktop (SYNC_CONTRACT).
12. Cross-references
- Frozen metric SQL: DATA_MODEL §6, DOMAIN_MODEL §3.
- Authorized view binding: SECURITY_MODEL §3.
- ETL orchestration: DEPLOYMENT_TOPOLOGY §3.
- AI feedback loop: AI_INTEGRATION.