This document delivers a comprehensive, highly granular technical breakdown of the iRonoc architecture. It spans the system architecture, frontend structure, granular backend service layer, and showcases deep functional flow sections for Donate Items, Portfolio Items, and Brews/Coffee subsystems.
The iRonoc portfolio platform is structured as a decoupled, multi-tier full-stack application. It integrates a high-performance Java 25 / Spring Boot backend (embedded Tomcat) with a responsive, client-side routed React 19 single-page application (SPA).
+---------------------------------------------------------------------------------------------------+
| Client Web Browser |
| - Renders UI elements (React 19, Material UI 7, Bootstrap 5) |
| - Triggers Client-Side Routes, REST Calls, and real-time GraphQL Subscription streams |
+-------------------------------------------------+-------------------------------------------------+
|
| HTTP / HTTPS / WSS (WebSockets)
v
+---------------------------------------------------------------------------------------------------+
| Gateway / Proxy Layer |
| - Serves compiled, static frontend bundles (.js, .css, .html) from Tomcat /static mapping |
| - Reverse-proxies API endpoints (/api/*) and GraphQL gateways (/graphql) to active servlet hooks |
+-------------------------------------------------+-------------------------------------------------+
|
v
+---------------------------------------------------------------------------------------------------+
| Spring Boot Backend (Tomcat) |
| |
| +---------------------------------------+ +-------------------------------------------+ |
| | REST Controllers | | GraphQL Controllers | |
| | - DonateRestController | | - DonateGraphqlController (Sinks.Many) | |
| | - CoffeeController | | - BrewGraphqlController | |
| | - ActivityTrackingController | | - PortfolioItemsResolver (QueryMapping) | |
| +-------------------+-------------------+ +-------------------+-----------------------+ |
| | | |
| +-----------------------+-----------------------+ |
| | |
| v |
| +-------------------------------------------------------------------------------------------+ |
| | Granular Backend Service & Resolver Layer | |
| | - GitDetailsService (GitHub REST engine) | |
| | - CoffeesService (REST Coffee parser) / GraphQLClientService (Custom GraphQL Client) | |
| | - In-Memory Caches: GitRepoCacheService, GitProjectCacheService, CoffeeCacheService | |
| | - Resolvers: DonateItemsResolver, PortfolioItemsResolver | |
| +-------------------------------------------+-----------------------------------------------+ |
| | |
+-----------------------------------------------v---------------------------------------------------+
|
+-------------------------+-------------------------+
| |
v v
+---------------------------------------+ +---------------------------------------+
| AWS Secrets Manager | | Third-Party APIs |
| - Retrieves GitHub personal keys | | - GitHub API (Issues, Repositories) |
| - Secures backend configurations | | - External Coffee API REST/GraphQLs |
+---------------------------------------+ +---------------------------------------+
These diagrams can be visualized natively inside IntelliJ IDEA (using the diagram viewer plugin), GitHub, or standard markdown readers.
This container blueprint details the precise boundaries, filter intercepts, servlet mappings, and multi-thread caching layers inside the Spring Boot container.
flowchart TB
subgraph ClientContainer [Client Browser Container]
SPA[React 19 SPA]
Apollo[Apollo Client Link Splitter]
Axios[Axios / sendBeacon Client]
end
subgraph SecurityFilterLayer [Tomcat Servlet Security & Mapping Layer]
CORS[CorsRegistry Filter Mappings]
Limiter[Bucket4j Rate Limiting Interceptor]
Dispatcher[Spring DispatcherServlet]
SockHandler[GraphQlWebSocketHandler]
end
subgraph ControllerLayer [Controller Endpoint Mappings]
REST[REST API Endpoints: Coffee, Donate, Activity]
GraphQL[GraphQL Engine Mappings: @QueryMapping, @MutationMapping]
end
subgraph ServiceCore [Granular Backend Service & Cache Engines]
GitService[GitDetailsService]
CoffeeService[CoffeesService]
CacheManager[In-Memory ConcurrentHashMap Cache Managers]
GitRepoCache[GitRepoCacheService]
GitProjCache[GitProjectCacheService]
CoffeeCache[CoffeeCacheService]
DonResolver[DonateItemsResolver]
PortResolver[PortfolioItemsResolver]
Sink[Reactor Sinks.Many Multicast Channel]
end
subgraph Datastore [Classpath JSON Datastore Layer]
DiskDonate[(json/donate-items.json)]
DiskBrews[(json/brews.json)]
DiskPortfolio[(json/portfolio-items.json)]
DiskWhitelist[(graphql/charities.txt)]
end
subgraph External [External Network boundaries]
AWS[AWS Secrets Manager API]
GitAPI[GitHub REST API v3]
CoffeeAPI[Third-Party Coffee REST / GraphQL APIs]
end
SPA -->|GraphQL Queries| Apollo
SPA -->|HTTP / Telemetry Beacons| Axios
Apollo -->|POST /graphql| CORS
Apollo -->|WS ws://localhost:8080/graphql| CORS
Axios -->|PUT/GET /api/*| CORS
CORS --> Limiter
Limiter --> Dispatcher
Limiter --> SockHandler
Dispatcher --> REST
Dispatcher --> GraphQL
SockHandler --> GraphQL
REST --> GitService
REST --> CoffeeService
GraphQL --> DonResolver
GraphQL --> PortResolver
GraphQL --> Sink
GitService --> GitRepoCache
GitService --> GitProjCache
CoffeeService --> CoffeeCache
GitRepoCache --> CacheManager
GitProjCache --> CacheManager
CoffeeCache --> CacheManager
DonResolver --> DiskDonate
DonResolver --> DiskWhitelist
PortResolver --> DiskPortfolio
GitService -->|GET Request / Bearer Token| GitAPI
GitService -->|Query Access Tokens| AWS
CoffeeService -->|GET Request| CoffeeAPI
This flowchart maps the sequential UX transitions, modal interactions, loading states, and live interface updates available to the user.
flowchart TD
Start([User Opens App]) --> Home[Renders Landing Page - Consistent Navy Theme]
Home --> NavProjects{Navigates App}
%% Projects UX Flow
NavProjects -->|Projects Link| Projects[Renders RepoDetails]
Projects --> LoadProjects[Check Cached Repository Data]
LoadProjects -->|Miss / Load| ShowSpinner1[Display LoadingSpinner]
ShowSpinner1 --> Hydrated1[Render Grid Cards with Repo Details]
LoadProjects -->|Hit| Hydrated1
Hydrated1 --> ClickRepo[User Clicks Specific Repo Card]
ClickRepo --> Issues[Open RepoIssues Backlog]
Issues --> Recharts[Display Interactive Recharts Bar Chart of Active Issues]
%% Brews UX Flow
NavProjects -->|Brews Link| CoffeeHome[Renders CoffeeHome]
CoffeeHome --> LoadRecipes[Check In-Memory CoffeeCacheService]
LoadRecipes -->|Miss| GetExtRecipes[Fetch Recipes from External Coffee API]
GetExtRecipes --> JacksonParser[Deserialize & Map to CoffeeDomain via Jackson]
JacksonParser --> Hydrated2[Render Coffee Carousel with preparation cards]
LoadRecipes -->|Hit| Hydrated2
%% Donate UX Flow
NavProjects -->|Donate Link| Donate[Renders Donate Carousel]
Donate --> HydrateDonate[Execute GET_DONATE_ITEMS Query]
HydrateDonate --> LoadWhitelist[Filter On-Disk Charities via charities.txt Allowed List]
LoadWhitelist --> RenderCarousel[Render Red Carousel Cards with Verified Charities]
RenderCarousel --> OpenModal[User Clicks 'Add Charity' Button]
OpenModal --> InputDetails[Input Charity Details in Registration Form]
InputDetails --> ValidateForm{Form Fields Validated?}
ValidateForm -->|Invalid format/year/protocol| FormError[Display Specific Warning message inside form]
FormError --> InputDetails
ValidateForm -->|Valid details| DispatchMutation[Submit addCharityOption Mutation to GraphQL Server]
DispatchMutation --> CheckServerWhitelist{Name is Whitelisted in charities.txt?}
CheckServerWhitelist -->|No / Fraud attempt| ServerError[Reject transaction & throw Validation error]
ServerError --> Donate
CheckServerWhitelist -->|Yes| PersistServer[Append details to json/donate-items.json]
PersistServer --> SinkEmit[Emit next charity to Multicast Sink]
SinkEmit --> PushWS[Push Event pushed instantly over ws://localhost:8080/graphql]
PushWS --> UpdateState[Client subscription state appends new card dynamically]
UpdateState --> RenderCarousel
This sequence diagram tracks the full transactional life cycle when a user registers a new charity, from validation to real-time sync.
sequenceDiagram
autonumber
actor Client as Client Browser
participant Controller as DonateGraphqlController
participant Resolver as DonateItemsResolver
participant Sink as Sinks.Many (Multicast Buffer)
participant Disk as JSON Datastore
Client->>Controller: Mutation: addCharityOption(...)
activate Controller
Controller->>Resolver: addDonateItem(Item)
activate Resolver
Resolver->>Resolver: Validate URL, Founding Year, & Email
Resolver->>Resolver: Check charities.txt whitelist
alt Item is Malformed or Exists
Resolver-->>Controller: Return false (invalid transaction)
Controller-->>Client: Return Failure Message
else Item is Valid & New
Resolver->>Disk: Persist payload to JSON datastore
Resolver-->>Controller: Return true (success)
deactivate Resolver
Controller->>Sink: tryEmitNext(newItem)
activate Sink
Sink-->>Controller: Confirmed Emit to Multicast buffer
deactivate Sink
par Broadcast real-time WebSocket update
Controller-->>Client: WebSocket push: donateItemsSubscription (newItem)
and Acknowledge original client request
Controller-->>Client: Return Success Message / DTO
deactivate Controller
end
end
This sequence diagram details the fallback and deserialization pipeline when querying coffee brewing instructions.
sequenceDiagram
autonumber
actor Client as Client Browser
participant Controller as CoffeeController
participant Cache as CoffeeCacheService
participant Service as CoffeesService / GraphQLClient
participant Ext as External Coffee APIs (REST/GraphQL)
Client->>Controller: GET /api/coffees
activate Controller
Controller->>Cache: get()
activate Cache
alt Cache Hit (In-Memory Available)
Cache-->>Controller: Return Cached CoffeeDomain List
Controller-->>Client: Return JSON payload (<50ms response)
else Cache Miss (Empty / Evicted)
Cache-->>Controller: Return null
deactivate Cache
Controller->>Service: getCoffeeDetails() / fetchCoffeeDetails()
activate Service
Service->>Ext: Query remote REST/GraphQL resources
activate Ext
Ext-->>Service: Return raw payload (ingredients as text array)
deactivate Ext
Service->>Service: Custom Deserialization (IngredientsDeserializer)
Service->>Service: Map payload to CoffeeDomain collection
Service-->>Controller: Return mapped list
deactivate Service
Controller->>Cache: put(coffeeDomains)
activate Cache
Cache-->>Controller: Confirmed hydrate cache
deactivate Cache
Controller-->>Client: Return newly compiled JSON payload
deactivate Controller
end
The Charity and Donation subsystem is a primary component of the iRonoc platform. It delivers real-time charity registration, cryptographic verification, and reactive synchronization between multiple client browsers and the datastore.
[ Client: Donate.js ] [ Spring Controllers ] [ DonateItemsResolver ] [ Datastore / Disk ]
| | | |
|---- GraphQL Query -------->| | |
| (getDonateItems) |---- getDonateItems() ------>| |
| | |---- load classpath ------>| [ donate-items.json ]
| | |---- validate year/URLs -->| [ charities.txt ]
|<--- JSON Charity List -----|<--- filtered list ----------| |
| | | |
| | | |
|---- GraphQL Mutation ----->| | |
| (addCharityOption) |---- addDonateItem(Item) --->| |
| | |--- write to class resource| [ donate-items.json ]
| | | |
| |--- Sink: tryEmitNext() | |
|<--- Mutated Confirmation --| (Broadcast to WS) | |
| | | |
components/Donate.js)The React frontend component renders a responsive Material-UI and Bootstrap grid layout of active, trusted charity options:
img), summary descriptions (overview), founding years, and validated telephone lines. Clicking a card directs the browser to the charity’s official donation portal.client.query) on mounting to perform initial pull-hydration of charity cards directly from /graphql.client.subscribe listening to DONATE_ADDED_SUBSCRIPTION mapping to donateItemsSubscription). This dynamically appends new cards pushed by the backend Sinks.Many multicast sink to the browser carousel list instantly without requiring full page fetches, polling, or Axios requests.DonateGraphqlController.java):
@QueryMapping on donateItems: Fetches all validated charities.@MutationMapping on addCharityOption: Initiates registration, validations, and disk-persistance.@SubscriptionMapping on donateItemsSubscription: Connects client WebSocket listeners to a Project Reactor multicast Sink (Sinks.Many with an backpressure buffer size of 256) to push real-time broadcasts.DonateRestController.java):
GET /api/donate-items returning the list of active charities as a raw JSON array for legacy browser integrations.To preserve the security of the application and mitigate spam or malicious scripts (e.g. cross-site scripting inputs), the backend enforces strict validation criteria in DonateItemsResolver.java:
charities.txt): Located at src/main/resources/graphql/charities.txt. This contains the exact, trimmed, case-insensitive names of charities permitted to be displayed on the platform. If an added name does not exist in this list, registration is blocked.donate-items.json): Located at src/main/resources/json/donate-items.json. Stores the details of the active, whitelisted charities in JSON format:
{
"alt": "Jack and Jill Foundation",
"name": "The Jack and Jill Children's Foundation",
"link": "https://www.jackandjill.ie",
"donate": "https://www.jackandjill.ie/how-you-can-help/donate/",
"img": "jack-and-jill-logo.png",
"overview": "Provides direct funding and home nursing care to children with highly complex medical conditions.",
"founded": 1997,
"phone": "+353 (0) 45 894 538"
}
1000 and 2100.link and donate) are parsed and verified using a strict HTTP/HTTPS pattern.To register and demonstrate your charity on this platform:
charities.txt.json/donate-items.json or submit it via the frontend Donation portal.📢 Important Security Notice: To protect users, only trusted charities are permitted. If your desired charity is not currently supported, please reach out directly to conorheffron on GitHub (username:
conorheffron/@conorheffron) to submit your charity’s credentials and request to have its name appended to the trusted whitelisted (charities.txt) file.
The frontend is built using React 19 (ES6+) as a Single-Page Application (SPA). It manages routing in the browser using React Router 7, performs data queries via REST (Axios/Fetch) or GraphQL (Apollo Client), and utilizes modern reactive UI controls.
+-------------------+
| App.js Entry |
| (Router Engine) |
+---------+---------+
|
+---------v---------+
| AppNavbar.js |
| (Bootstrap/MUI 7) |
+---------+---------+
|
+-------------------------+-------------------------+
| |
v (Static/View routes) v (Dynamic/Functional routes)
+---------+-----------+ +---------+---------+
| Static Presentation | | State & API Driven|
+---------+-----------+ +---------+---------+
| |
+-------------+-------------+ +-------------+-------------+
| | | | | |
v v v v v v
About.js Home.js NotFound.js Donate.js CoffeeHome.js RepoDetails.js
(Profile) (Landing) (404 Page) (Charity Grid) (Brews list) (Backlog View)
| | |
v v v
[Apollo Client] [Fetch API] [Axios REST]
App.js (Core Orchestrator): Houses the central Router and registers the app’s dynamic view routes. It also declares and initializes the Apollo Client instance specifically wrapped around the Donate route.AppNavbar.js & Footer.js: Core layout elements. They offer fully responsive toggles and structural grids styled with MUI 7 and Bootstrap 5.components/Home.js (The Landing Page): Renders the central entry point. Integrates custom background asset loaders (loadCameraRollImages) to serve a consistent, stylized Navy theme (darkblue-bg.png).components/Donate.js: Connecting endpoint for charitable contributions. Leverages Apollo Client’s useQuery, useMutation, and real-time WebSockets useSubscription to synchronize charity registers instantly.components/CoffeeHome.js & ControlledCarousel.js: Interactive hubs. Render dynamic coffee preparation cards, pulling brewing instructions and graphics either from Spring REST interfaces or mock JSON arrays.components/RepoDetails.js & components/RepoIssues.js: Backlog management panels. Perform REST requests using Axios to pull cached, rate-limited GitHub repositories, displaying active project issue backlogs using Recharts graphic plots.The backend uses a service-driven, cache-optimized structure to coordinate Spring Controllers with third-party networks and filesystem records.
+---------------------------------------------------------------------------------+
| Spring Controllers |
+-------+-------------------------+------------------------+------------------+---+
| | | |
v v v v
+--------------+--------------+ +--------+--------+ +-------------+-------------+ +--+----------------+
| GitDetailsService | | BrewsResolver | | DonateItemsResolver | |ActivityTracking |
| - Coordinates git calls | | - Loads brews | | - Loads, validates, lists | | Service |
| - Thread-safe repository | | local JSON | | permitted charities | | - Receives click |
+--------------+--------------+ +--------+--------+ +-------------+-------------+ | beacons |
| | | +--+----------------+
+------+------+ v v |
| | +-----------------+ +-----------------+ v
v v | Brews Datastore| | Charity Files | +------+------+
+-----+---+ +-----+---+ | (json/brews.json| | (charities.txt | | Activity |
|GitRepo | |GitProj | +-----------------+ | donate-items) | | Datastore |
| Cache | | Cache | +-----------------+ +-------------+
+---------+ +---------+
net.ironoc.portfolio.service)GitDetailsService: Coordinates queries hitting the GitHub API. Uses Java’s template endpoints to resolve usernames, fetch backlogs, and convert complex GitHub REST payloads into serializable RepositoryDetailDto records.GitRepoCacheService / GitProjectCacheService: High-performance caching layers. Built with thread-safe ConcurrentHashMap collections. When scheduled cron jobs (GitDetailsJob) sync Git data in the background, these services hold the data to avoid hitting GitHub’s strict API rate limits.CoffeeCacheService: Stores serialized coffee preparation listings. It supports rapid memory fetches and implements explicit cleanup via @PreDestroy methods during Spring application context teardowns.ActivityTrackingService: Monitors user interaction telemetry. Receives asynchronous clicks/beacons dispatched by client browsers, processing them for usage reports.net.ironoc.portfolio.graph)DonateItemsResolver: Manages the charity registry. Loads json/donate-items.json from classpath resources, filters them against the strict graphql/charities.txt whitelist, and validates each entity’s structure (URL format, founding year, phone/email syntax) before exposing them.PortfolioItemsResolver: Parses json/portfolio-items.json to resolve, filter, and deliver structured portfolio records directly to GraphQL mapping queries.net.ironoc.portfolio.client / net.ironoc.portfolio.aws)GitClient: Integrates with the remote GitHub REST endpoints. It implements robust HTTP headers, authentication tokens, and custom timeouts (connectTimeout/readTimeout) to ensure reliable network requests.AwsSecretManager: Integrates with AWS Secrets Manager via the AWS SDK. It retrieves Git API credentials dynamically at runtime, removing the need for hardcoded keys in the repository.This section details how the platform executes its core workflows across the React client, Spring Controllers, Service Layer, and Datastores.
This module parses and delivers static portfolio metrics and highlight carousels.
[ Client: Portfolio.js ] [ PortfolioController ] [ PortfolioItemsResolver ] [ Datastore / Disk ]
| | | |
|---- GraphQL Query ---------->| | |
| (portfolioItems) |---- getPortfolioItems() ---->| |
| | |--- load from classpath --->| [ portfolio-items.json ]
|<--- JSON Portfolio list -----|<--- map to response List ----| |
portfolioItems GraphQL query.PortfolioController captures the query and calls PortfolioItemsResolver.getPortfolioItems().json/portfolio-items.json from the disk resources.PortfolioItem types), which is sent back to the browser to render the highlight cards and carousels.The coffee subsystem coordinates external APIs, in-memory caches, local configurations, and custom Jackson deserializers to serve detailed brewing instructions.
[ Client: CoffeeHome.js ] [ CoffeeController ] [ Coffee Services ] [ Ext. Web / GraphQL ]
| | | |
|---- GET /api/coffees ------>| | |
| |--- check cache --------->| |
| | (CoffeeCacheService) | |
| | [Hit: return list] | |
| | | |
| | [Miss: fetch rest]--->| |
| | |=== REST: fetch hot/ice ==>| [ https://api.sampleapis.com ]
| | |<== Map to CoffeeDomain ===|
| | | |
| | [Miss: fetch Graph]-->| |
| | |=== GraphQL Client =======>| [ GraphQL Coffee Server ]
| | |<== Map to Map<Str,Obj> ===|
|<--- JSON Coffee Domain -----|<--- Update Cache --------| |
GET request to /api/coffees. CoffeeController checks the CoffeeCacheService first.
CoffeesService.getCoffeeDetails(). This service performs REST requests to external endpoints (e.g. https://api.sampleapis.com/coffee/hot and https://api.sampleapis.com/coffee/iced).getCoffeeDetailsGraphQl(), which runs GraphQLClientService.fetchCoffeeDetails(). This service uses RestTemplate to send a structured GraphQL query to a coffee API.IngredientsDeserializer) to clean and format the ingredients into standardized list models.CoffeeDomain object models.CoffeeDomain list is stored in CoffeeCacheService and returned to the client browser as a JSON array.CoffeeCarousel component.To guarantee build safety and code correctness, the project enforces strict test coverage limits (Minimum 80% coverage on all modifications):