PRD: Frontend Design Improvement Initiative
Status: Draft Author: Product & Engineering Date: 2026-03-17 Version: 1.0
1. Context & Why Now
Market & User Context
- Den Hartog ZE-ERE is the primary ERE (Emissie Reductie Eenheden) administration portal for EV charging certificates in the Netherlands. The portal serves both B2C (particulier) and B2B (bedrijf) users who manage renewable energy certificates for their charging infrastructure.
- The frontend was built function-first: every feature works, but visual polish and UX consistency took a back seat to shipping capabilities. The overall design quality scores 6.4/10 across ~70 pages analyzed by 6 independent review agents.
- The admin team uses the portal daily for verification workflows. As the user base grows, admin efficiency directly impacts processing throughput and revenue realization.
- The Capacitor mobile app (iOS + Android) wraps the same SPA, meaning every improvement benefits three platforms simultaneously.
Why Now
- Auth page first impression: Every new user lands on Login or Register. These pages score 3-5/10 for distinctiveness -- plain gray backgrounds, no brand atmosphere. This is the single highest-leverage conversion touchpoint.
- Admin efficiency ceiling: No bulk actions, no dashboard charts, poor mobile table responsiveness. The admin team is growing and hitting workflow bottlenecks that design improvements can solve without backend changes.
- Design system maturity: Tailwind v4 @theme tokens, a Button component, Modal with focus trap, BentoCard system, AnimateOnScroll, and Recharts are all already installed and partially used. The foundation exists; it needs consistent application.
- Cost of delay: Every week without auth page polish means continued friction at the acquisition funnel entry point. Every week without bulk admin actions means linear admin team scaling instead of leveraged scaling.
2. Users & Jobs-to-Be-Done
Persona 1: Nieuwe Gebruiker (New User -- Particulier or Bedrijf)
Description: First-time visitor arriving from the landing page, WordPress site, or referral link. Evaluating whether to register.
JTBD: "When I arrive at the login or registration page, I want to see a professional, trustworthy portal that matches the quality of the landing page, so I can feel confident entrusting my energy certificate administration to this company."
Current alternative: The landing page (8/10) sets an expectation that auth pages (3-5/10) fail to meet. The visual cliff between landing and login erodes trust.
Persona 2: Actieve Gebruiker (Active User -- Particulier or Bedrijf)
Description: Registered user who uploads documents, manages charging points, submits kWh records, and tracks ERE claims. Returns monthly or quarterly.
JTBD: "When I need to upload documents or check my dashboard, I want to complete my tasks quickly with clear feedback, so I can get back to my day without frustration."
Current alternative: File uploads use basic <input type="file"> without drag-and-drop. Dashboard shows only numbers without trend context. Document lists lack search.
Persona 3: Admin Medewerker (Admin Team Member)
Description: Den Hartog employee who verifies documents, reviews kWh records, manages authorizations, and handles user support. Uses the portal all day, every day.
JTBD: "When I have 50 pending verifications to process, I want to select multiple items and act on them in bulk, and see my progress on a dashboard with charts, so I can work efficiently and report on trends."
Current alternative: Each verification requires individual page navigation. Dashboard is numbers-only with no sparklines or trend charts despite Recharts being installed. Tables don't collapse on mobile, preventing field work.
Persona 4: Organisatie Eigenaar (Organization Owner -- Bedrijf)
Description: Business user managing a holding structure with subsidiaries, multiple EAN codes, and team members.
JTBD: "When I manage my holding company's charging infrastructure, I want to see the organizational hierarchy visually and navigate between subsidiaries intuitively, so I can oversee the entire portfolio."
Current alternative: Holding structure is a flat list. No tree/org-chart visualization. Deep navigation has no breadcrumbs.
3. Business Goals & Success Metrics
Leading Indicators (move within days/weeks)
| Metric | Current Baseline | Target | Timeframe |
|---|---|---|---|
| Login page bounce rate | [Assumption: ~15-20% based on industry avg for plain auth pages] | <10% | 4 weeks post Phase 1 |
| Registration completion rate | [Assumption: ~60-70%] | +15% relative improvement | 6 weeks post Phase 1 |
| Avg time to upload a document | [Assumption: ~45s with file picker] | <20s with drag-and-drop | 2 weeks post Phase 2 |
| Admin actions per hour (verifications) | [Assumption: ~12-15 per hour per admin] | +40% with bulk actions | 4 weeks post Phase 3 |
Lagging Indicators (business outcomes)
| Metric | Current Baseline | Target | Timeframe |
|---|---|---|---|
| Onboarding funnel completion | [Measured via AdminAnalyticsPage] | +10% relative improvement | 3 months |
| Monthly active user retention (30-day) | [Assumption: ~65-70%] | >80% | 6 months |
| Admin team satisfaction (internal survey) | [Assumption: not measured] | >4.0/5.0 | After Phase 3 |
| Support tickets related to "how do I upload?" | [Assumption: exists] | -50% | After Phase 2 |
4. Functional Requirements
Phase 1: First Impression & Design Foundation
FR-1: Auth Page Visual Upgrade
- Description: Redesign Login, Register, ForgotPassword, and ResetPassword pages to match the landing page quality (8/10). Replace plain
bg-gray-50backgrounds with branded atmospheric design using existing navy/green theme tokens. Add subtle background elements (gradient, pattern, or illustration) and ensure the card floats visually. - Acceptance Criteria:
- All four auth pages use a shared
AuthLayoutcomponent with branded background (navy gradient or split layout) - Logo is prominently displayed with consistent sizing (h-20 as current)
- Background uses existing @theme tokens (--color-navy, --color-primary-*) instead of hardcoded grays
- Card uses
.cardor.bento-cardsystem with elevation (shadow-lg or higher) - Visual design matches landing page quality level (subjective review by 2+ stakeholders)
- All pages remain fully functional on mobile (min-width: 320px)
- Capacitor mobile build renders correctly (safe area insets respected)
- Page load performance: LCP < 1.5s (no heavy image assets)
- All four auth pages use a shared
- Priority: P0
FR-2: Password Strength Indicator on ResetPassword
- Description: The Register page has a
PasswordRequirementscomponent showing live validation. The ResetPassword page lacks this, creating an inconsistent experience where users don't know if their new password meets requirements until form submission. - Acceptance Criteria:
-
PasswordRequirementscomponent is rendered on ResetPassword page below the password field - Component shows the same criteria as the Register page
- Confirm password match is validated live (if confirm field exists on ResetPassword)
-
- Priority: P1
FR-3: Color Token Consolidation
- Description: Several pages use hardcoded Tailwind colors (
green-600,red-50,blue-100) instead of the semantic design tokens defined in@theme(primary-600,danger-50,success-100). This creates visual inconsistency and makes future theme changes expensive. - Acceptance Criteria:
- Audit identifies all hardcoded color references that should use @theme tokens
- StatusBadge component uses semantic tokens:
success-100/success-700for positive states,warning-*for pending,danger-*for negative,gray-*for neutral - No page uses
green-600/green-700whereprimary-600/primary-700is semantically correct - No page uses
red-50/red-100wheredanger-50is semantically correct - Visual diff confirms no unintended color changes
- Priority: P1
FR-4: Icon Sizing Standardization
- Description: Icons use a mix of
h-4 w-4,h-5 w-5, andh-6 w-6with no clear pattern tied to context. Define and apply a consistent sizing convention. - Acceptance Criteria:
- Documented convention: inline text icons =
h-4 w-4, card/section header icons =h-5 w-5, hero/empty state icons =h-8 w-8orh-12 w-12 - All
lucide-reacticon usages reviewed and corrected where they deviate from convention - StatusBadge icon sizes remain consistent with badge size prop (sm:
h-3 w-3, md:h-3.5 w-3.5)
- Documented convention: inline text icons =
- Priority: P2
FR-5: Button Component Adoption
- Description: The codebase has a
Buttoncomponent (components/common/Button.tsx) with 6 variants and loading state, but many pages still use raw<button className="btn btn-primary">. Migrate to the component for consistency and to reduce inline Tailwind duplication. - Acceptance Criteria:
- All new code in this initiative uses the
Buttoncomponent exclusively - Existing pages touched by other FRs in this phase are migrated to
Buttoncomponent - Raw
.btnclass usage is not increased by this initiative
- All new code in this initiative uses the
- Priority: P2
Phase 2: Core UX Improvements
FR-6: Drag-and-Drop File Upload Component
- Description: Create a reusable
FileDropZonecomponent that wraps file upload interactions. The DocumentsPage already has drag-and-drop event handling at the card level; this FR extracts it into a dedicated component and adds visual feedback (border highlight, icon animation, file type validation preview). - Acceptance Criteria:
-
FileDropZonecomponent supports: single file, multiple files, accepted MIME types, max file size - Visual states: idle (dashed border), hover/dragover (primary-colored border, background tint), uploading (progress indication), error (red border + message)
- Clicking the zone opens the native file picker
- Displays accepted file types to the user (e.g., "PDF, JPG, PNG")
- Shows file name and size after selection, before upload begins
- Integrated into: DocumentsPage, OnboardingDocuments, ProfilePage (avatar upload), KwhBulkImportPage
- Works on touch devices (Capacitor mobile) -- fallback to tap-to-select
- Preserves existing upload API calls unchanged (component is purely presentational + event handling)
-
- Priority: P0
FR-7: User Dashboard Charts
- Description: Add trend visualization to the user DashboardPage. The page currently shows numeric stats (kWh, ERE claims, earnings) without any temporal context. Recharts is installed and already used on the admin dashboard. The DashboardPage already imports
LazyBarChart,LazyAreaChart, andBar,Area,XAxis,YAxis,CartesianGrid,Tooltip,Legendfrom recharts but [Assumption: may not render them for all users or may only show them conditionally]. - Acceptance Criteria:
- User dashboard shows a kWh trend chart (monthly bar or area chart) for the current year
- Chart uses the existing
LazyChartWrapperfor code-split loading - Chart uses the existing
CustomTooltipandChartGradientscomponents for visual consistency with admin dashboard - Empty state handled gracefully when user has < 2 months of data (show
EmptyChartcomponent) - Chart is responsive and renders well at mobile widths (300px+)
- Chart colors use @theme tokens (primary-600 for bars, navy for accents)
- Priority: P0
FR-8: Search on User-Facing Lists
- Description: Add the existing
SearchInputcomponent to DocumentsPage, ConversationsPage, and ChargingPointsPage. These pages currently lack client-side or server-side search, forcing users to scroll through lists. - Acceptance Criteria:
-
SearchInputcomponent is rendered at the top of the list section on DocumentsPage, ConversationsPage, and ChargingPointsPage - DocumentsPage: filters by document type name, filename, or status
- ConversationsPage: filters by subject or last message content
- ChargingPointsPage: filters by charging point name, brand, model, or location
- Search is debounced (300ms) to prevent excessive re-renders
- Clearing search restores the full list
- Empty search results show the
EmptyStatecomponent with a "no results" message
-
- Priority: P1
FR-9: Inline Document Preview Modal
- Description: The DocumentsPage currently has a
DocumentPreviewModalcomponent but document preview for images/PDFs should be enhanced with zoom, rotation for images, and in-modal pagination for multi-page PDFs. Currently the modal opens but the experience is basic. - Acceptance Criteria:
- Image preview supports pinch-to-zoom on mobile and scroll-to-zoom on desktop
- Image preview supports 90-degree rotation
- PDF preview renders inline in the modal (using browser native
<object>or<iframe>) - Download button is always visible in the modal header
- Modal size is
xl(max-w-4xl) for adequate preview space - Non-previewable files show a clear "Preview niet beschikbaar" message with download link
- Priority: P2
FR-10: Onboarding Progress Bar Enhancement
- Description: The
StepIndicatorcomponent already has a horizontal stepper with connecting lines and a mobile progress bar. Enhance it with: a completed-step count fraction (e.g., "3/6"), step descriptions on hover (desktop), and a subtle animation when transitioning between steps. - Acceptance Criteria:
- Desktop: hovering a step circle shows a tooltip with the step description
- Desktop: connecting line animates (fills) when a step is completed
- Mobile: progress bar shows fraction text (e.g., "3 van 6 voltooid") below the bar
- Transition between steps includes a subtle slide animation on the main content
- All changes are backwards-compatible with existing
OnboardingProviderstate management
- Priority: P2
Phase 3: Admin Efficiency
FR-11: Bulk Admin Actions
- Description: Add bulk selection and batch operations to admin table pages. Priority tables: AdminDocumentsPage, AdminKwhEntriesPage, AdminEREClaimsPage. Admins currently process items one-by-one.
- Acceptance Criteria:
- Checkbox column added to AdminDocumentsPage, AdminKwhEntriesPage, AdminEREClaimsPage tables
- "Select all on page" checkbox in table header
- Floating action bar appears when 1+ items selected, showing: count, available actions, "Deselect all"
- AdminDocumentsPage bulk actions: Verify Selected, Reject Selected (with shared rejection reason)
- AdminKwhEntriesPage bulk actions: Verify Selected, Reject Selected
- AdminEREClaimsPage bulk actions: Submit Selected, Reject Selected
- Confirmation modal before bulk state changes with count of affected items
- Success/error toast after bulk operation with count of succeeded/failed
- Selection state is preserved during pagination (across pages) [Assumption: acceptable to clear on filter change]
- Backend already supports individual PATCH operations; bulk is implemented as parallel API calls with error aggregation
- Priority: P0
FR-12: Admin Dashboard Charts Enhancement
- Description: The AdminDashboard already has a
DashboardChartscomponent. Ensure it renders monthly kWh and revenue trend charts for the selected year. Add a user growth sparkline to the KeyMetrics section. - Acceptance Criteria:
- DashboardCharts renders bar chart for monthly kWh and area chart for monthly revenue
- Charts use consistent color scheme from @theme tokens
- User count metric in KeyMetrics includes a small sparkline showing 6-month trend
- Charts handle empty data gracefully (EmptyChart component)
- Year selector controls all charts (already wired via selectedYear prop)
- Priority: P1
FR-13: Mobile Table Responsiveness
- Description: Admin tables with 6-9 columns don't collapse on mobile viewports. Implement a responsive table pattern that works for the admin table pages.
- Acceptance Criteria:
- Tables with >5 columns switch to a card-based layout on viewports < 768px
- Card layout shows: primary identifier (name/email), status badge, key metric, and an expand/detail button
- Expanded card shows all columns in a key-value list format
- Sort and filter controls remain accessible on mobile
- Pattern implemented as a reusable
ResponsiveTablecomponent or mixin - Applied to: AdminUsersPage, AdminDocumentsPage, AdminKwhEntriesPage, AdminEREClaimsPage, AdminChargingPointsPage, AdminOrganizationsPage
- Priority: P1
FR-14: Charging Point Map View (Admin)
- Description: Add a map view toggle to AdminChargingPointsPage. The project already has
@react-google-maps/apiinstalled and aChargingPointsMapViewcomponent exists incomponents/charging-points/. - Acceptance Criteria:
- Toggle button (list view / map view) in the page header
- Map view renders all charging points as markers using
@react-google-maps/api - Clicking a marker shows an info window with: name, brand/model, owner, status
- Map defaults to Netherlands bounding box, auto-zooms to fit all markers
- Filter state from the list view applies to the map view (same dataset)
- Map view does not load on initial page load (lazy loaded on toggle)
- Priority: P2
Phase 4: Polish & Consistency
FR-15: Breadcrumb Navigation
- Description: Deep pages (AdminUserDetailPage, AdminOrganizationDetailPage, AdminChargingPointDetailPage, AdminEANCodeDetailPage, ConversationDetailPage) don't show their position in the navigation hierarchy. Add a breadcrumb component.
- Acceptance Criteria:
-
Breadcrumbcomponent renders a horizontal path: Home > Section > Item Name - Each breadcrumb segment is a link except the current page
- Component integrates with react-router-dom for path-based breadcrumb generation
- Applied to all detail pages (minimum 6 pages listed above)
- Mobile: breadcrumbs truncate with "..." for long paths, showing at minimum the parent and current page
-
- Priority: P1
FR-16: Modal Component Consolidation
- Description: There are 20+ modal implementations across the codebase. Many use inline
fixed inset-0 bg-black/50patterns instead of the centralizedModalcomponent with focus trap. Migrate all inline modals to use the sharedModalcomponent. - Acceptance Criteria:
- Audit identifies all inline modal implementations (search for
fixed inset-0) - All modals use the
Modalcomponent fromcomponents/common/Modal.tsx - Focus trap works correctly in all migrated modals
- Escape key closes all modals
- Scroll lock is applied when any modal is open
- No visual regressions in any migrated modal
- Audit identifies all inline modal implementations (search for
- Priority: P1
FR-17: Settings Page Tabs
- Description: ProfilePage and OrganizationSettingsPage are long scrolling pages. Convert them to tabbed layouts using the existing
Tabscomponent (components/common/Tabs.tsx). - Acceptance Criteria:
- ProfilePage has tabs: Profiel, Beveiliging, Voorkeuren
- OrganizationSettingsPage has tabs: Algemeen, Leden, Facturatie
- Tab state is reflected in the URL hash (e.g.,
/profile#beveiliging) for deep linking - Tab content loads lazily (only the active tab's section is rendered)
- Mobile: tabs are horizontally scrollable if they overflow
- Priority: P2
FR-18: Holding Structure Visualization
- Description: The HoldingManagementPage shows subsidiaries as a flat list. Add a tree/org-chart visualization for holding companies with subsidiaries.
- Acceptance Criteria:
- Holding company displayed as root node with subsidiaries as children
- Each node shows: organization name, KVK number, status, member count
- Nodes are clickable and navigate to the organization detail page
- Tree handles up to 20 subsidiaries without performance issues
- Mobile: tree collapses to an indented list view
- No additional library required (built with CSS flexbox/grid + existing card components)
- Priority: P2
FR-19: Status Badge Color Alignment
- Description: Status badge colors are inconsistent between contexts: EREClaimsPage uses blue (
bg-blue-100) for VERIFIED while DocumentsPage uses green (bg-success-100). TheStatusBadgecomponent defines a canonical mapping, but some pages override or bypass it. - Acceptance Criteria:
- All pages use the
StatusBadgecomponent for status display (no inline badge rendering) - VERIFIED/APPROVED/ACTIVE always use
success-*tokens (green family) - PENDING/SUBMITTED/IN_BEHANDELING always use
warning-*tokens (yellow family) - REJECTED/FAILED/REVOKED always use
danger-*tokens (red family) - IN_PROGRESS/PROCESSING/OPEN use
info-*(blue family) -- distinguishable from success - CLOSED/EXPIRED/CANCELLED/INACTIVE use
gray-*tokens - Visual audit confirms consistent colors across all pages
- All pages use the
- Priority: P1
FR-20: EmptyState Component Consistency
- Description: The
EmptyStatecomponent exists but is not used on all pages that can have empty lists. Some pages show plain text or nothing when no data exists. - Acceptance Criteria:
- All list/table pages use
EmptyStatewhen data array is empty - Each EmptyState includes: relevant icon, message, and a primary action button (where applicable)
- EmptyState messages are context-specific (not generic "No data found")
- Applied to minimum 10 pages: DocumentsPage, ChargingPointsPage, EREClaimsPage, ConversationsPage, EANCodesPage, KwhEntryPage, and all admin list pages with missing EmptyState
- All list/table pages use
- Priority: P2
5. Non-Functional Requirements
Performance
- Auth pages (Phase 1): LCP < 1.5s, no layout shift from background loading
- Charts (Phase 2, 3): Recharts bundles are already lazy-loaded via
LazyChartWrapper; maintain this pattern. Chart render time < 500ms for datasets up to 12 months. - Drag-and-drop (Phase 2): File selection to upload-start latency < 200ms
- Bulk actions (Phase 3): UI remains responsive during parallel API calls; use request batching (max 10 concurrent)
- Map view (Phase 3): Lazy-loaded Google Maps bundle; initial render < 2s for up to 500 markers
Scale
- Current user base: [Assumption: hundreds of users, growing]. Design for up to 5,000 active users.
- Admin tables: Must handle 10,000+ rows with pagination (already server-side paginated).
- Bulk actions: Tested with selections up to 100 items.
- Map view: Tested with up to 500 charging point markers. Use marker clustering if >200 visible.
SLOs/SLAs
- N/A -- frontend-only changes. No backend SLA modifications.
- Client-side error rate (tracked via Grafana Faro): maintain < 0.5% error rate after each phase rollout.
- Bundle size budget: no phase should increase the main bundle by more than 50KB gzipped. Use code splitting for new components.
Privacy
- No new PII collection or processing.
- File drag-and-drop: files are sent via the existing
multipart/form-dataupload API. No client-side file storage or caching beyond the upload flow. - Map view: uses coordinates already stored in the database. No new geolocation collection from users.
Security
- No new authentication or authorization flows.
- Bulk admin actions: reuse existing per-item API endpoints with existing RBAC. No new admin-only endpoints needed.
- File uploads: existing backend validation (MIME type, magic bytes, file size) remains unchanged.
- Modal focus trap: already implemented in the shared
Modalcomponent. Migration ensures all modals get this security benefit (prevents interaction with background content).
Observability
- Each phase includes Grafana Faro integration for error tracking (already configured globally).
- New components should include
data-testidattributes for E2E test targeting. - Console errors from new chart/map components should be caught and logged, not displayed to users.
- [Assumption: No new server-side metrics needed for frontend-only changes.]
6. Scope
In Scope
- Visual redesign of auth pages (Login, Register, ForgotPassword, ResetPassword)
- Reusable FileDropZone component + integration on 4 pages
- User dashboard chart additions
- SearchInput integration on 3 user-facing list pages
- Document preview modal enhancement
- Onboarding step indicator polish
- Bulk selection + batch actions on 3 admin table pages
- Admin dashboard chart enhancements
- Mobile-responsive table pattern for 6 admin pages
- Admin charging point map view
- Breadcrumb navigation on 6+ detail pages
- Modal consolidation (migrate inline modals to shared Modal component)
- Tabbed settings pages (ProfilePage, OrganizationSettingsPage)
- Holding structure tree visualization
- Status badge color alignment
- EmptyState consistency
- Color token, icon sizing, and button component consolidation
Out of Scope (and why)
- Backend API changes: This initiative is frontend-only. Bulk actions use existing per-item endpoints. If backend bulk endpoints are needed for performance, that is a separate initiative.
- New features / business logic: This PRD covers UX and design improvements to existing functionality. No new features are being added.
- Form library migration (react-hook-form everywhere): The codebase mixes react-hook-form with uncontrolled state. Full migration is desirable but too large for this initiative. New code should use react-hook-form; existing code is migrated only when a page is already being touched.
- Admin import profile visual mapping: Requires significant backend changes to support visual column preview. Deferred.
- Real-time collaboration features: Out of scope for a design improvement initiative.
- Landing page changes: Already scored 8/10. Not a priority.
- Native mobile-specific UI (Capacitor plugins): All changes must work in the SPA web view. No platform-specific native UI.
Future Considerations
- Design system documentation site: Once tokens and components are consolidated, create a Storybook or similar reference.
- Dark mode support: The @theme token system would make this feasible after this initiative.
- Backend bulk action endpoints: If parallel API calls for bulk actions prove too slow, purpose-built batch endpoints would be the next step.
- Accessibility audit: This initiative maintains existing accessibility but does not systematically improve it. A focused a11y initiative should follow.
- Animation library: If more complex animations are needed beyond CSS transitions, consider framer-motion.
7. Rollout Plan
Phase 1: First Impression & Design Foundation (Weeks 1-3)
Deliverables: FR-1 through FR-5
Gate criteria to proceed to Phase 2:
- All four auth pages deployed with new AuthLayout
- No increase in login error rate (Grafana Faro)
- Stakeholder visual review approved
- All E2E auth tests pass
Guardrails:
- Login success rate: must not drop below current baseline
- Auth page LCP: must stay < 1.5s
- Mobile viewport rendering: verified on iOS Safari and Android Chrome via Capacitor build
Phase 2: Core UX Improvements (Weeks 4-7)
Deliverables: FR-6 through FR-10
Gate criteria to proceed to Phase 3:
- FileDropZone deployed on all 4 target pages
- Dashboard charts rendering for users with data
- Search working on 3 user-facing list pages
Guardrails:
- Upload success rate: must not drop (monitor via existing upload API error rates)
- Bundle size: total increase < 30KB gzipped (charts are already code-split)
- No new console errors on mobile devices
Phase 3: Admin Efficiency (Weeks 8-11)
Deliverables: FR-11 through FR-14
Gate criteria to proceed to Phase 4:
- Bulk actions functional on 3 admin pages
- Mobile table responsiveness verified on real devices
- Admin team feedback collected (internal testing)
Guardrails:
- Bulk action failure rate: < 5% of individual operations within a bulk batch
- Admin page load times: no regression (monitor via Faro)
- Map view: no Google Maps API quota spikes (monitor billing)
Phase 4: Polish & Consistency (Weeks 12-15)
Deliverables: FR-15 through FR-20
Gate criteria for completion:
- All breadcrumbs deployed on detail pages
- All inline modals migrated to shared Modal component
- Status badge colors consistent across all pages
- EmptyState used on all list pages
Guardrails:
- No visual regressions (screenshot comparison via Playwright
docs:screenshots) - E2E test suite passes without new failures
- Client-side error rate remains < 0.5%
Kill Switch
- Feature flags: Not currently in the codebase. For this initiative, changes are deployed behind the
developbranch and tested before merging tomain. - Rollback: Each phase is a set of commits on
develop. If a phase causes issues post-merge-to-main, revert the merge commit. Frontend-only changes have zero database migration risk. - Emergency disable for map view: The Google Maps component is lazy-loaded. If API quota is exceeded, the toggle can be hidden with a simple condition check (environment variable or admin setting).
8. Risks & Open Questions
Known Risks
| Risk | Probability | Impact | Mitigation |
|---|---|---|---|
| Auth page redesign reduces conversion temporarily (A/B test not feasible with current infra) | Low | High | Deploy to develop first, stakeholder review before main merge. Monitor login success rate for 1 week. |
| Bulk actions overload backend with parallel requests | Medium | Medium | Implement client-side request batching (max 10 concurrent). Add retry with exponential backoff for failed items. |
| Google Maps API costs increase with map view usage | Low | Medium | Lazy-load map only on toggle. Monitor billing. Set daily quota limit in Google Cloud Console. |
| Modal migration introduces subtle focus/scroll bugs | Medium | Low | Migrate incrementally (5 modals at a time). Test each with keyboard navigation. |
| Mobile responsive tables look different from what admins expect | Low | Medium | Internal admin preview and feedback before deployment. |
| Recharts bundle size impact on mobile performance | Low | Medium | Already lazy-loaded via LazyChartWrapper. Verify no bundle regression. |
Open Questions
| Question | Owner | Needed By | Suggested Resolution |
|---|---|---|---|
| What is the current login page bounce rate and registration completion rate? | Product | Before Phase 1 starts | Check Grafana Faro or analytics tool for baseline metrics |
| Does the admin team prefer card-based or horizontally-scrollable tables on mobile? | Admin team lead | Before Phase 3 | Run a quick internal poll with mockups of both approaches |
| Should bulk actions use a new backend batch endpoint or parallel individual calls? | Backend lead | Before Phase 3 | Start with parallel calls; add batch endpoint if performance is inadequate for >50 items |
| Is there a Google Maps API key already configured for production? | DevOps | Before Phase 3 (FR-14) | Check .env.production for VITE_GOOGLE_MAPS_API_KEY |
| Should the AuthLayout use a static gradient or a subtle animated background? | Design/Product | Before Phase 1 | Recommend static gradient for performance; animated version as future enhancement |
Dependencies & Assumptions
- No backend changes required. All improvements are frontend-only. Bulk actions use existing per-item PATCH endpoints.
- Recharts v3.5.1 is already installed and working. Used on AdminDashboard. No version upgrade needed.
- @react-google-maps/api is already installed.
ChargingPointsMapViewcomponent exists. Map view is an extension, not a net-new integration. - Tailwind v4 @theme tokens are already defined in
index.csswith navy, primary, success, warning, danger color scales. - The shared
Modalcomponent with focus trap exists and is production-ready atcomponents/common/Modal.tsx. - The
Buttoncomponent exists atcomponents/common/Button.tsxwith all 6 variants. - The
SearchInputcomponent exists atcomponents/common/SearchInput.tsxand is used on admin pages. - E2E tests exist for auth flows, dashboard, and key user journeys. All phases must pass the existing E2E suite.
Prioritization Rationale
The ordering follows this ROI logic:
-
Phase 1 (Auth + Foundation): Highest leverage per engineering hour. Auth pages are the single point of entry for every new user. Design foundation work (tokens, icons, buttons) reduces cost of all subsequent phases.
-
Phase 2 (Core UX): Drag-and-drop and dashboard charts address the two most frequent user complaints (file upload friction and "where am I?" dashboard context). Search on lists is low-effort with the existing SearchInput component.
-
Phase 3 (Admin Efficiency): Bulk actions and mobile tables are the admin team's top requests. These directly translate to operational cost savings as the user base grows. Map view adds spatial context for a geographically distributed asset base.
-
Phase 4 (Polish & Consistency): Breadcrumbs, modal consolidation, and status badge alignment are important for long-term codebase health but have lower immediate user impact. Grouping them last ensures they don't delay higher-impact work.