Skip to content

Commit eb559d2

Browse files
Kanishkavijay39Kanishka
andauthored
feat: add projection support to suggestions API [SITES-39183] (#1693)
## Summary Adds field projection via a `view` query parameter and optional status filtering to the Suggestions API endpoints. This allows clients to request lighter payloads optimized for specific UI needs (e.g., selection lists, table displays). Implements API projection for suggestions with a schema-driven architecture. This PR integrates with spacecat-shared PR-1289 which provides type-specific data schemas, validation, and projection logic. adobe/spacecat-shared#1289 ## Changes ### `view` parameter Pre-defined projections for all GET suggestion endpoints: | View | Returns | Use Case | |------|---------|----------| | `minimal` | `id`, `status`, URL-related `data` fields | Lightest payload for selection lists | | `summary` | Minimal + `opportunityId`, `type`, `rank`, `url`, timestamps | Table displays without heavy data | | `full` | All fields including `data` and `kpiDeltas` | Default, backward compatible | ### `status` parameter Filter suggestions by status (non-paginated endpoint only): - Single status: `?status=NEW` - Multiple statuses: `?status=NEW,APPROVED,IN_PROGRESS` - Valid values: `NEW`, `APPROVED`, `SKIPPED`, `FIXED`, `ERROR`, `IN_PROGRESS`, `OUTDATED`, `PENDING_VALIDATION` - Returns `400 Bad Request` for invalid status values > **Note:** Status filtering excluded from paginated endpoints to avoid pagination inconsistencies. Use `/by-status/{status}/paged` for paginated status-filtered results. ## Example Usage ### Minimal view for selection list GET /sites/{siteId}/opportunities/{opptyId}/suggestions?view=minimal ### Summary view with status filter GET /sites/{siteId}/opportunities/{opptyId}/suggestions?view=summary&status=NEW,FIXED ### Full view (default) GET /sites/{siteId}/opportunities/{opptyId}/suggestions --------- Co-authored-by: Kanishka <kanishka@adobe.com>
1 parent ff362d2 commit eb559d2

13 files changed

Lines changed: 10618 additions & 8745 deletions

File tree

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,27 @@ $ npm install
6161
$ npm test
6262
```
6363

64+
### E2E Tests
65+
66+
End-to-end tests validate the API against the live CI environment.
67+
68+
#### Setup
69+
70+
Add the following to your `.env` file:
71+
72+
```plaintext
73+
USER_API_KEY=your_api_key_for_ci_environment
74+
```
75+
76+
The E2E tests use a hardcoded test site ID and auto-discover opportunities/suggestions for testing.
77+
(You can change site id according to you)
78+
79+
#### Run E2E Tests Locally
80+
81+
```bash
82+
$ npm run test-e2e
83+
```
84+
6485
### Lint
6586

6687
```bash

docs/index.html

Lines changed: 8465 additions & 8706 deletions
Large diffs are not rendered by default.

docs/openapi/parameters.yaml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,3 +384,43 @@ cursor:
384384
schema:
385385
type: string
386386
example: "eyJzayI6IjIwMjQtMDEtMTVUMTI6MzA6MDBaIiwiaWQiOiIxMjNlNDU2Ny1lODliLTEyZDMtYTQ1Ni00MjY2MTQxNzQwMDAifQ=="
387+
388+
suggestionView:
389+
name: view
390+
description: |
391+
Projection view for suggestion response data. Controls which fields are returned.
392+
- `minimal`: Returns id, status, timestamps (createdAt, updatedAt), and URL-related data fields (lightest payload for selection lists)
393+
- `summary`: Returns key fields: id, opportunityId, type, rank, status, url, timestamps (excludes heavy data and kpiDeltas)
394+
- `full`: Returns all fields including data and kpiDeltas (default, backward compatible)
395+
in: query
396+
required: false
397+
schema:
398+
type: string
399+
enum:
400+
- minimal
401+
- summary
402+
- full
403+
default: full
404+
example: summary
405+
406+
suggestionStatus:
407+
name: status
408+
description: |
409+
Filter suggestions by status. Supports single status or comma-separated multiple statuses.
410+
When provided, only suggestions matching any of the specified statuses are returned.
411+
412+
**Valid values:** NEW, APPROVED, SKIPPED, FIXED, ERROR, IN_PROGRESS, OUTDATED, PENDING_VALIDATION
413+
414+
Returns 400 Bad Request if invalid status values are provided.
415+
in: query
416+
required: false
417+
schema:
418+
type: string
419+
description: Single status or comma-separated statuses (e.g., "NEW" or "NEW,APPROVED")
420+
examples:
421+
single:
422+
value: NEW
423+
summary: Filter by single status
424+
multiple:
425+
value: NEW,APPROVED,IN_PROGRESS
426+
summary: Filter by multiple statuses (comma-separated)

docs/openapi/schemas.yaml

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2923,6 +2923,147 @@ SuggestionList:
29232923
type: array
29242924
items:
29252925
$ref: '#/Suggestion'
2926+
SuggestionMinimal:
2927+
type: object
2928+
description: Minimal suggestion projection containing id, status, timestamps, and URL-related data fields for listing views
2929+
properties:
2930+
id:
2931+
description: UUID of this suggestion
2932+
$ref: '#/Id'
2933+
status:
2934+
description: Status of this suggestion
2935+
$ref: '#/SuggestionStatus'
2936+
data:
2937+
type: object
2938+
description: URL-related fields extracted from the full data object. Only present if any URL fields exist.
2939+
properties:
2940+
url:
2941+
type: string
2942+
example: "https://example.com/page"
2943+
urls:
2944+
type: array
2945+
items:
2946+
type: string
2947+
urlFrom:
2948+
type: string
2949+
example: "https://example.com/source"
2950+
urlTo:
2951+
type: string
2952+
example: "https://example.com/destination"
2953+
url_from:
2954+
type: string
2955+
description: Source URL (snake_case variant for broken backlinks)
2956+
example: "https://example.com/source"
2957+
url_to:
2958+
type: string
2959+
description: Target URL (snake_case variant for broken backlinks)
2960+
example: "https://example.com/destination"
2961+
urlsSuggested:
2962+
type: array
2963+
description: Array of suggested URLs
2964+
items:
2965+
type: string
2966+
sitemapUrl:
2967+
type: string
2968+
example: "https://example.com/sitemap.xml"
2969+
pageUrl:
2970+
type: string
2971+
example: "https://example.com/page"
2972+
pattern:
2973+
type: string
2974+
link:
2975+
type: string
2976+
path:
2977+
type: string
2978+
sourceUrl:
2979+
type: string
2980+
destinationUrl:
2981+
type: string
2982+
recommendations:
2983+
type: array
2984+
items:
2985+
type: object
2986+
cves:
2987+
type: array
2988+
items:
2989+
type: object
2990+
findings:
2991+
type: array
2992+
items:
2993+
type: object
2994+
form:
2995+
type: object
2996+
page:
2997+
type: object
2998+
accessibility:
2999+
type: object
3000+
metrics:
3001+
type: object
3002+
description: CWV metrics (mobileMetric, desktopMetric) for calculating totalIssues
3003+
type:
3004+
type: string
3005+
description: Type indicator (e.g., 'url' vs 'group' for CWV)
3006+
pageviews:
3007+
type: number
3008+
description: Page views count for display
3009+
issues:
3010+
type: array
3011+
description: Issues array for Accessibility, ColorContrast, FormNonExperimental (includes occurrences field)
3012+
items:
3013+
type: object
3014+
createdAt:
3015+
description: UTC timestamp of when the suggestion was created
3016+
$ref: '#/DateTime'
3017+
updatedAt:
3018+
description: UTC timestamp of when the suggestion was last updated
3019+
$ref: '#/DateTime'
3020+
required:
3021+
- id
3022+
- status
3023+
- createdAt
3024+
- updatedAt
3025+
SuggestionSummary:
3026+
type: object
3027+
description: Summary suggestion projection (superset of minimal, subset of full). Contains minimal data fields plus metadata for table displays.
3028+
properties:
3029+
id:
3030+
description: UUID of this suggestion
3031+
$ref: '#/Id'
3032+
status:
3033+
description: Status of this suggestion
3034+
$ref: '#/SuggestionStatus'
3035+
data:
3036+
type: object
3037+
description: URL-related fields from minimal view (same as SuggestionMinimal.data). Only present if any URL fields exist.
3038+
opportunityId:
3039+
description: UUID of the opportunity this suggestion belongs to
3040+
$ref: '#/Id'
3041+
type:
3042+
$ref: '#/SuggestionType'
3043+
rank:
3044+
description: Type-specific numeric rank value (e.g., "domainTraffic" for a broken-backlink) helps sorting
3045+
type: number
3046+
example: 45600
3047+
url:
3048+
description: URL associated with the suggestion (extracted from data). May be null if no URL found.
3049+
type: string
3050+
example: "https://example.com/page"
3051+
createdAt:
3052+
description: UTC timestamp of when the suggestion was created
3053+
$ref: '#/DateTime'
3054+
updatedAt:
3055+
description: UTC timestamp of when the suggestion was last updated
3056+
$ref: '#/DateTime'
3057+
updatedBy:
3058+
description: Who last updated this suggestion
3059+
type: string
3060+
example: "user@example.com"
3061+
required:
3062+
- id
3063+
- status
3064+
- opportunityId
3065+
- type
3066+
- rank
29263067
PaginationMetadata:
29273068
type: object
29283069
description: Metadata for paginated responses

docs/openapi/site-opportunities.yaml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,10 +195,27 @@ site-opportunity-suggestions:
195195
parameters:
196196
- $ref: './parameters.yaml#/siteId'
197197
- $ref: './parameters.yaml#/opportunityId'
198+
- $ref: './parameters.yaml#/suggestionView'
199+
- $ref: './parameters.yaml#/suggestionStatus'
198200
get:
199201
operationId: getSiteOpportunitySuggestions
200202
summary: |
201203
Retrieve a list of all suggestions for a specific opportunity
204+
description: |
205+
Returns all suggestions (non-paginated) with optional field projection and status filtering.
206+
207+
**Field Projection:**
208+
- `view=minimal` - Returns id, status, timestamps (createdAt, updatedAt), and URL-related data fields (lightest)
209+
- `view=summary` - Returns minimal fields plus metadata (opportunityId, type, rank, updatedBy)
210+
- `view=full` - Returns all fields including complete data object (default)
211+
212+
**Status Filtering:**
213+
- Single status: `status=NEW`
214+
- Multiple statuses: `status=NEW,APPROVED,IN_PROGRESS`
215+
- Valid values: NEW, APPROVED, SKIPPED, FIXED, ERROR, IN_PROGRESS, OUTDATED, PENDING_VALIDATION
216+
- Returns 400 Bad Request for invalid status values
217+
218+
**Note:** For paginated results, use the `/paged` endpoints. Status filtering is only available on this non-paginated endpoint or the dedicated `/by-status` endpoints.
202219
tags:
203220
- opportunity-suggestions
204221
responses:
@@ -260,10 +277,13 @@ site-opportunity-suggestions-by-status:
260277
required: true
261278
schema:
262279
type: string
280+
- $ref: './parameters.yaml#/suggestionView'
263281
get:
264282
operationId: getSiteOpportunitySuggestionsByStatus
265283
summary: |
266284
Retrieve suggestions for a specific opportunity filtered by status
285+
description: |
286+
Returns suggestions filtered by status with optional field projection using the view parameter.
267287
tags:
268288
- opportunity-suggestions
269289
responses:
@@ -293,12 +313,15 @@ site-opportunity-suggestions-paged:
293313
- $ref: './parameters.yaml#/siteId'
294314
- $ref: './parameters.yaml#/opportunityId'
295315
- $ref: './parameters.yaml#/limit'
316+
- $ref: './parameters.yaml#/suggestionView'
296317
get:
297318
operationId: getSiteOpportunitySuggestionsPaged
298319
summary: |
299320
Retrieve a paginated list of suggestions for a specific opportunity
300321
description: |
301322
Returns suggestions in pages with pagination metadata. Use the cursor from the response to fetch subsequent pages.
323+
Supports field projection using the view parameter to reduce response size.
324+
Note: For status filtering, use the non-paginated endpoint or the by-status endpoints.
302325
tags:
303326
- opportunity-suggestions
304327
responses:
@@ -329,12 +352,15 @@ site-opportunity-suggestions-paged-with-cursor:
329352
- $ref: './parameters.yaml#/opportunityId'
330353
- $ref: './parameters.yaml#/limit'
331354
- $ref: './parameters.yaml#/cursor'
355+
- $ref: './parameters.yaml#/suggestionView'
332356
get:
333357
operationId: getSiteOpportunitySuggestionsPagedWithCursor
334358
summary: |
335359
Retrieve a paginated list of suggestions for a specific opportunity using a cursor
336360
description: |
337361
Returns suggestions in pages with pagination metadata. Provide the cursor from a previous response to fetch the next page.
362+
Supports field projection using the view parameter to reduce response size.
363+
Note: For status filtering, use the non-paginated endpoint or the by-status endpoints.
338364
tags:
339365
- opportunity-suggestions
340366
responses:
@@ -369,12 +395,14 @@ site-opportunity-suggestions-by-status-paged:
369395
schema:
370396
type: string
371397
- $ref: './parameters.yaml#/limit'
398+
- $ref: './parameters.yaml#/suggestionView'
372399
get:
373400
operationId: getSiteOpportunitySuggestionsByStatusPaged
374401
summary: |
375402
Retrieve a paginated list of suggestions for a specific opportunity filtered by status
376403
description: |
377404
Returns suggestions filtered by status in pages with pagination metadata. Use the cursor from the response to fetch subsequent pages.
405+
Supports field projection using the view parameter to reduce response size.
378406
tags:
379407
- opportunity-suggestions
380408
responses:
@@ -410,12 +438,14 @@ site-opportunity-suggestions-by-status-paged-with-cursor:
410438
type: string
411439
- $ref: './parameters.yaml#/limit'
412440
- $ref: './parameters.yaml#/cursor'
441+
- $ref: './parameters.yaml#/suggestionView'
413442
get:
414443
operationId: getSiteOpportunitySuggestionsByStatusPagedWithCursor
415444
summary: |
416445
Retrieve a paginated list of suggestions for a specific opportunity filtered by status using a cursor
417446
description: |
418447
Returns suggestions filtered by status in pages with pagination metadata. Provide the cursor from a previous response to fetch the next page.
448+
Supports field projection using the view parameter to reduce response size.
419449
tags:
420450
- opportunity-suggestions
421451
responses:
@@ -520,10 +550,13 @@ site-opportunity-suggestion:
520550
- $ref: './parameters.yaml#/siteId'
521551
- $ref: './parameters.yaml#/opportunityId'
522552
- $ref: './parameters.yaml#/suggestionId'
553+
- $ref: './parameters.yaml#/suggestionView'
523554
get:
524555
operationId: getSiteOpportunitySuggestion
525556
summary: |
526557
Retrieve details of a specific suggestion
558+
description: |
559+
Returns a single suggestion with optional field projection using the view parameter.
527560
tags:
528561
- opportunity-suggestions
529562
responses:

src/controllers/fixes.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,10 @@ export class FixesController {
193193
if (res) return res;
194194

195195
const suggestions = await fix.getSuggestions();
196-
return ok(suggestions.map(SuggestionDto.toJSON));
196+
return ok(suggestions.map((s) => {
197+
const opportunity = s.getOpportunity();
198+
return SuggestionDto.toJSON(s, 'full', opportunity);
199+
}));
197200
}
198201

199202
/**

0 commit comments

Comments
 (0)