# Backend API Updates — Phase 1 Implementation Spec

## Overview

Phase 1 is limited to low-risk backend additions that directly support the SuperAdmin refresh without reshaping existing API contracts.

This phase is intentionally additive except for one approved change:

- enforce SuperAdmin middleware on SuperAdmin routes

Everything else should avoid route-path changes, envelope changes, and field renames on existing endpoints.

---

## Phase 1 Scope

### Included

- SuperAdmin dashboard stats endpoint
- Service provider list enrichment
- Continued login timestamp persistence plus SuperAdmin-safe exposure
- SuperAdmin Laravel logs endpoint
- Site quote-part CSV import endpoint
- Site quote-part template download endpoint
- API docs and frontend integration notes for the new/extended responses

### Explicitly deferred

- site status support
- any schema change that introduces true site-level activation state
- cleanup or normalization of existing response envelopes
- large search/filter rewrites unless data volume proves it is needed

Reason for deferral:

- `sites` has no native `is_active` or `status` column
- current status behavior lives on `site_services.status`, which is a deeper model problem and should not be forced into Phase 1

---

## Existing API Impact Assessment

### Non-breaking changes

These changes are safe because they are additive:

- add `GET /api/dashboard-stats`
- add `GET /api/logs`
- add `POST /api/site-quote-part`
- add `GET /api/site-quote-part-template`
- add `site_count`, `user_count`, and `last_login_at` to `GET /api/service-providers`

### Approved breaking change

Current SuperAdmin routes are only behind JWT auth. Phase 1 will also enforce the existing `superadmin` middleware.

Impact:

- requests made with non-superadmin tokens to SuperAdmin endpoints will now fail
- this is intentional and approved

### Changes that must not happen in Phase 1

- do not add a URI prefix to existing SuperAdmin endpoints
- do not rename existing fields such as `last_login` on existing user/surveyor responses
- do not change paginator or Fractal envelope shapes on current endpoints
- do not repurpose `DELETE /api/site` into site-wide activation logic

### Frontend break risk summary

Known frontend risk is limited to authorization behavior:

- if any non-superadmin frontend screen is incorrectly calling SuperAdmin endpoints today, middleware enforcement will surface that bug immediately

No contract break should occur if Phase 1 keeps these rules:

- existing paths stay the same
- existing payload structures stay the same
- new fields are additive only

---

## Route Plan

Phase 1 should keep the existing URI style used in `routes/api.php`.

New routes:

```http
GET /api/dashboard-stats
GET /api/logs
POST /api/site-quote-part
GET /api/site-quote-part-template
```

Auth:

- JWT required
- SuperAdmin role required

Existing SuperAdmin routes that should also be role-protected in this phase:

- `POST /api/service-provider`
- `GET /api/service-providers`
- `PUT /api/service-provider`
- `DELETE /api/service-provider`
- `POST /api/service-provider-admin/reinvite`
- `GET /api/fetch-service-providers`
- `POST /api/site`
- `GET /api/sites`
- `GET /api/sitelists`
- `PUT /api/site`
- `DELETE /api/site`
- `POST /api/site/change-service-provider`
- `POST /api/lots-import-excel`
- `GET /api/lots-barcode-details`
- `POST /api/rate-management`
- `GET /api/rate-management`
- `PUT /api/rate-management`
- `DELETE /api/rate-management`
- `GET /api/fetch-rates`
- `POST /api/mail_check`
- `DELETE /api/site-lots`
- `POST /api/site-quote-part`
- `GET /api/site-quote-part-template`
- existing Vilogi SuperAdmin routes

---

## Endpoint 1 — Dashboard Stats

### Endpoint

```http
GET /api/dashboard-stats
```

### Auth

- JWT required
- SuperAdmin role required

### Purpose

- powers the SuperAdmin dashboard
- removes the current empty dashboard state
- gives a single request for the page instead of stitching together multiple calls

### Response shape

