Finance teams expect accurate invoices, fast visibility, and zero downtime. This guide shows how to stabilize your billing backend, expose secure admin invoice endpoints, and ship a Vue-powered UI with reusable components and consistent currency formatting.
Why this approach works
- Production-minded: layered architecture, defensive null handling, and DTO-to-domain mapping so backend changes never leak into the UI.
- Reusable UI: a slot-based button component replaces duplicated markup and centralizes behavior.
- Finance-friendly: currency formatting and empty states that keep admins confident while generating invoices.
Step-by-step build
- Stabilize the backend: pull the latest Docker image, rebuild with
docker-compose up -d --build, and verify admin invoice endpoints before touching the UI. - Expose admin APIs: add
getInvoiceListandcreateInvoice; return an empty array on null responses to avoid runtime errors. - Centralize paths: extract a shared invoices base path so URL changes become single-line edits.
- Map DTOs to domain models: convert raw responses to UI-friendly objects (id, user email, amount, status) to insulate components from backend churn.
- Build a reusable button: slot-based, emits
click, supportsdisabled, and replaces duplicate markup across login, registration, sidebar actions, tariff cards, and invoices. - Render the admin table: use Vue
v-if/v-forwith templates; show purposeful empty states when no invoices exist. - Format currency consistently: move formatting into a shared formats module and reuse it across tariffs, subscriptions, and invoices.
- UX polish: place “Create Invoice” where the future user selector will live; remove artificial request delays; retest after admin re-auth (tokens expire within hours).
Architecture patterns to reuse
- Layered access: keep invoices behind a public API entry point; never call raw endpoints directly from UI components.
- Defensive defaults: return empty lists instead of surfacing null and crashing views.
- Reusable primitives: slots + events in
VButtonreduce markup drift and centralize button behavior. - Currency standardization: one formatter reused across billing surfaces prevents “950” style raw numbers.
QA and rollout checklist
- Admin token valid; session refresh tested.
- Invoice list returns an empty array without errors.
- “Create Invoice” generates records with correct user/email mapping.
- Table columns: ID, user email, amount (formatted), status.
- Loading, empty, and error states are visible and distinct.
- Reusable button renders correctly across all reused locations.
- Currency formatting matches product and subscription views.
Common pitfalls to avoid
- Letting the UI call raw endpoints (payload drift breaks components).
- Duplicated button markup that diverges over time.
- Ignoring null invoice responses, causing runtime errors.
- Hardcoding paths instead of centralizing them.
- Skipping re-authentication when admin tokens expire.
Future enhancements
- Add user-facing invoice views and payment flows.
- Introduce filters (status, date range, account) for large datasets.
- Add audit logging for admin actions alongside invoice generation.
- Extend currency formatter with locale-aware settings and rounding rules.
- Experiment with bulk invoice generation and retry logic for flaky calls.