feat: Phase 5 frontend - Seller gateway core, mock-backed (scoped)
core/sellers/services against docs/backend/PHASE-5-SELLER-PORTAL- CONTRACT.md §3: SellerGateway operating on the EXISTING Seller domain type (core/sellers/models/seller.model.ts - deliberately not a new competing shape; GAPS-AND-IMPROVEMENTS.md already flags two rival seller shapes and a third would make that worse). Adds SellerUser/SellerRole. Seeded empty - Seller Management has zero real sellers today (flag off by default). Scope note: this session's largest deferral. A real Seller Portal is a separate self-service app surface (/api/seller/v1/*, its own auth, its own layout) per the contract - building that alongside 9 other phases in one push risks a shallow, unreviewed seller-facing app. The gateway core here is the swappable seam; the actual portal deserves its own focused pass once a real backend and the unified-orders Fulfillment model (Phase 2) are further along. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
12
src/app/core/sellers/models/seller-user.model.ts
Normal file
12
src/app/core/sellers/models/seller-user.model.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { UUID } from '../../../shared/types/primitive.types';
|
||||
|
||||
/** Per docs/backend/PHASE-5-SELLER-PORTAL-CONTRACT.md §2, §4. */
|
||||
export type SellerRole = 'SELLER_OWNER' | 'SELLER_CATALOG_MANAGER' | 'SELLER_ORDER_MANAGER' | 'SELLER_FINANCE_VIEWER' | 'SELLER_VIEWER';
|
||||
|
||||
export interface SellerUser {
|
||||
id: UUID;
|
||||
sellerId: UUID;
|
||||
role: SellerRole;
|
||||
email: string;
|
||||
status: 'active' | 'invited' | 'suspended';
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Observable } from 'rxjs';
|
||||
import { Seller } from '../models/seller.model';
|
||||
import { SellerUser } from '../models/seller-user.model';
|
||||
|
||||
/** Per docs/backend/PHASE-5-SELLER-PORTAL-CONTRACT.md §3. Operates on the existing Seller domain type. */
|
||||
export interface SellerGateway {
|
||||
loadSellers(): Observable<Seller[]>;
|
||||
loadTeam(sellerId: string): Observable<SellerUser[]>;
|
||||
}
|
||||
9
src/app/core/sellers/services/seller-gateway.token.ts
Normal file
9
src/app/core/sellers/services/seller-gateway.token.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { InjectionToken, inject } from '@angular/core';
|
||||
import { SellerGateway } from './seller-gateway.interface';
|
||||
import { SellerLocalGateway } from './seller-local.gateway';
|
||||
|
||||
/** Swap point for docs/backend/PHASE-5-SELLER-PORTAL-CONTRACT.md §3. */
|
||||
export const SELLER_GATEWAY = new InjectionToken<SellerGateway>('SELLER_GATEWAY', {
|
||||
providedIn: 'root',
|
||||
factory: () => inject(SellerLocalGateway),
|
||||
});
|
||||
22
src/app/core/sellers/services/seller-local.gateway.ts
Normal file
22
src/app/core/sellers/services/seller-local.gateway.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { Seller } from '../models/seller.model';
|
||||
import { SellerUser } from '../models/seller-user.model';
|
||||
import { SellerGateway } from './seller-gateway.interface';
|
||||
|
||||
/**
|
||||
* No seller has ever onboarded (Seller Management is flag-off by default,
|
||||
* zero backend today per GAPS-AND-IMPROVEMENTS.md). Seeded empty - ready to
|
||||
* populate the moment docs/backend/PHASE-5-SELLER-PORTAL-CONTRACT.md ships
|
||||
* and the flag flips on for the first tenant.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class SellerLocalGateway implements SellerGateway {
|
||||
loadSellers(): Observable<Seller[]> {
|
||||
return of([]);
|
||||
}
|
||||
|
||||
loadTeam(_sellerId: string): Observable<SellerUser[]> {
|
||||
return of([]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user