```json
{
  "status": true,
  "message": "Dashboard stats",
  "data": {
    "totals": {
      "service_providers": 12,
      "active_service_providers": 10,
      "sites": 48,
      "users": 91,
      "active_users": 84,
      "meters": 1260
    },
    "provider_breakdown": [
      {
        "id": 3,
        "name": "Alpha Utilities",
        "status": true,
        "site_count": 4,
        "user_count": 9,
        "meter_count": 188,
        "last_login_at": "2026-04-02T08:15:00Z"
      }
    ],
    "recent_activity": [
      {
        "type": "user_login",
        "label": "Provider admin logged in",
        "occurred_at": "2026-04-03T06:40:00Z",
        "service_provider_id": 3,
        "service_provider_name": "Alpha Utilities",
        "user_id": 17,
        "user_name": "Jane Doe",
        "meta": {
          "role_id": 2
        }
      },
      {
        "type": "site_created",
        "label": "Site created",
        "occurred_at": "2026-04-02T11:20:00Z",
        "service_provider_id": 5,
        "service_provider_name": "West Bay",
        "site_id": 44,
        "site_name": "Block C"
      }
    ]
  }
}
```

### Data rules

#### Totals

- `service_providers`: count of all service providers
- `active_service_providers`: count where `service_providers.status = 1`
- `sites`: count of all sites
- `users`: count of provider admins plus surveyors
- `active_users`: count where `users.status = 1`
- `meters`: count of lots

#### Provider breakdown

Each row should include:

- provider identity
- provider current status
- `site_count`
- `user_count`
- `meter_count`
- `last_login_at` as the latest non-null login among that provider's users

#### Recent activity feed

This is a lightweight operational feed, not an audit log.

Allowed data sources for Phase 1:

- `users.last_login`
- `users.created_at`
- `sites.created_at`
- `service_providers.created_at`
- `archived_sessions.created_at`

Suggested activity types:

- `user_login`
- `user_created`
- `site_created`
- `service_provider_created`
- `session_closed`

Rules:

- newest first
- keep payload compact
- target dashboard usefulness, not forensic completeness
- return a small bounded list such as the latest `10` or `15` items

### Implementation notes

- use a dedicated SuperAdmin dashboard controller/service instead of adding more bulk to the existing service-provider controller
- keep query count low; use grouped queries rather than N+1 loops
- no new tables are required for Phase 1

---

## Endpoint 2 — Service Provider List Enrichment

### Existing endpoint

```http
GET /api/service-providers
```

### Auth

- JWT required
- SuperAdmin role required in Phase 1

### Change type

Additive only. Existing response shape must remain intact.

### New fields per provider row

- `site_count`
- `user_count`
- `last_login_at`

### Response example

Only the new fields are shown below. Existing fields remain as they are today.

```json
{
  "status": true,
  "message": "Service provider list",
  "data": {
    "current_page": 1,
    "data": [
      {
        "id": 3,
        "name": "Alpha Utilities",
        "status": true,
        "site_count": 4,
        "user_count": 9,
        "last_login_at": "2026-04-02T08:15:00Z"
      }
    ]
  }
}
```

### Rules

- do not remove existing relations already returned by the endpoint
- do not rename any existing key
- `last_login_at` should be nullable
- `last_login_at` is derived from the provider's related users, not a new database column

### Implementation notes

- add a `sites()` relation on `ServiceProvider`
- use aggregate queries or eager-loaded counts
- avoid computing counts row-by-row in PHP

---

## Endpoint 3 — Last Login Tracking

### Scope in Phase 1

No schema change is needed in this phase.

Existing behavior already writes login timestamps to `users.last_login`.

Phase 1 work:

- keep the current persistence behavior
- expose a normalized `last_login_at` field only in SuperAdmin-facing responses added or extended in this phase

### Compatibility rule

Do not replace existing `last_login` fields on already-shipped endpoints.

That means:

- existing user/surveyor responses may keep `last_login`
- new SuperAdmin-oriented additions may use `last_login_at`

This avoids unnecessary frontend breakage while still giving the new UI a cleaner contract.

---

