A full-stack intern-level demo project for an insurance internship interview.
This project follows a classic three-tier architecture with a strict separation of concerns between frontend, backend, and database.
The Angular frontend runs in the user's browser and is responsible entirely for display logic. It never touches a database directly. Instead, it calls a REST API over HTTP using Angular's HttpClient. All API communication is centralised in Angular services (PolicyService, ClaimService), keeping components clean and focused on rendering. Angular's Router maps URL paths to components, giving the app multiple pages without a full page reload.
The Spring Boot backend exposes three REST endpoints (GET /policies, GET /claims, POST /claims). Internally it follows the industry-standard Controller → Service → Repository layered pattern: controllers handle HTTP, services contain business rules, repositories talk to the database. DTOs (Data Transfer Objects) sit at the API boundary — they control exactly what fields the frontend sees, preventing accidental leakage of internal database columns. JPA + Hibernate maps Java classes to SQL tables automatically based on @Entity annotations, so no manual SQL DDL is needed. For the demo, an H2 in-memory database is used (zero installation), seeded with realistic data at startup via data.sql. Switching to PostgreSQL for production requires only a one-line change in application.yml.
insurance-portal/
├── .github/
│ └── workflows/
│ └── ci.yml ← GitHub Actions CI pipeline
│
├── backend/ ← Spring Boot project (Java 17)
│ ├── pom.xml ← Maven dependencies
│ └── src/
│ ├── main/
│ │ ├── java/com/insurance/portal/
│ │ │ ├── InsurancePortalApplication.java ← Main entry point
│ │ │ ├── controller/
│ │ │ │ ├── PolicyController.java
│ │ │ │ └── ClaimController.java
│ │ │ ├── service/
│ │ │ │ ├── PolicyService.java
│ │ │ │ └── ClaimService.java
│ │ │ ├── repository/
│ │ │ │ ├── UserRepository.java
│ │ │ │ ├── PolicyRepository.java
│ │ │ │ └── ClaimRepository.java
│ │ │ ├── entity/
│ │ │ │ ├── User.java
│ │ │ │ ├── Policy.java
│ │ │ │ └── Claim.java
│ │ │ └── dto/
│ │ │ ├── PolicyResponseDto.java
│ │ │ ├── ClaimRequestDto.java
│ │ │ └── ClaimResponseDto.java
│ │ └── resources/
│ │ ├── application.yml ← Config: port, H2 URL, JPA settings
│ │ └── data.sql ← Seed data (runs at startup)
│ └── test/
│ └── java/com/insurance/portal/
│ └── InsurancePortalApplicationTests.java
│
└── frontend/ ← Angular 17 project
├── angular.json
├── package.json
├── tsconfig.json
└── src/
├── index.html
├── main.ts
├── styles.css ← Global styles + shared badge/table CSS
├── environments/
│ └── environment.ts ← API base URL config
└── app/
├── app.module.ts ← Root module (registers all components)
├── app-routing.module.ts ← URL → component mapping
├── app.component.* ← Shell: nav bar + <router-outlet>
├── models/
│ ├── policy.model.ts
│ └── claim.model.ts
├── services/
│ ├── policy.service.ts
│ └── claim.service.ts
└── components/
├── dashboard/ ← Summary cards + recent claims
├── policy-list/ ← All policies in a card grid
├── claim-form/ ← Reactive form for submitting claims
└── claim-list/ ← Full claims table with status badges
cd backend
./mvnw spring-boot:run
# API available at http://localhost:8080/api
# H2 console at http://localhost:8080/h2-consolecd frontend
npm install
ng serve
# App available at http://localhost:4200-- Hibernate generates these tables from @Entity annotations
CREATE TABLE app_user (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
name VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE
);
CREATE TABLE policy (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
policy_number VARCHAR(255) NOT NULL UNIQUE,
type VARCHAR(255) NOT NULL, -- AUTO, HOME, LIFE, HEALTH
status VARCHAR(255) NOT NULL, -- ACTIVE, EXPIRED, CANCELLED
user_id BIGINT NOT NULL REFERENCES app_user(id)
);
CREATE TABLE claim (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
policy_id BIGINT NOT NULL REFERENCES policy(id),
description VARCHAR(1000) NOT NULL,
status VARCHAR(255) NOT NULL, -- SUBMITTED, UNDER_REVIEW, APPROVED, REJECTED
created_at TIMESTAMP NOT NULL
);| Method | Endpoint | Request Body | Response |
|---|---|---|---|
| GET | /api/policies | — | PolicyResponseDto[] |
| GET | /api/claims | — | ClaimResponseDto[] |
| POST | /api/claims | { policyId, description } |
ClaimResponseDto (201) |
Opening (30 seconds):
"I built an Insurance Self-Service Portal where customers can view their policies and file claims. It's a full-stack project with an Angular frontend and a Spring Boot REST API backed by a SQL database."
Frontend explanation (60 seconds):
"The Angular app has four pages — a dashboard, a policy list, a claim submission form, and a claims tracker. I used Angular Reactive Forms for the claim form because they make validation logic cleaner and easier to test. All HTTP calls live in dedicated services, so components only handle display logic. Angular's Router manages navigation without page reloads."
Backend explanation (90 seconds):
"The Spring Boot API follows the Controller → Service → Repository pattern. Controllers receive HTTP requests and return HTTP responses. Services contain the business rules — for example, a claim can only be filed against an existing policy, and the status always starts as SUBMITTED. Repositories are Spring Data JPA interfaces — I don't write SQL; Spring generates it from method names like findByUserId(). I also use DTOs at the API boundary to control exactly what the frontend sees, which is a security and maintainability best practice."
Database explanation (30 seconds):
"JPA automatically creates the tables from my @Entity annotations. For local development I use H2, an in-memory database — it starts instantly with no configuration. Switching to PostgreSQL for production requires one line in application.yml."
CI explanation (30 seconds):
"I set up a GitHub Actions pipeline that triggers on every pull request. It installs Java, runs mvn test, and uploads the test report. This ensures no broken code can be merged without the build passing."
Closing:
"The main thing I'd highlight is the separation of concerns — each layer has exactly one responsibility, which makes the code easy to test, change, and explain."
| Priority | Improvement | Why |
|---|---|---|
| High | JWT Authentication | Currently any user can see all data. In production, a JWT token would be issued on login and validated in a Spring Security filter, scoping each request to the authenticated user. |
| High | Input Validation | Add @Valid + @NotBlank / @Size annotations on DTOs and return structured 400 Bad Request responses instead of raw exceptions. |
| Medium | Switch to PostgreSQL | H2 is convenient for demos but doesn't behave identically to production databases. One line change in application.yml. |
| Medium | Frontend error handling | Add a global Angular HTTP interceptor to catch 401/500 errors and show user-friendly messages instead of just console errors. |
| Medium | Angular unit tests | Write Jasmine/Karma tests for the services (mock HttpClient) and components (use TestBed). |
| Low | Pagination | For large datasets, add Spring's Pageable to repositories and display paginated tables in the frontend. |
| Low | Azure deployment | Package the backend as a Docker container, push to Azure Container Registry, and deploy to Azure App Service. The Angular build output can be hosted on Azure Static Web Apps. |
| Low | Claim status updates | Add a PATCH /claims/{id}/status endpoint and an admin view where staff can advance claim status. |