Payment Routing System is a full-stack operations application for payment lifecycle control. It presents payments as operational records that move from creation to review, provider attempts, and final status. The frontend is the controlled user interface; the Flask API is the authority for authentication, RBAC, merchant scoping, persistence, and mutation rules.
The core modelling decision is provider_attempts. A payment may not succeed on the first provider, so the system records each attempt with provider, result, and latency. This turns routing/fallback behaviour into inspectable history and gives analytics meaningful operational data.
The Angular frontend is the assessed COM661 component. It consumes a Flask API backed by MongoDB and demonstrates role-aware workflows without treating the browser as the data authority.
The application has three main layers:
Angular Frontend -> Flask API -> MongoDB
Angular handles interaction: login/register pages, dashboard, payments workspace, analytics charts, confirmation dialogs, notifications, and role-aware controls. It validates input and manages interface state before calling the API.
Flask handles the server contract: login, JWT issuing/validation, role checks, merchant-scoped queries, payment persistence, controlled payment updates, account deletion rules, and analytics aggregation.
MongoDB stores users and payment records. Payment records include transaction details, customer details, status, merchant ownership, initiated timestamp, and provider attempts.
- User enters email and password in the Angular login form.
AuthService.loginsendsPOST /api/auth/login.- Flask validates credentials against MongoDB and returns email, role and JWT token.
- Angular stores the session in session storage.
- Guards and role-aware navigation use the session for browser workflow decisions.
- A protected page calls
PaymentsService. - The HTTP interceptor reads the stored session.
- The request is sent with
Authorization: Bearer <token>. - Flask decodes the JWT and attaches identity to the request.
- The backend queries MongoDB using the role boundary.
- Merchant requests are scoped by
created_by = authenticated_email. - Angular receives data and updates signals/computed values for the UI.
- User submits create, status, provider-attempt, edit, or delete action.
- Angular validates form state and calls
PaymentsService. - Flask validates role and allowed fields.
- MongoDB is updated only through the API.
- Angular shows notification feedback.
- Payment data is refreshed.
- Analytics refresh state is triggered so charts reflect the latest records.
The core folder contains application infrastructure:
- services for API communication and session management
- guards for authentication and RBAC
- HTTP interceptor for bearer token headers
- typed models for API, auth, payments and analytics
- constants shared across features
The features folder contains route-level screens:
auth: login and register pagesdashboard: role-scoped payment summarypayments: main payment operations workspaceanalytics: chart-based performance viewsunauthorized: access denied page
The shared folder contains reusable UI components:
- app shell
- stat card
- empty state
- confirmation dialog
- notification banner
- theme toggle
This separates workflow screens from reusable interface behaviour and keeps repeated UI decisions out of feature components.
The frontend uses Angular signals for local reactive state rather than broad shared mutable objects. This is important because the payments workspace combines multiple concerns: role-scoped data, search, filters, sorting, pagination, current selection, loading states, and mutation feedback.
Examples in the payments page:
payments: full role-scoped payment listselectedPayment: current detail panel recordsearchTerm,statusFilter,regionFilter,currencyFilter: filter statesortDirection: initiated date sort statecurrentPage: pagination stateisLoading,isSubmitting,errorMessage: UI feedback state
Computed values derive UI-ready data:
- available regions and currencies
- filtered payment list
- sorted payment list
- paged payment list
- total page count
- role-based permissions
The original API response is not mutated by filtering or sorting. This makes selection synchronisation and reset behaviour predictable, especially when filters remove the currently selected payment from view.
API access is isolated inside Angular services:
AuthServicehandles login, registration, logout, active session state, and account deletion requests.PaymentsServicehandles paginated payments, full payment aggregation, create, update and payment delete operations.AnalyticsServicehandles volume, latency and status analytics.HealthServicechecks backend availability.
The services use typed models so components work with known data shapes. The HTTP interceptor centralises bearer token attachment so feature components do not manually handle auth headers.
Authentication is JWT-based.
- User logs in.
- Flask returns a JWT containing user email and role.
- Angular stores the session in session storage.
- The app derives authentication state, role and email from
AuthService. - The HTTP interceptor attaches the bearer token to API requests.
- The backend verifies the token and applies role checks.
- Logout clears the stored session and returns the user to login.
Route protection is handled by:
authGuard: blocks unauthenticated access to private screensroleGuard: blocks access when the active role is not allowed by route data
Frontend and backend both participate in RBAC, but they do not have equal authority.
Frontend:
- route guards restrict navigation
- computed permission checks hide or show actions
- forms and buttons are displayed according to role
Backend:
- protected endpoints require JWT identity
- merchant queries are scoped by
created_by - admin and finance users can access platform-wide payment data
- payment and account mutations are checked against role-specific rules
Role behaviour:
| Role | Behaviour |
|---|---|
| Admin | Global payment visibility, core payment edits, provider attempts, status changes, and payment deletion |
| Finance | Global payment review, approve/reject status changes, provider attempts, and analytics |
| Merchant | Merchant-scoped payment visibility, payment creation, analytics for own records, and own account deletion |
Merchant scoping matters because payment records include customer and transaction information. UI restrictions improve usability, but backend scoping protects the actual data boundary.
Payment routing is not always a single action. A provider can fail or respond slowly, and a fallback provider may be attempted. Storing attempts as an ordered array preserves that history, supports investigation, and provides the source data for provider latency analytics.
Payment status and provider attempts affect operational truth. Merchant users can initiate payments, but finance/admin users control status and provider-attempt updates so review actions remain separate from merchant data entry.
Payment systems can accumulate many records. Pagination keeps API responses and table rendering manageable. The frontend aggregates pages only when a full role-scoped dataset is needed for dashboard metrics or complete client-side filtering.
Admin and finance users need broad visibility for review and analytics. Merchants need focused access to their own records. Server-side scoping prevents a merchant session from accessing platform-wide data even if frontend state or requests are manipulated.
The payments page is for operational action. Analytics are separated so payment volume, provider latency, and status distribution can be reviewed without cluttering the transaction workflow. The metrics still derive from the same stored payment records.
- Provider routing decisions are represented through recorded provider attempts; the current system does not run an automated provider-selection algorithm.
- The frontend depends on the Flask API being available and seeded with users/data for a full demonstration.
- Analytics focus on core operational metrics rather than forecasting or predictive modelling.
- Automated tests cover important frontend and backend behaviours, but full browser end-to-end tests would improve confidence.
- The project is coursework-sized, so production concerns such as audit logs, refresh tokens, deployment pipelines and observability are intentionally limited.