## Endpoint 4 — Laravel Logs

### Endpoint

```http
GET /api/logs
```

### Auth

- JWT required
- SuperAdmin role required

### Query params

- `date`: optional, format `YYYY-MM-DD`
- `level`: optional, case-insensitive log level filter such as `error`, `warning`, `info`
- `page`: optional, integer, default `1`

### Purpose

- allows an internal log viewer without shell access
- gives the frontend enough filtering to build a simple operational screen

### Response shape

```json
{
  "status": true,
  "message": "Logs list",
  "data": {
    "current_page": 1,
    "per_page": 50,
    "total": 312,
    "data": [
      {
        "timestamp": "2026-04-03 09:11:27",
        "level": "error",
        "channel": "local",
        "message": "SQLSTATE[23000]: Integrity constraint violation",
        "context": null,
        "source": "laravel.log"
      }
    ]
  }
}
```

### Rules

- newest first
- paginate in memory after parsing
- multiline stack traces should stay attached to the originating log entry
- default source is `storage/logs/laravel.log`
- Phase 1 may ignore non-primary channels if that keeps the implementation simple

### Implementation notes

- build a small parser service instead of mixing file IO into the controller
- return a stable shape even when no logs are found
- invalid filters should return validation errors, not partial guesses

---

## Endpoint 5 — Site Quote-Part CSV Import

### Endpoint

```http
POST /api/site-quote-part
```

### Auth

- JWT required
- SuperAdmin role required

### Purpose

- bulk-update `lots.quote_part` for one site
- keep quote-part maintenance separate from the full lot import flow
- support the bowser fallback dependency without re-uploading all lot metadata

### Request

`multipart/form-data`

Fields:

- `site_id`: required integer
- `service_type_id`: optional integer, defaults to `1` for water
- `file`: required CSV file

### CSV format

Headers:

```csv
Barcode,Quote Part (%)
```

Example:

```csv
Barcode,Quote Part (%)
1234567890,12.50
1234567891,7.25
```

### Validation rules

Follow the existing lot-upload validation style where applicable.

Request-level rules:

- `file` is required
- `site_id` is required
- `service_type_id` defaults to `1` when omitted
- empty uploads should fail

Per-row rules:

- `barcode` is required
- `barcode` must resolve to an existing lot for the given `site_id`
- matched lot must belong to the requested `service_type_id`
- `quote_part` is required
- `quote_part` must be numeric
- `quote_part` must be between `0` and `100`

### Behavior

- header row is skipped
- rows are matched by barcode only
- only `lots.quote_part` is updated
- lot owner, meter, reading, and site metadata remain untouched
- partial failure is allowed; invalid rows fail individually and are counted

### Response example

```json
{
  "status": true,
  "message": "Quote-part CSV uploaded successfully! Successful: 18, Failed: 2"
}
```

### Implementation notes

- add this to the SuperAdmin service-provider workflow
- reuse the existing CSV file-reading pattern from the current lot import flow
- reuse the existing `quote_part` numeric range validation already applied during lot upload
- keep row processing transaction-safe in the same style as the lot import endpoint

---

## Endpoint 6 — Site Quote-Part Template Download

### Endpoint

```http
GET /api/site-quote-part-template
```

### Auth

- JWT required
- SuperAdmin role required

### Query params

- `site_id`: required integer
- `service_type_id`: optional integer, defaults to `1` for water

### Purpose

- generate the quote-part upload template for a site
- prefill operators with the correct barcode list for the selected site/service

### Response

CSV download with these columns:

```csv
Barcode,Quote Part (%)
```

Recommended exported rows:

- `Barcode`: prefilled from the lot's related barcode
- `Quote Part (%)`: prefilled from current `lots.quote_part` when present, else empty

### Implementation notes

- reuse the existing CSV streaming/export pattern used by the open-session CSV download flow
- this should be site-scoped and service-scoped
- default `service_type_id` to `1` if omitted
- order rows consistently, preferably by lot number

---

## Search and Filtering

This remains optional in Phase 1.

