diff --git a/src/app/core/auth/guards/ed25519-auth.guard.ts b/src/app/core/auth/guards/ed25519-auth.guard.ts deleted file mode 100644 index a7e31da..0000000 --- a/src/app/core/auth/guards/ed25519-auth.guard.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { inject } from '@angular/core'; -import { CanActivateFn, Router } from '@angular/router'; -import { SessionService } from '../services/session.service'; - -/** - * Guards routes under the Ed25519 JWT flow. Not wired onto any live route - * yet (see docs/AUTH.md cutover plan) - `adminAuthGuard` - * (`core/admin-auth/admin-auth.guard.ts`) remains the active guard for - * `/backoffice` and `/edit` until the backend ships the challenge/verify - * endpoints this depends on. - */ -export const ed25519AuthGuard: CanActivateFn = () => { - const session = inject(SessionService); - const router = inject(Router); - - if (session.isAuthenticated()) { - return true; - } - - if (session.status() === 'expired') { - return router.parseUrl('/admin-login/error/session-expired'); - } - - return router.parseUrl('/admin-login'); -}; diff --git a/src/app/core/auth/guards/permission.guard.ts b/src/app/core/auth/guards/permission.guard.ts deleted file mode 100644 index bddaaa9..0000000 --- a/src/app/core/auth/guards/permission.guard.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { inject } from '@angular/core'; -import { CanActivateFn, Router } from '@angular/router'; -import { Permission } from '../models/permission.model'; -import { PermissionService } from '../services/permission.service'; -import { SessionService } from '../services/session.service'; - -/** - * Factory guard: `permissionGuard('users.manage')` in a route's - * `canActivate`. Composes with `ed25519AuthGuard` - route to this only after - * confirming authentication, since an unauthenticated user has no role and - * would otherwise always be routed to `forbidden` instead of the login page. - */ -export function permissionGuard(required: Permission): CanActivateFn { - return () => { - const session = inject(SessionService); - const permissions = inject(PermissionService); - const router = inject(Router); - - if (!session.isAuthenticated()) { - return router.parseUrl('/admin-login'); - } - - return permissions.has(required) ? true : router.parseUrl('/admin-login/error/forbidden'); - }; -} diff --git a/src/app/core/auth/interceptors/auth.interceptor.ts b/src/app/core/auth/interceptors/auth.interceptor.ts deleted file mode 100644 index b99e204..0000000 --- a/src/app/core/auth/interceptors/auth.interceptor.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { HttpErrorResponse, HttpInterceptorFn } from '@angular/common/http'; -import { inject } from '@angular/core'; -import { Router } from '@angular/router'; -import { catchError, switchMap, throwError } from 'rxjs'; -import { SessionService } from '../services/session.service'; -import { AuthService } from '../services/auth.service'; - -/** Paths gated by the Ed25519 JWT once it is the live admin auth mechanism. Kept identical to adminAuthHeadersInterceptor's list for consistency. */ -const ADMIN_GATED_PATH_SEGMENTS = ['/admin/', '/backoffice/', '/builder/', '/media/']; - -/** - * Attaches `Authorization: Bearer ` to admin API requests and, on a 401, - * attempts a single silent refresh-then-retry before giving up and routing - * to the session-expired screen. Not registered in app.config.ts yet - this - * activates once the Ed25519 flow replaces (or runs alongside) - * adminAuthHeadersInterceptor; see docs/AUTH.md for the cutover plan. - */ -export const authInterceptor: HttpInterceptorFn = (req, next) => { - const isAdminRequest = ADMIN_GATED_PATH_SEGMENTS.some(segment => req.url.includes(segment)); - if (!isAdminRequest) { - return next(req); - } - - const session = inject(SessionService); - const auth = inject(AuthService); - const router = inject(Router); - - const token = session.token(); - const authedReq = token ? req.clone({ headers: req.headers.set('Authorization', `Bearer ${token}`) }) : req; - - return next(authedReq).pipe( - catchError((error: unknown) => { - if (!(error instanceof HttpErrorResponse) || error.status !== 401 || !session.getRefreshToken()) { - return throwError(() => error); - } - - return auth.refresh().pipe( - switchMap(refreshed => next(req.clone({ headers: req.headers.set('Authorization', `Bearer ${refreshed.token}`) }))), - catchError(refreshError => { - router.navigate(['/admin-login/error', 'session-expired']); - return throwError(() => refreshError); - }) - ); - }) - ); -}; diff --git a/src/app/features/backoffice/categories/.gitkeep b/src/app/features/backoffice/categories/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/features/backoffice/customers/.gitkeep b/src/app/features/backoffice/customers/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/features/backoffice/inventory/.gitkeep b/src/app/features/backoffice/inventory/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/features/backoffice/orders/.gitkeep b/src/app/features/backoffice/orders/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/features/backoffice/products/.gitkeep b/src/app/features/backoffice/products/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/features/backoffice/settings/.gitkeep b/src/app/features/backoffice/settings/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/features/backoffice/shared/backoffice-coming-soon-page.component.html b/src/app/features/backoffice/shared/backoffice-coming-soon-page.component.html deleted file mode 100644 index c2f9d4a..0000000 --- a/src/app/features/backoffice/shared/backoffice-coming-soon-page.component.html +++ /dev/null @@ -1,5 +0,0 @@ -
-

