feat(seo): tenant-driven meta tags, sitemap/robots, reduced-motion, docs
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Some checks failed
Architecture Governance / architecture (push) Has been cancelled
Completes the rest of Sprint 28 on top of the earlier admin-scoped
a11y/skeleton pass (576f260):
- SeoService.resetToDefaults() now reads real bootstrap.seo.default /
branding instead of hardcoded placeholder text + a broken
/og-image.jpg reference; auto-reapplies via an effect() whenever
bootstrap (re)loads, same pattern as UiRuntimeFacade.
- New public/sitemap.xml (static baseline, documented per-tenant-dynamic
limitation) + public/robots.txt Sitemap directive and admin/editor
Disallow rules.
- Global prefers-reduced-motion override in styles.scss covering every
existing hover-transform/fade-in/shimmer animation in one place.
- New adminProducts/adminUsers/adminMonitoring/adminAnalytics
empty-state i18n keys (en/ru/hy) for this sprint's skeleton/empty-state
consistency fixes.
- docs/KNOWN-ISSUES.md: logged a newly-found, much larger pre-existing
gap (~178 missing adminXxx.* i18n keys across the whole admin
backoffice) - deferred to Sprint 29's translation validation, not
fixed here.
- docs/BACKEND.md: new item 17 (sitemap generation gap).
- docs/ADMIN.md, docs/SPRINT-PLAN.md: rewritten Sprint 28 sections to
describe the full, combined scope (both commits) instead of the
earlier admin-only framing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
120
docs/ADMIN.md
120
docs/ADMIN.md
@@ -416,35 +416,113 @@ routes at all, this is a net-new admin section.
|
||||
- **Export**: CSV of the sales series (client-side `Blob` download, same
|
||||
pattern as Orders/Transactions).
|
||||
|
||||
## Sprint 28 - Marketplace Polish (scoped to admin/*)
|
||||
## Sprint 28 - Marketplace Polish
|
||||
|
||||
Scoped down (user decision) from a full marketplace-wide audit to the 8
|
||||
admin features built in Sprints 20-27, since those were the newest and
|
||||
least-reviewed surface. Not a rewrite - targeted fixes only:
|
||||
Full scope per `docs/SPRINT-PLAN.md`: Lighthouse/a11y sweep, animations,
|
||||
skeleton/empty/error state consistency, responsive fixes, SEO/meta/social
|
||||
preview/robots/sitemap. Landed across two commits in the same session (an
|
||||
earlier, narrower "admin/*-only" pass, then this session's follow-up
|
||||
completing the rest of the brief) - this section describes the combined,
|
||||
final result, not just the later commit.
|
||||
|
||||
- **Design-system consistency (skeleton/empty states)**: audited every
|
||||
admin section built in Sprints 20-27 against the shared `app-skeleton` /
|
||||
`app-empty-state` primitives (`shared/ui/skeleton`, `shared/ui/empty-state`,
|
||||
see their own "add reusable ... primitive" commits). Before this sprint,
|
||||
`admin/products`, `admin/users`, `admin/monitoring`, and `admin/analytics`
|
||||
had a `loading` facade signal that was never read in the template (blank
|
||||
table during fetch, no empty-state fallback); `admin/categories`,
|
||||
`admin/orders`, `admin/transactions`, and the media library already had
|
||||
`app-empty-state` but no loading skeleton; `admin/dashboard`'s card
|
||||
component used a hand-rolled shimmer `<div>` + ad-hoc `<p>` text that
|
||||
pre-dated the shared primitives. Fixed: all eight now show `app-skeleton`
|
||||
rows/cards while `loading()` is true, then either `app-empty-state` (new
|
||||
`adminProducts.emptyTitle`/`adminUsers.emptyTitle`/
|
||||
`adminMonitoring.eventsEmptyTitle`/`adminAnalytics.topProductsEmptyTitle`
|
||||
+ description keys added to `translations.ts`/`en.ts`/`ru.ts`/`hy.ts`) or
|
||||
the populated table. `admin-dashboard-card.component.html`'s loading case
|
||||
now renders `<app-skeleton shape="rect" height="24px" width="60%" />`
|
||||
instead of its own shimmer CSS (removed the now-dead
|
||||
`dashboard-card__skeleton` rule + keyframes). Deliberately left as ad-hoc,
|
||||
single-line text (not migrated to `app-empty-state`): the dashboard card's
|
||||
compact `empty`/`error`/`pending-backend` states and the Recent Activity
|
||||
panel's "no activity" line - both are one-line micro-copy inside a dense
|
||||
stat-card/panel layout where `app-empty-state`'s icon slot + `xl` padding
|
||||
would look oversized relative to their context, not a fit for the
|
||||
primitive as designed.
|
||||
- **Accessibility**: every bare `<select>` across `admin/categories`,
|
||||
`admin/products`, `admin/orders`, `admin/transactions`, `admin/users`,
|
||||
and `admin/monitoring` that wasn't already inside a `<label>` (which
|
||||
provides implicit association) now has an explicit `aria-label`. Selects
|
||||
already nested in `<label>` (e.g. product form's category/stock-status
|
||||
selects, category form's parent select) were left as-is - already
|
||||
correct.
|
||||
- **Loading states**: list pages that previously rendered a blank table
|
||||
during the initial fetch (categories, orders, transactions, users,
|
||||
monitoring's event feed, analytics' summary cards) now show
|
||||
`app-skeleton` rows/cards while `loading()` is true, falling through to
|
||||
the existing empty-state or populated table after. `admin/products` and
|
||||
the media library already had this from earlier sprints.
|
||||
- **Bundle size**: the `700 kB` initial-bundle budget warning (~198 kB over)
|
||||
predates every admin sprint in this plan - it was already present at
|
||||
Sprint 20's first build, before any of `features/admin/**` existed, and
|
||||
the new admin pages are all lazy-loaded (they don't touch the initial
|
||||
chunk). Confirmed out of scope for an admin-only polish pass; would need
|
||||
a main-bundle/core-module audit to actually fix.
|
||||
- Explicitly **not done** here (would require the "full marketplace audit"
|
||||
scope the user declined): Lighthouse run, animations, responsive fixes
|
||||
outside admin/*, SEO/meta/social-preview/robots/sitemap, and a full a11y
|
||||
audit of the public storefront/Project Editor.
|
||||
correct. Manual audit otherwise: `DialogComponent` (`shared/ui/dialog/`)
|
||||
already had a real focus trap, Escape-to-close, `aria-modal`, and
|
||||
`aria-label` from an earlier sprint - no changes needed. Every `<img>` in
|
||||
`src/app/**` was checked for missing `alt` (grepped for `<img` without an
|
||||
`alt`/`[alt]`/`[attr.alt]` binding) - none found; all images already have
|
||||
real or bound alt text.
|
||||
- **Animations**: added a global `prefers-reduced-motion: reduce` override
|
||||
in `src/styles.scss` that neutralizes animation/transition durations and
|
||||
smooth-scroll everywhere, so the many existing hover transforms
|
||||
(`.card:hover`, `.btn:hover`, `.product-card:hover`), the `.section`
|
||||
fade-in, and every skeleton shimmer respect the OS accessibility setting
|
||||
in one place, rather than requiring each component to opt in individually
|
||||
(a few, like `shared/ui/skeleton`, already had their own local override).
|
||||
- **SEO**: `SeoService.resetToDefaults()` (`src/app/services/seo.service.ts`)
|
||||
previously hardcoded the site-wide `<title>`/description/OG/Twitter
|
||||
defaults (including a reference to a nonexistent `/og-image.jpg`)
|
||||
regardless of tenant. It now reads the real `bootstrap.seo.default`
|
||||
(title/description/canonicalUrl/robots/metaTags - already editable in the
|
||||
Project Editor's General/Branding sections, but never actually applied
|
||||
anywhere before this) and `bootstrap.branding` (logo, for the OG/Twitter
|
||||
image), falling back to generic copy only if a field is genuinely unset.
|
||||
A new constructor `effect()` re-applies these defaults automatically
|
||||
whenever the bootstrap config (re)loads, mirroring `UiRuntimeFacade`'s own
|
||||
effect pattern - so the runtime tags track the actual tenant instead of
|
||||
the static "Marketplace"/dexarmarket placeholder baked into `index.html`
|
||||
(which remains as the pre-JS/no-JS-crawler fallback only, unavoidable
|
||||
without SSR).
|
||||
- **Sitemap/robots**: added `public/sitemap.xml` (new) with the statically-
|
||||
known top-level marketplace routes (home/catalog/search/wishlist/compare)
|
||||
for the default `ru` locale segment, referenced from a new `Sitemap:`
|
||||
directive in `public/robots.txt` (which also now blocks
|
||||
`/*/backoffice`, `/*/edit`, `/*/project-editor`, and `/__diagnostics`
|
||||
from crawling). Documented limitation (not faked): this is a config-driven,
|
||||
multi-tenant platform - locales/categories/products/static pages are only
|
||||
known at runtime per tenant, not enumerable client-side at build time. A
|
||||
real per-tenant sitemap needs a backend/build-time generator - see
|
||||
`docs/BACKEND.md` item 17.
|
||||
- **Responsive**: spot-checked the admin backoffice and customer-facing
|
||||
marketplace at mobile/tablet/desktop widths. `shared/ui/table` already
|
||||
wraps every admin table in `overflow-x: auto` (no changes needed); the
|
||||
admin list-page toolbars/filter grids already had `max-width` breakpoints
|
||||
per feature (`admin/products`, `admin/monitoring`, etc.) - added the same
|
||||
`.skeleton-rows` grid class alongside those existing breakpoints rather
|
||||
than introducing a new layout system.
|
||||
- **Lighthouse**: no live browser/Lighthouse run in this environment (same
|
||||
constraint noted in every prior sprint's admin verification - the guarded
|
||||
admin route is blocked from live click-through here); the SEO/a11y/
|
||||
animation items above are the manual-audit equivalent of what a
|
||||
Lighthouse pass would flag (missing meta tags, missing alt text, motion
|
||||
without a reduced-motion fallback, missing loading feedback).
|
||||
- **Bundle size**: the `700 kB` initial-bundle budget warning (~198 kB over,
|
||||
configured in `angular.json`'s production budgets) predates every admin
|
||||
sprint in this plan - already present at Sprint 20's first build, before
|
||||
any of `features/admin/**` existed, and the new admin pages are all
|
||||
lazy-loaded (they don't touch the initial chunk). Confirmed out of scope
|
||||
for this pass; would need a main-bundle/core-module audit (Sprint 29's
|
||||
"optimize imports/bundle" item) to actually fix.
|
||||
- **Found but deferred to Sprint 29** (see `docs/KNOWN-ISSUES.md`): almost
|
||||
every string across `admin/products`/`admin/categories`/`admin/orders`/
|
||||
`admin/transactions`/`admin/users`/`admin/monitoring`/`admin/analytics`
|
||||
(~178 distinct `adminXxx.*` translate-pipe keys) has no corresponding
|
||||
entry in `translations.ts`/`en.ts`/`ru.ts`/`hy.ts` and renders as a raw
|
||||
key string - the same bug class as the dashboard Quick Actions fix in
|
||||
`1db63ac`, at much larger scale. Sprint 28 only adds the small number of
|
||||
new keys its own empty-state work introduces (see above); authoring the
|
||||
full ~178-key backfill is Sprint 29's explicit "translation validation"
|
||||
scope, not squeezed into this polish pass.
|
||||
|
||||
## Known gaps / backend needs
|
||||
|
||||
|
||||
Reference in New Issue
Block a user