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:
sdarbinyan
2026-08-17 23:53:24 +04:00
parent 6ac52b1c50
commit 475d75781f
4 changed files with 52 additions and 0 deletions

View 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';
}

View File

@@ -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[]>;
}

View 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),
});

View 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([]);
}
}