{{ titleKey | translate }}

-

{{ 'dashboard.comingSoonDescription' | translate }}

- {{ 'dashboard.backToDashboard' | translate }} -
diff --git a/src/app/features/backoffice/shared/backoffice-coming-soon-page.component.scss b/src/app/features/backoffice/shared/backoffice-coming-soon-page.component.scss deleted file mode 100644 index 699a5a6..0000000 --- a/src/app/features/backoffice/shared/backoffice-coming-soon-page.component.scss +++ /dev/null @@ -1,32 +0,0 @@ -.coming-soon { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 12px; - max-width: 640px; - margin: 40px auto; - padding: 24px; - text-align: left; -} - -.coming-soon__title { - margin: 0; - font-size: var(--font-size-3xl, 1.5rem); - font-weight: 800; - color: var(--text-primary, #1e3c38); -} - -.coming-soon__description { - margin: 0; - color: var(--text-secondary, #667a77); -} - -.coming-soon__link { - color: var(--primary-color, #497671); - font-weight: var(--font-weight-semibold, 600); - text-decoration: none; -} - -.coming-soon__link:hover { - text-decoration: underline; -} diff --git a/src/app/features/backoffice/shared/backoffice-coming-soon-page.component.ts b/src/app/features/backoffice/shared/backoffice-coming-soon-page.component.ts deleted file mode 100644 index c4e6eb4..0000000 --- a/src/app/features/backoffice/shared/backoffice-coming-soon-page.component.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; -import { CommonModule } from '@angular/common'; -import { ActivatedRoute, RouterLink } from '@angular/router'; -import { TranslatePipe } from '../../../i18n/translate.pipe'; - -/** Landing page for backoffice sections not built yet (categories, static pages, transactions, orders, media). Route `data.titleKey` sets the section name; falls back to the generic "coming soon" title. */ -@Component({ - selector: 'app-backoffice-coming-soon-page', - standalone: true, - imports: [CommonModule, RouterLink, TranslatePipe], - templateUrl: './backoffice-coming-soon-page.component.html', - styleUrls: ['./backoffice-coming-soon-page.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class BackofficeComingSoonPageComponent { - private readonly route = inject(ActivatedRoute); - - readonly titleKey: string = this.route.snapshot.data['titleKey'] ?? 'dashboard.comingSoonTitle'; -} diff --git a/src/app/features/content-management/pages/content-management-page.component.ts b/src/app/features/content-management/pages/content-management-page.component.ts deleted file mode 100644 index a9ac125..0000000 --- a/src/app/features/content-management/pages/content-management-page.component.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { StaticPagesEditorComponent } from '../components/static-pages-editor.component'; - -@Component({ - selector: 'app-content-management-page', - standalone: true, - imports: [StaticPagesEditorComponent], - template: ``, - changeDetection: ChangeDetectionStrategy.OnPush -}) -export class ContentManagementPageComponent {} diff --git a/src/app/features/search/components/empty-results/search-empty-results.component.html b/src/app/features/search/components/empty-results/search-empty-results.component.html deleted file mode 100644 index ea90ce2..0000000 --- a/src/app/features/search/components/empty-results/search-empty-results.component.html +++ /dev/null @@ -1,44 +0,0 @@ -
-

{{ 'search.noResults' | translate }}

- - - - @if (popularCategories.length > 0) { -
- {{ 'search.popularCategories' | translate }} -
- @for (category of popularCategories; track category.id) { - - } -
-
- } - - @if (popularSearches.length > 0) { -
- {{ 'catalog.popularSearchesTitle' | translate }} -
- @for (item of popularSearches; track $index) { - - } -
-
- } - - @if (recommendedProducts.length > 0) { -
- {{ 'search.recommendedProducts' | translate }} -
- @for (product of recommendedProducts; track product.itemID) { - - } -
-
- } -
diff --git a/src/app/features/search/components/empty-results/search-empty-results.component.scss b/src/app/features/search/components/empty-results/search-empty-results.component.scss deleted file mode 100644 index 26c15ab..0000000 --- a/src/app/features/search/components/empty-results/search-empty-results.component.scss +++ /dev/null @@ -1,48 +0,0 @@ -.search-empty-results { - display: grid; - gap: 14px; - padding: 16px; -} - -h3 { - margin: 0; -} - -.reset-btn { - justify-self: start; - min-height: 40px; - border: 1px solid var(--border-color); - border-radius: var(--radius-sm); - background: var(--bg-primary); - color: var(--text-primary); - padding: 0 14px; - cursor: pointer; - font-weight: var(--font-weight-bold, 700); -} - -.block { - display: grid; - gap: 8px; -} - -.chip-list { - display: flex; - flex-wrap: wrap; - gap: 8px; -} - -.chip { - min-height: 36px; - border: 1px solid var(--border-color); - border-radius: var(--radius-full, 999px); - background: var(--bg-primary); - color: var(--text-secondary); - padding: 0 12px; - cursor: pointer; -} - -.product-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); - gap: 10px; -} diff --git a/src/app/features/search/components/empty-results/search-empty-results.component.ts b/src/app/features/search/components/empty-results/search-empty-results.component.ts deleted file mode 100644 index 60f7921..0000000 --- a/src/app/features/search/components/empty-results/search-empty-results.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; -import { Product } from '../../../../core/products/models/product-domain.model'; -import { ProductCardComponent } from '../../../../components/product-card/product-card.component'; -import { TranslatePipe } from '../../../../i18n/translate.pipe'; - -@Component({ - selector: 'app-search-empty-results', - standalone: true, - imports: [ProductCardComponent, TranslatePipe], - templateUrl: './search-empty-results.component.html', - styleUrls: ['./search-empty-results.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush -}) -export class SearchEmptyResultsComponent { - @Input() popularCategories: Array<{ id: string | number; label: string }> = []; - @Input() popularSearches: string[] = []; - @Input() recommendedProducts: Product[] = []; - - @Output() resetFilters = new EventEmitter(); - @Output() popularCategorySelected = new EventEmitter(); - @Output() popularSearchSelected = new EventEmitter(); - @Output() productSelected = new EventEmitter(); - @Output() productAddToCart = new EventEmitter<{ product: Product; event: Event }>(); -} diff --git a/src/app/features/search/services/search-analytics.service.ts b/src/app/features/search/services/search-analytics.service.ts deleted file mode 100644 index 1903ba1..0000000 --- a/src/app/features/search/services/search-analytics.service.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Injectable } from '@angular/core'; -import { SearchAnalyticsEvent } from '../models/search.model'; - -@Injectable({ providedIn: 'root' }) -export class SearchAnalyticsService { - buildEvent(input: { - query: string; - tenant: string; - language: string; - resultCount: number; - timestamp?: string; - }): SearchAnalyticsEvent { - return { - query: input.query, - tenant: input.tenant, - language: input.language, - timestamp: input.timestamp ?? new Date().toISOString(), - resultCount: input.resultCount, - }; - } -} diff --git a/src/app/pages/public/platform-home.component.ts b/src/app/pages/public/platform-home.component.ts deleted file mode 100644 index d8e2d51..0000000 --- a/src/app/pages/public/platform-home.component.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core'; -import { Router } from '@angular/router'; -import { DynamicPageLayoutComponent } from '../../layouts/containers/dynamic-page-layout.component'; -import { PageRenderModel } from '../../dynamic-renderer/page-renderer/page-renderer.model'; -import { WebsiteRuntimeFacade } from '../../facades/website/website-runtime.facade'; -import { TranslatePipe } from '../../i18n/translate.pipe'; - -@Component({ - selector: 'app-platform-home', - standalone: true, - imports: [DynamicPageLayoutComponent, TranslatePipe], - template: ` - @if (loading()) { -
-
{{ 'platform.loadingPage' | translate }}
-
- } @else if (model()) { - - } @else { -
-
{{ 'platform.emptyConfig' | translate }}
-
- } - `, - styles: [ - ` - .platform-loading, .platform-empty { padding: 2rem; color: var(--text-secondary, #667a77); } - ` - ], - changeDetection: ChangeDetectionStrategy.OnPush -}) -export class PlatformHomeComponent { - readonly model = signal(null); - readonly loading = signal(true); - private readonly router = inject(Router); - - constructor(private readonly websiteRuntime: WebsiteRuntimeFacade) { - this.websiteRuntime.getPageRenderModelForUrl(this.router.url).subscribe({ - next: (model) => { - this.model.set(model); - this.loading.set(false); - }, - error: () => { - this.model.set(null); - this.loading.set(false); - } - }); - } -} diff --git a/src/app/shared/index.ts b/src/app/shared/index.ts deleted file mode 100644 index 9723bff..0000000 --- a/src/app/shared/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './models'; -export * from './types'; diff --git a/src/app/shared/models/domain/.gitkeep b/src/app/shared/models/domain/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/app/shared/models/domain/index.ts b/src/app/shared/models/domain/index.ts deleted file mode 100644 index cc6c09f..0000000 --- a/src/app/shared/models/domain/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './user-preferences.model'; diff --git a/src/app/shared/models/domain/user-preferences.model.ts b/src/app/shared/models/domain/user-preferences.model.ts deleted file mode 100644 index 4a4aba2..0000000 --- a/src/app/shared/models/domain/user-preferences.model.ts +++ /dev/null @@ -1,8 +0,0 @@ -export interface UserPreferences { - locale: string; - currency: string; - themeMode: 'light' | 'dark' | 'system'; - compactMode?: boolean; - wishlistEnabled?: boolean; - notificationsEnabled?: boolean; -} diff --git a/src/app/shared/models/index.ts b/src/app/shared/models/index.ts deleted file mode 100644 index 3e3515e..0000000 --- a/src/app/shared/models/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * as ConfigModels from './config'; -export * as DomainModels from './domain'; -export * as UiModels from './ui'; diff --git a/src/app/shared/types/index.ts b/src/app/shared/types/index.ts deleted file mode 100644 index 3a4c267..0000000 --- a/src/app/shared/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './primitive.types'; diff --git a/src/assets/mock/backoffice/customers/list.json b/src/assets/mock/backoffice/customers/list.json deleted file mode 100644 index fe51488..0000000 --- a/src/assets/mock/backoffice/customers/list.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/src/assets/mock/backoffice/orders/list.json b/src/assets/mock/backoffice/orders/list.json deleted file mode 100644 index fe51488..0000000 --- a/src/assets/mock/backoffice/orders/list.json +++ /dev/null @@ -1 +0,0 @@ -[]