Front to Back: What Building a Full-Stack Application Really Taught Me

Most of my work has lived firmly on the frontend, interfaces, interactions, and user experience. So when I had the opportunity to work on a full-stack project, I didn’t think twice before jumping on the backend of things.
If you’ve followed my journey, you’ll know I’ve built plenty of frontend projects and maybe only one true full-stack application before this. That made this experience especially valuable not just technically, but in how it reshaped the way I think about systems as a whole.
Due to the nature of the work, I can’t share everything, but conceptually the application had functionality similar to Reddit:
User authentication and authorisation
Creating and viewing posts
Upvoting and downvoting content
Tech Stack
Frontend: Vanilla JavaScript, HTML, CSS
Backend: Java Spring Boot
Build Tool: Maven
Database: H2
API Testing: Postman
I chose to work on the backend deliberately. I’d been spending a lot of time on frontend work, and since my team at work was backend-focused, this was the perfect chance to sharpen those skills and understand what really happens behind the scenes.
Planning Under Pressure
We kicked things off with a structured plan to make sure we could deliver quickly and collaboratively.
Requirements were analysed to define an MVP
Tasks were broken down using a Kanban board
Daily stand-ups helped us track progress and unblock issues
The real challenge?
We had just five days to deliver and two of us missed the first two days due to illness. That meant less time, no room for indecision, and a need for very clear ownership.
We split the project into frontend and backend:
3 engineers on the frontend
2 engineers (including me) on the backend
Within the backend, we divided responsibilities into two clear domains:
User & Security
Messages & Voting
This separation allowed us to move fast without stepping on each other’s toes.
Design: Keeping It Simple
Before diving into code, I created a low-fidelity prototype in Figma. Nothing fancy just enough to communicate layout, flow, and intent. I shared it with the team, gathered quick feedback, and once everyone aligned, we moved straight into development. The goal wasn’t perfection, it was clarity.
Development: Building the Backbone
Since the database and language were already chosen, I started by translating requirements into clear API contracts especially around authentication and authorisation.
That meant defining:
Controllers
DTOs
Entities
Enums
Repositories
Custom exceptions
A dedicated security package
This upfront structure paid off quickly as the project scaled.
Architecture: A Layered System That Scales

A Layered Architecture with Clear Responsibilities
The backend follows a layered architecture, keeping concerns cleanly separated:
Controller Layer – Handles HTTP requests and responses
AuthController: registration, loginUserController: profile, updates, password changes
Service Layer – Business logic lives here
UserService: user operationsCustomUserDetailsService: Spring Security integration
Repository Layer – Data access via Spring Data JPA
UserRepository
Security Layer – JWT-based authentication
JwtTokenProviderJwtAuthenticationFilterSecurityConfig(including CORS rules)
Domain Layer – Core entities
UserRoleenum (USER,ADMIN)
DTO Layer – Clean API communication
Requests:
RegisterRequest,LoginRequest,ChangePasswordRequestResponses:
UserResponse,AuthResponse
This structure made the codebase easier to reason about, test, and extend even under tight deadlines.
Security: Stateless and Intentional
Security was treated as a first-class concern.
I implemented JWT-based authentication, keeping the system fully stateless:
Users log in
The server issues a signed JWT
Every protected request includes the token in the
AuthorizationheaderThe backend validates the token and authorises access
No sessions. No server-side state. Clean and scalable.
Validation & Error Handling
Inputs were validated thoroughly:
Email format
Password strength
Password confirmation matching
When something failed, the API returned clear, human-readable error messages. This improved frontend UX and made testing significantly easier.
Testing: Confidence Before Demo Day
Testing wasn’t an afterthought it was part of development.
Unit Tests
Focused on business logic:
Duplicate email validation
Password checks
Safe response mapping
Integration Tests
End-to-end testing of:
Controllers
Services
Repositories
Security filters
This ensured the entire request pipeline worked as expected not just individual pieces.
Postman: The Human Test
Postman was invaluable for manual testing and demos:
Registration
Login (token generation)
Protected endpoints
A Real-World Gotcha (403 in the Spotlight)
During the presentation/demo, I registered a new user but forgot to update the token in Postman. I then tried accessing a protected endpoint with the old user’s token.
Result?
403 Forbidden.
Lesson learned:
JWTs are user-specific. Switch users → switch tokens.
Pro tips:
Use Postman environments (
{{token}},{{baseUrl}})Automatically update tokens after login
Separate environments for different users
Connecting Frontend to Backend
At its core, the connection is simple: HTTP requests from JavaScript.
Signup/Login: frontend sends credentials, backend responds with a message or JWT
Authenticated requests: token sent via
Authorization: Bearer <token>Error handling:
401→ missing or invalid token403→ valid token, wrong permissions or wrong user
This is a high level explanation of the connection from front to back but understanding what actually happens at each step is what turns “I can build” into “I understand systems.”
Here’s the general flow:
1. The Frontend Initiates a Request
Everything starts in the browser.
When a user:
Signs up
Logs in
Creates a post
Upvotes content
…the frontend (JavaScript) sends an HTTP request to the backend API using fetch or similar tools.
Each request includes:
A URL (e.g.
/api/auth/login)An HTTP method (
GET,POST,PUT,DELETE)Optional headers (like
Content-TypeorAuthorization)Optional body data (JSON payload)
2. The Backend Receives and Routes the Request
On the backend side:
The request hits a controller endpoint
Spring Boot maps the URL and HTTP method to the correct controller method
Request data is parsed into DTOs
At this stage, the backend decides:
Is this endpoint public or protected?
Does the request include a valid token?
Is the user allowed to perform this action?
3. Authentication & Authorisation (JWT Flow)
For protected endpoints, this is where JWT authentication comes into play.
Login flow:
Frontend sends email + password
Backend validates credentials
Backend generates a JWT
JWT is returned to the frontend
Subsequent requests:
Frontend attaches the token to the request:
Authorization: Bearer <token>Backend validates the token on every request
If valid → request proceeds
If missing/invalid →
401 UnauthorizedIf valid but insufficient permissions →
403 Forbidden
This keeps the backend stateless, scalable, and secure.
4. Business Logic & Data Access
Once authorised:
Controllers pass control to services
Services handle business rules
Repositories interact with the database
Entities are mapped and persisted
The backend then constructs a response DTO, ensuring:
Sensitive data (like passwords) is never exposed
Only relevant fields are returned
5. Response Back to the Frontend
The backend sends a structured response:
Success →
200 OK/201 CreatedFailure → appropriate error code + message
The frontend then:
Updates the UI
Stores tokens if needed
Shows feedback to the user (success or error)
6. CORS: The Silent Middleman
During development, frontends and backends often run on different origins (e.g. different ports on localhost).
Without proper CORS configuration, browsers block requests even if the backend is working perfectly.
By explicitly allowing trusted origins and headers on the backend, the frontend can communicate freely without security issues.
Token Storage Trade-offs
For this project, I kept things simple with bearer tokens. Other approaches like HTTP-only cookies offer stronger XSS protection but add complexity. Each option has trade-offs depending on context.
Final Thoughts
This project reminded me that backend development isn’t just about endpoints, it’s about:
Designing systems under pressure
Making security intentional
Writing code that others can understand
Thinking beyond “does it work?” to “will it scale?”
Stepping away from the frontend and into the backend gave me a much deeper appreciation of how full-stack systems truly come together from front to back.