If needed after the core work lands, add query params to existing list endpoints:

- `GET /api/service-providers?search=alpha`
- `GET /api/sites?search=block`
- `GET /api/rate-management?search=water`

Rules:

- additive only
- no new list endpoints
- no change to default behavior when `search` is absent

---

## Frontend Integration Notes

### General rules

- treat all existing endpoints as unchanged unless the notes below explicitly say otherwise
- do not assume response normalization across old and new endpoints
- only SuperAdmin screens should call the new dashboard and logs endpoints

### 1. SuperAdmin dashboard

Use `GET /api/dashboard-stats` as the single page bootstrap request.

Frontend usage:

- show top-level cards from `data.totals`
- use `data.provider_breakdown` for the provider table or health list
- use `data.recent_activity` for the activity panel

Recommended client behavior:

- do not make extra count calls for this page
- allow `last_login_at` to be `null`
- render empty-state messaging if `recent_activity` is empty

### 2. Service provider management page

Continue using `GET /api/service-providers`.

Frontend usage:

- keep current list rendering logic
- add display columns for `site_count`, `user_count`, and `last_login_at`
- do not depend on those fields existing in older environments until the backend deploy lands

Recommended UI fallbacks:

- `last_login_at = null` => display `Never`
- counts missing during rollout => hide the column or show `-`

### 3. Logs page

Use `GET /api/logs`.

Frontend usage:

- filter by `date`
- optionally filter by `level`
- paginate using `page`

Recommended UI constraints:

- show the message line first
- allow expansion for long messages or stack traces
- make this a read-only internal tool; no log deletion or download workflow in Phase 1

### 4. Quote-part maintenance flow

Use this pair of endpoints for quote-part maintenance:

- `GET /api/site-quote-part-template?site_id=:id&service_type_id=1`
- `POST /api/site-quote-part`

Frontend usage:

- download the template for the selected site
- edit only the `Quote Part (%)` column
- upload the CSV back through the quote-part import endpoint

Client rules:

- when `service_type_id` is omitted, assume water
- barcode is the row identifier; do not match by lot number in the client
- preserve the CSV header names

Recommended UI constraints:

- show upload result counts for successful and failed rows
- let operators fix failed rows and re-upload
- keep this flow separate from full lot onboarding/import

### 5. Middleware enforcement impact

Because SuperAdmin middleware will be enforced in Phase 1:

- provider-admin tokens must not be used on SuperAdmin screens
- frontend should handle `401` and `406` responses cleanly
- if a page currently depends on a provider-admin token for SuperAdmin APIs, that is a frontend bug to fix during integration

---

## Verification

Minimum verification pass:

- SuperAdmin-only endpoints reject non-superadmin authenticated users
- `GET /api/dashboard-stats` returns the documented top-level keys
- `GET /api/service-providers` keeps its existing envelope and includes the additive fields
- `GET /api/logs` validates filters and paginates correctly
- `GET /api/site-quote-part-template` returns the expected CSV headers and site rows
- `POST /api/site-quote-part` defaults `service_type_id` to water and updates only matching lots
- login still updates `users.last_login`
- no existing admin or surveyor endpoints are behaviorally changed by these additions

Recommended tests:

- feature test for dashboard stats access and payload shape
- feature test for logs access control and filter validation
- feature test for service-provider enrichment fields
- feature test for quote-part template download headers and default service type
- feature test for quote-part CSV upload success, partial failure, and numeric validation
- feature test confirming non-superadmin access is denied on SuperAdmin endpoints

---

## Out of Scope for This Phase

- site-wide status toggle design
- adding `sites.status` or `sites.is_active`
- changing `DELETE /api/site` semantics
- broad API contract cleanup across legacy endpoints
- audit-grade activity tracking

---

## Success Criteria

- SuperAdmin dashboard can load meaningful operational data in one request
- service-provider management becomes data-usable instead of mostly decorative
- internal operators can inspect Laravel logs without shell access
- existing frontend integrations remain stable except where middleware enforcement intentionally blocks invalid access
