Overview
At Nakisa, I worked on a production enterprise web platform where correctness, performance, and UX consistency matter because users operate on large datasets and repeat the same workflows daily.
My internship was full-stack in practice: I shipped customer-facing UI features in Vue 3 + TypeScript (Quasar), wired them into Spring Boot APIs, and then tightened the system by improving slow database paths and increasing backend test coverage to make changes safer.
Customer-facing UI features
Most of my UI work lived in Quasar components that revolve around structured, table-driven workflows (filtering, editing, and reviewing large lists of items). My goal was always the same: make the page feel fast and obvious even when the underlying data and rules are complex.
Concretely, I implemented new UI flows and enhancements by building reusable Quasar component patterns (cards/tables/dialogs/forms), keeping state transitions explicit (idle → loading → success/error), and making edge cases predictable (empty states, partial failures, validation feedback, and disabled actions when preconditions weren’t met).
I focused heavily on UX polish: consistent spacing/typography, clear inline error messages, and “no surprises” interactions. For example, long actions were always accompanied by a visible loading state, and success states were reflected immediately through UI refreshes or optimistic updates (when safe) rather than leaving the user guessing.
State management & accessibility (ARIA)
I collaborated on frontend state handling so complex, table-driven workflows stayed predictable across loading, filtering, inline edits, and error cases.
Instead of scattering request logic across components, I helped standardize state transitions (idle → loading → success/error) and made sure failures surfaced cleanly without leaving the UI in inconsistent states.
I also contributed accessibility improvements by adding/adjusting ARIA attributes and improving keyboard and screen-reader friendliness in interactive components (dialogs, form controls, tables), so the UI remained usable beyond mouse-only flows.
Integrating Vue/Quasar with Spring Boot APIs
A big part of shipping features was connecting the UI to Spring Boot endpoints cleanly. I treated the API boundary as a contract: request payloads were typed, validation behavior was anticipated, and error responses were mapped to user-facing messages instead of generic failures.
On the frontend, I structured calls so that components didn’t become a mess of chained promises: I centralized request logic, standardized response handling, and made sure UI state stayed correct under retries or slow responses.
On the backend side, I worked with service-layer patterns where controller endpoints delegate to business logic services. This made it easier to test, easier to reason about, and reduced the risk of accidentally mixing UI concerns with business logic.
Performance: how I cut latency ~30%
Some pages and workflows felt slow primarily because certain API calls were doing too much work per request—often caused by heavy SQL queries, inefficient joins, or over-fetching data that the UI didn’t actually need.
My approach was systematic: I first reproduced the slow behavior, identified the exact endpoint(s) responsible, and then traced the performance issue down to the database layer by examining the queries being executed. From there, I iterated on improvements and re-measured to confirm the effect.
The optimizations came from practical changes: tightening queries to fetch only what was needed, improving filtering logic so the DB could do the work efficiently, and ensuring the query plan wasn’t doing unnecessary scans. Where appropriate, I worked with indexing/SQL structure improvements and verified that results stayed identical.
In parallel, I supported a webhook-driven async processing approach for workflows that included long-running operations. The idea was to keep the UI responsive by moving heavy work off the critical path: the API triggers processing, returns quickly, and the UI updates when completion events arrive. This reduced perceived waiting time and helped the product feel more responsive under load.
Combined, these changes reduced latency on key endpoints by roughly ~30% and improved the overall responsiveness of the flows users care about most.
Reliability: how I raised test coverage to ~90%
Because this was a production system, I treated testing as part of shipping. When changes touch service logic, the worst outcome isn’t a compile error—it’s a regression that breaks a real workflow after deployment.
I wrote and maintained unit tests using JUnit and Mockito focused on the service layer. The goal was to test behavior, not implementation details: input validation, edge cases, permission checks, and the correctness of the returned results.
I structured tests to be readable and resilient: clean setup with small fixtures, mocking external dependencies (repositories/services) only where necessary, and assertions that verify outcomes (returned values, updates performed, exceptions thrown) instead of brittle internal calls.
I also targeted test coverage strategically: I focused on the parts that historically break or are easy to break—complex branching logic, data transformation steps, and integration-like service flows. That effort raised coverage to ~90% on the areas I owned and significantly reduced regression risk.
What I learned
This internship taught me how to ship in a real product environment: build features that are pleasant to use, keep the API boundaries clean, measure performance instead of guessing, and leave the codebase safer than you found it.
More than that, I especially learned how to think end-to-end across the stack. It’s not enough to make a UI change if the backend can’t support it with good performance, and it’s not enough to optimize a backend path if the tests don’t protect the behavior from drifting later. The best engineers I worked with had a holistic mindset: they cared about the entire system and made sure their changes were solid from the database all the way to the user’s screen.
Those engineers taught how to work with an Agile mindset: break work into small, testable pieces; iterate based on feedback; and prioritize the user experience while keeping technical health in mind. I also saw how important it is to communicate clearly with teammates and between teams: whether it’s clarifying requirements, discussing design trade-offs, or sharing knowledge about the system, good communication is key to shipping well.
My biggest improvement was learning to think end-to-end: UX changes are only “done” when the backend performance supports them, and performance fixes are only “done” when tests protect the behavior from drifting later.