Introduction
This project is a simplified tax filing application built to mirror the tech stack and architecture of the Intuit TurboTax Tax Filing team.
What This Project Covers
- Backend: A Spring Boot (Java 21) service that orchestrates tax return submissions, saves returns to PostgreSQL, and simulates handing off filing data to a downstream e-Filing service.
- Frontend: A React application providing a tax return form, a “Finish and File” review/print experience, and basic agent-facing views.
- Infrastructure: Redis for caching, Kubernetes for deployment, and Maven for builds.
Mapping to the Real Team
| This Project | TurboTax Tax Filing Team |
|---|---|
| Tax return CRUD API | Backend orchestration of tax returns |
| Simulated e-Filing handoff | Sending data to the EFE (e-Filing) team |
| Print/download return | “Finish and File” print experiences |
| React frontend | AppFabric-based dynamic experiences |
| Kubernetes deployment | IKS (Intuit Kubernetes Service) |
| Maven build | Maven + Jenkins CI/CD |
Development Environment
Prerequisites
| Tool | Version | Purpose |
|---|---|---|
| Java (JDK) | 25+ | Backend runtime |
| Maven | 3.9+ | Build and dependency management |
| Node.js | 20+ | Frontend runtime |
| npm/yarn | latest | Frontend package management |
| Docker | 24+ | Containerization |
| kubectl | 1.28+ | Kubernetes CLI |
| minikube | latest | Local Kubernetes cluster |
| PostgreSQL | 16+ | Database |
| Redis | 7+ | Cache |
| mdbook | latest | Documentation |
Installation
Java 25
# Arch Linux
sudo pacman -S jdk25-openjdk
# Verify
java --version
Maven
# Arch Linux
sudo pacman -S maven
# Verify
mvn --version
Node.js
# Arch Linux
sudo pacman -S nodejs npm
# Verify
node --version
npm --version
Docker
# Arch Linux
sudo pacman -S docker
sudo systemctl enable --now docker
sudo usermod -aG docker $USER
# Log out and back in for group change to take effect
PostgreSQL & Redis (via Docker)
No local installation needed. Run them as containers:
# PostgreSQL
docker run -d --name postgres \
-e POSTGRES_DB=intuit_crash_course \
-e POSTGRES_USER=dev \
-e POSTGRES_PASSWORD=dev \
-p 5432:5432 \
postgres:16
# Redis
docker run -d --name redis \
-p 6379:6379 \
redis:7
To stop/start later:
docker stop postgres redis
docker start postgres redis
Kubernetes (minikube)
# Arch Linux
sudo pacman -S minikube kubectl
# Start cluster
minikube start
Running the Project
Backend
cd backend
mvn spring-boot:run
The API will be available at http://localhost:8080.
Frontend
cd frontend
npm install
npm run dev
The app will be available at http://localhost:5173.
Documentation
cd doc
mdbook serve --open
IDE Setup
IntelliJ IDEA (recommended for Java/Spring Boot)
- Import as Maven project
- Set Project SDK to Java 25
- Install Spring Boot plugin
VS Code (for React frontend)
- Install extensions: ESLint, Prettier, ES7+ React snippets
- Install extension: Extension Pack for Java (if working on backend too)
Architecture
System Overview
+------------------+
| React Frontend |
| (Vite + React) |
+--------+---------+
|
| REST API
|
+--------v---------+
| Spring Boot API |
| (Java 25) |
+--+----------+----+
| |
+---------+ +----------+
| |
+-------v-------+ +---------v--------+
| PostgreSQL | | Redis |
| (persistence) | | (cache) |
+----------------+ +------------------+
Components
Backend (Spring Boot)
The backend is a REST API built with Spring Boot and Java 25. It is responsible for:
- Managing tax return data (CRUD operations)
- Orchestrating the filing workflow (save, validate, submit)
- Simulating the handoff to an e-Filing service (mimicking the EFE team)
- Generating printable/downloadable return documents
Key layers:
- Controller: REST endpoints
- Service: Business logic and orchestration
- Repository: Data access via Spring Data JPA
- Model/Entity: Domain objects mapped to database tables
Frontend (React)
The frontend provides:
- A tax return input form
- A “Finish and File” review and print experience
- Return status tracking
- An agent-facing view for filed return information
Database (PostgreSQL)
Stores tax return data, user information, and filing status history.
Cache (Redis)
Used for:
- Caching frequently accessed return data
- Session management
- Rate limiting (optional)
API Design
The API follows REST conventions:
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/returns | Create a new tax return |
| GET | /api/returns/{id} | Get a tax return by ID |
| GET | /api/returns | List all returns |
| PUT | /api/returns/{id} | Update a tax return |
| DELETE | /api/returns/{id} | Delete a tax return |
| POST | /api/returns/{id}/file | Submit a return for filing |
| GET | /api/returns/{id}/status | Get filing status |
| GET | /api/returns/{id}/print | Get printable return |
Backend
Overview
The backend is a Spring Boot application using Java 25 and Maven. It provides REST APIs for tax return management and filing orchestration.
Project Layout
backend/
src/
main/
java/com/example/taxfiling/
controller/ # REST controllers
service/ # Business logic
repository/ # Spring Data JPA repositories
model/ # Entity classes
dto/ # Data transfer objects
config/ # Spring configuration
exception/ # Custom exceptions and error handling
resources/
application.yml # Application configuration
pom.xml # Maven build file
Key Dependencies
spring-boot-starter-web- REST APIspring-boot-starter-data-jpa- Database accessspring-boot-starter-data-redis- Redis cachingspring-boot-starter-validation- Input validationspring-boot-starter-test- Testingpostgresql- PostgreSQL JDBC driverlombok- Boilerplate reduction
Configuration
Application configuration is in application.yml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/intuit_crash_course
username: ${DB_USERNAME}
password: ${DB_PASSWORD}
jpa:
hibernate:
ddl-auto: update
show-sql: true
data:
redis:
host: localhost
port: 6379
server:
port: 8080
Testing
# Run all tests
mvn test
# Run with coverage
mvn test jacoco:report
Spring Boot Basics
Project Structure
A file-by-file explanation of the Spring Boot project generated by Spring Initializr.
Project Tree
backend/
pom.xml # Maven build definition
mvnw # Maven wrapper script
.mvn/wrapper/
maven-wrapper.properties # Maven wrapper config
src/
main/
java/com/example/taxfiling/
TaxfilingApplication.java # Application entry point
controller/
HealthController.java # REST controller (we added this)
resources/
application.properties # Spring Boot configuration
static/ # Static files (HTML, CSS, JS) served directly
templates/ # Server-side templates (Thymeleaf, etc.)
test/
java/com/example/taxfiling/
TaxfilingApplicationTests.java # Test class
target/ # Build output (gitignored)
pom.xml - The Project Definition
POM stands for “Project Object Model”. It tells Maven everything about your project.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.5.0</version>
</parent>
Parent POM: Inherits from spring-boot-starter-parent, which pre-configures a lot of defaults (compiler settings, dependency versions, plugin configs). You don’t need to specify versions for most Spring dependencies because the parent manages them.
<properties>
<java.version>25</java.version>
</properties>
Java version: Tells the Maven compiler plugin to use Java 25.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Dependencies: “Starters” are curated dependency bundles:
spring-boot-starter-webpulls in Spring MVC, embedded Tomcat, Jackson (JSON), and everything needed for a REST API. This single line replaces dozens of individual dependency declarations.spring-boot-starter-testpulls in JUnit 5, Mockito, Spring Test, and other testing tools.<scope>test</scope>means it’s only available during testing, not in production.
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
Build plugin: Enables mvn spring-boot:run and packages the app into a fat JAR (a single .jar file containing your code + all dependencies + embedded Tomcat).
mvnw - Maven Wrapper
A shell script that downloads and runs a specific Maven version, so everyone on the team uses the same Maven version regardless of what’s installed locally. Use ./mvnw instead of mvn for reproducible builds. The version is configured in .mvn/wrapper/maven-wrapper.properties.
You already have Maven installed, so you can use either mvn or ./mvnw - they do the same thing.
TaxfilingApplication.java - Entry Point
@SpringBootApplication
public class TaxfilingApplication {
public static void main(String[] args) {
SpringApplication.run(TaxfilingApplication.class, args);
}
}
This is the entire application bootstrap. @SpringBootApplication is a shortcut that combines three annotations:
@Configuration- This class can define beans (objects managed by Spring)@EnableAutoConfiguration- Spring Boot automatically configures things based on your dependencies (e.g., it seesspring-boot-starter-weband sets up Tomcat + Spring MVC)@ComponentScan- Scans the current package and sub-packages for classes annotated with@Controller,@Service,@Repository, etc., and registers them automatically
SpringApplication.run() starts the embedded Tomcat server, initializes the Spring context, and your app is live.
HealthController.java - REST Controller
@RestController
public class HealthController {
@GetMapping("/")
public Map<String, String> hello() {
return Map.of("message", "Tax Filing API is running");
}
}
@RestController=@Controller+@ResponseBody. It tells Spring this class handles HTTP requests and return values are serialized directly to JSON (not rendered as a view template).@GetMapping("/")maps HTTP GET requests to/to this method.- The
Mapreturn value is automatically serialized to{"message":"Tax Filing API is running"}by Jackson (included viastarter-web).
Spring discovered this class automatically because it’s in a sub-package of com.example.taxfiling (where @ComponentScan starts).
application.properties - Configuration
spring.application.name=taxfiling
Currently minimal. This is where you configure database connections, server port, logging, etc. Spring Boot has sensible defaults for everything (e.g., port 8080), so you only override what you need. Can also be written as application.yml.
TaxfilingApplicationTests.java - Smoke Test
@SpringBootTest
class TaxfilingApplicationTests {
@Test
void contextLoads() {
}
}
@SpringBootTest starts the full application context. The contextLoads() test has no assertions - it passes as long as the application starts without errors. This catches configuration mistakes, missing beans, and circular dependencies early.
Run with: mvn test
target/ Directory
Generated by Maven when you build or run. Contains:
classes/- Compiled.classfiles and copied resourcestest-classes/- Compiled test classes*.jar- Packaged application (aftermvn package)
This directory is gitignored. Never commit it.
How It All Fits Together
- You run
mvn spring-boot:run - Maven compiles
src/main/java/**intotarget/classes/ - Maven calls
TaxfilingApplication.main() @SpringBootApplicationtriggers auto-configuration and component scanning- Spring finds
HealthControllervia@ComponentScan, registers it - Embedded Tomcat starts on port 8080
- HTTP GET
/hitsHealthController.hello(), returns JSON
Annotations
Annotations are the primary way you configure Spring Boot. Instead of XML config files, you put @Something on a class/method/field and Spring handles the rest.
How Annotations Work in Spring
Spring Boot starts up, scans your code for annotations, and builds an application context - a container of objects (called beans) that Spring manages. Annotations tell Spring:
- What objects to create
- How to wire them together
- How to map HTTP requests to code
Core Annotations
@SpringBootApplication
The root annotation on your main class. It’s a shortcut for three annotations:
// These two are equivalent:
@SpringBootApplication
public class TaxfilingApplication { }
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class TaxfilingApplication { }
| Annotation | What it does |
|---|---|
@Configuration | Marks this class as a source of bean definitions |
@EnableAutoConfiguration | Spring Boot guesses what you need based on dependencies (e.g., sees starter-web -> sets up Tomcat) |
@ComponentScan | Scans current package + sub-packages for annotated classes |
@Component and Its Specializations
@Component tells Spring: “create an instance of this class and manage it.” Spring provides specialized versions that work the same way but express intent:
@Component <-- generic Spring-managed bean
|-- @Controller <-- handles HTTP requests (returns views)
|-- @RestController <-- handles HTTP requests (returns JSON/data)
|-- @Service <-- business logic layer
+-- @Repository <-- data access layer
They all do the same thing at the core (register a bean), but:
@Repositoryadds automatic exception translation for database errors@RestControlleradds@ResponseBodyso return values become JSON- Using the right one makes your code self-documenting
Example of a typical layered architecture:
@RestController // handles HTTP
public class TaxReturnController {
private final TaxReturnService service;
// ...
}
@Service // business logic
public class TaxReturnService {
private final TaxReturnRepository repo;
// ...
}
@Repository // database access
public interface TaxReturnRepository extends JpaRepository<TaxReturn, Long> {
// ...
}
Dependency Injection Annotations
@Autowired
Tells Spring to inject a dependency. Spring finds a matching bean and passes it in.
@Service
public class TaxReturnService {
@Autowired
private TaxReturnRepository repo; // field injection
}
Constructor injection (preferred - no @Autowired needed if there’s only one constructor):
@Service
public class TaxReturnService {
private final TaxReturnRepository repo;
// Spring automatically injects the repo here
public TaxReturnService(TaxReturnRepository repo) {
this.repo = repo;
}
}
Constructor injection is preferred because:
- Fields can be
final(immutable) - Dependencies are explicit
- Easier to test (just pass mocks to the constructor)
@Bean
Defines a bean manually in a @Configuration class. Use this when you need to configure a third-party object that you can’t annotate with @Component.
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate(); // Spring manages this instance
}
}
@Value
Injects values from application.properties:
@Value("${spring.application.name}")
private String appName; // "taxfiling"
Web / REST Annotations
Request Mapping
@RestController
@RequestMapping("/api/returns") // base path for all methods in this class
public class TaxReturnController {
@GetMapping // GET /api/returns
public List<TaxReturn> list() { }
@GetMapping("/{id}") // GET /api/returns/42
public TaxReturn get(@PathVariable Long id) { }
@PostMapping // POST /api/returns
public TaxReturn create(@RequestBody TaxReturn taxReturn) { }
@PutMapping("/{id}") // PUT /api/returns/42
public TaxReturn update(@PathVariable Long id, @RequestBody TaxReturn taxReturn) { }
@DeleteMapping("/{id}") // DELETE /api/returns/42
public void delete(@PathVariable Long id) { }
}
Parameter Annotations
| Annotation | Source | Example |
|---|---|---|
@PathVariable | URL path | /returns/{id} -> @PathVariable Long id |
@RequestParam | Query string | /returns?status=filed -> @RequestParam String status |
@RequestBody | JSON request body | POST payload -> @RequestBody TaxReturn data |
@RequestHeader | HTTP header | Authorization: Bearer ... -> @RequestHeader String authorization |
Response Annotations
@PostMapping
@ResponseStatus(HttpStatus.CREATED) // returns 201 instead of default 200
public TaxReturn create(@RequestBody TaxReturn taxReturn) { }
JPA / Database Annotations
These map Java classes to database tables (you’ll use these when adding PostgreSQL):
@Entity // this class maps to a DB table
@Table(name = "tax_returns") // explicit table name
public class TaxReturn {
@Id // primary key
@GeneratedValue(strategy = GenerationType.IDENTITY) // auto-increment
private Long id;
@Column(nullable = false) // column constraint
private String taxpayerName;
@Enumerated(EnumType.STRING) // store enum as string, not ordinal
private FilingStatus status;
@CreationTimestamp // auto-set on insert
private LocalDateTime createdAt;
}
Validation Annotations
Used with spring-boot-starter-validation to validate request data:
public class TaxReturnRequest {
@NotBlank(message = "Name is required")
private String taxpayerName;
@Min(2020)
private int taxYear;
@Email
private String email;
}
// In controller - @Valid triggers validation
@PostMapping
public TaxReturn create(@Valid @RequestBody TaxReturnRequest request) { }
Testing Annotations
@SpringBootTest // start full application context
class TaxfilingApplicationTests {
@Test // marks a test method
void contextLoads() { }
}
@WebMvcTest(TaxReturnController.class) // test only the web layer
class TaxReturnControllerTest {
@Autowired
private MockMvc mockMvc; // simulates HTTP requests
@MockBean // replace real bean with a mock
private TaxReturnService service;
}
| Annotation | What it starts | Speed |
|---|---|---|
@SpringBootTest | Full application context | Slow |
@WebMvcTest | Only web layer (controllers) | Fast |
@DataJpaTest | Only JPA layer (repositories + DB) | Fast |
Annotation Quick Reference
Application: @SpringBootApplication
Beans: @Component, @Service, @Repository, @Controller, @RestController
Config: @Configuration, @Bean, @Value
Injection: @Autowired (or just constructor injection)
Web: @RequestMapping, @GetMapping, @PostMapping, @PutMapping, @DeleteMapping
Parameters: @PathVariable, @RequestParam, @RequestBody
Database: @Entity, @Table, @Id, @Column, @GeneratedValue
Validation: @Valid, @NotBlank, @Min, @Max, @Email
Testing: @SpringBootTest, @WebMvcTest, @DataJpaTest, @MockBean
Frontend
Overview
The frontend is a React application bootstrapped with Vite. It provides the user interface for creating, reviewing, and filing tax returns.
Project Layout
frontend/
src/
components/ # Reusable UI components
pages/ # Page-level components (routes)
services/ # API client functions
hooks/ # Custom React hooks
context/ # React context providers
types/ # TypeScript type definitions
App.tsx # Root component
main.tsx # Entry point
public/ # Static assets
package.json
vite.config.ts
Key Dependencies
react+react-dom- UI frameworkreact-router-dom- Client-side routingaxios- HTTP clienttypescript- Type safety
Pages
| Route | Page | Description |
|---|---|---|
/ | Home | Dashboard with return list |
/returns/new | New Return | Tax return input form |
/returns/:id | Return Detail | View a single return |
/returns/:id/review | Finish and File | Review and submit the return |
/returns/:id/print | Printable/downloadable return view |
Development
cd frontend
npm install
npm run dev
Building for Production
npm run build
Output goes to frontend/dist/.
Deployment
Overview
The application is containerized with Docker and deployed to Kubernetes. This mirrors Intuit’s use of IKS (Intuit Kubernetes Service) and CDD for deployments.
Docker
Backend
FROM eclipse-temurin:25-jre-alpine
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Frontend
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
Build Images
# Backend
cd backend && mvn clean package -DskipTests
docker build -t intuit-crash-course-backend .
# Frontend
cd frontend
docker build -t intuit-crash-course-frontend .
Kubernetes
Manifests live in the k8s/ directory.
Components
| Manifest | Resource |
|---|---|
backend.yaml | Deployment + Service for backend |
frontend.yaml | Deployment + Service for frontend |
postgres.yaml | StatefulSet + Service for DB |
redis.yaml | Deployment + Service for cache |
ingress.yaml | Ingress for routing |
Deploy to minikube
# Start cluster
minikube start
# Apply manifests
kubectl apply -f k8s/
# Check status
kubectl get pods
kubectl get services
# Access the app
minikube service frontend-service
Useful Commands
# View logs
kubectl logs -f deployment/backend
# Scale
kubectl scale deployment/backend --replicas=3
# Rollback
kubectl rollout undo deployment/backend