Full Stack Engineering Day 2
Backend Engineering Masterclass
Full Stack Engineering · Day 2

Backend Engineering Masterclass

Follow one request from the edge to Java code, business rules, data, security and production operations.

Java & Spring BootAPIsSecurityScalingEventsModernization
01

The backend is the brain—and the trust boundary.

A frontend presents possibilities. The backend decides what is actually allowed, applies business rules, coordinates data and returns a stable result.

Backend mental model from users through gateway, backend and data systems

Accept

Receive requests from web, mobile, partners or other services.

Decide

Authenticate, authorize, validate and execute domain rules.

Coordinate

Read or change databases, caches, queues and external APIs.

Explain

Return a contract: status, headers and a structured body.

Never trust a button being hidden in the UI. Every sensitive rule must be enforced again on the server.
02

A language runs code; a framework supplies the common machinery.

EcosystemRuntime / languageTypical frameworksCommon fit
JavaJVM / JavaSpring Boot, QuarkusLarge, long-lived enterprise systems
JavaScriptNode.js / TypeScriptExpress, NestJSWeb APIs and full-stack teams
PythonPythonFastAPI, Django, FlaskAPIs, automation and AI-heavy systems
.NETCLR / C#ASP.NET CoreMicrosoft-centered enterprise systems

Framework value

Routing, dependency injection, configuration, serialization, validation, security and database integration.

Node.js in one line

It brought the JavaScript engine outside the browser, allowing JavaScript to run server-side.

Selection rule

Prefer team competence, ecosystem maturity, workload fit and operability over fashion.

03

One HTTP request crosses several deliberate boundaries.

Lifecycle of one backend request
ClientGateway / filtersControllerServiceRepositoryDatabase
  1. The server accepts the connection and parses HTTP.
  2. Middleware attaches identity, correlation, limits and telemetry.
  3. The router selects a controller method.
  4. Input is deserialized and validated.
  5. The service executes the use case and business rules.
  6. The repository communicates with storage.
  7. The result is serialized into a status, headers and JSON body.
Failures also follow a contract. Convert internal exceptions into safe, useful client errors; do not expose stack traces or secrets.
04

Separate transport, business decisions and persistence.

Controller service repository layered architecture
LayerOwnsIncident exampleAvoid
ControllerHTTP input/outputPOST /api/incidents → 201SQL and complex business rules
ServiceUse cases and policiesReject an invalid severity transitionHTTP-specific details
RepositoryPersistence queriesFind incidents by statusAuthorization decisions
Domain modelBusiness vocabulary and invariantsIncident, severity, statusFramework leakage where unnecessary
IncidentController.java
@RestController
@RequestMapping("/api/incidents")
class IncidentController {
  private final IncidentService service;

  @GetMapping
  List<Incident> list() { return service.findAll(); }

  @PostMapping
  ResponseEntity<Incident> create(@Valid @RequestBody CreateIncident request) {
    return ResponseEntity.status(201).body(service.create(request));
  }

  @DeleteMapping("/{id}")
  ResponseEntity<Void> delete(@PathVariable long id) {
    service.delete(id);
    return ResponseEntity.noContent().build();
  }
}
IncidentService.java
@Service
class IncidentService {
  private final IncidentRepository repository;

  Incident create(CreateIncident input) {
    // Business policy belongs here, not in the browser.
    if (input.severity() == Severity.P0 && input.owner() == null)
      throw new ValidationException("P0 incidents require an owner");
    return repository.save(Incident.from(input));
  }
}
05

Keep durable state outside replaceable application processes.

Database

Authoritative business records such as incidents and users.

Cache

Derived, temporary data that can usually be recreated.

Token or session store

Identity context carried by the client or shared across instances.

A stateless service can handle request 1 on instance A and request 2 on instance B. That is the foundation of reliable horizontal scaling.
06

REST models resources through HTTP.

A good URL names a resource. The HTTP method expresses the operation. Status codes explain the outcome.

MethodMeaningExampleTypical success
GETReadGET /api/incidents/42200 OK
POSTCreate / commandPOST /api/incidents201 Created
PUTReplacePUT /api/incidents/42200 or 204
PATCHPartially updatePATCH /api/incidents/42200 or 204
DELETERemoveDELETE /api/incidents/42204 No Content
CodeMeaningUse
400Bad RequestMalformed or invalid input
401UnauthenticatedIdentity is missing or invalid
403ForbiddenIdentity is known but not allowed
404Not FoundResource does not exist or is concealed
409ConflictState conflict or duplicate
429Too Many RequestsRate limit exceeded
500Server ErrorUnexpected internal failure
07

An API is a contract, not a database exposed over HTTP.

Resource shape

Expose what consumers need. Use DTOs so internal tables and fields can evolve.

Query design

Filter, sort and paginate: ?status=OPEN&page=0&size=20.

Error shape

Return a stable code, safe message, field errors and correlation ID.

A useful response contract
HTTP/1.1 201 Created
Location: /api/incidents/42
Content-Type: application/json

{
  "id": 42,
  "title": "Payment API latency",
  "severity": "P1",
  "status": "OPEN",
  "createdAt": "2026-08-28T10:15:00Z"
}
Do not return every row forever. Pagination, maximum page size and bounded filters are part of availability design.
08

Choose the communication style that fits the boundary.

Comparison of REST gRPC and server rendered applications
StyleBest fitStrengthTrade-off
REST + JSONPublic APIs, browsers, mobileSimple, ubiquitous, inspectableLarger payloads and looser contracts
gRPC + ProtobufInternal service-to-service callsTyped contracts, efficient binary transportMore tooling; browser use is less direct
Server-rendered HTMLContent-heavy or simpler applicationsServer sends ready HTMLDifferent interaction model from a rich SPA
Marshalling converts an in-memory object into JSON, Protobuf or another wire format. Unmarshalling converts the received bytes back into a usable object.
09

Stable contracts let teams change independently.

OpenAPI

Machine-readable endpoints, schemas, authentication and responses; tools can render Swagger UI or generate clients.

Compatibility

Add optional fields safely. Avoid changing meaning, type or required behavior unexpectedly.

Versioning

Use a new version for breaking changes, and publish migration and retirement plans.

OpenAPI excerpt
paths:
  /api/incidents:
    post:
      summary: Create an incident
      responses:
        '201': { description: Created }
        '400': { description: Invalid request }
        '401': { description: Authentication required }
Internal APIs still need contracts. “Internal” changes the audience; it does not remove consumers.
10

API security is defense in depth.

API security defense in depth

Transport

HTTPS protects data in transit and verifies the server.

Identity

Authentication proves who is calling.

Permission

Authorization decides whether that principal may perform this action on this resource.

Input

Validate type, range, format, size and allowed values server-side.

Safe Spring Security shape
http.authorizeHttpRequests(auth -> auth
    .requestMatchers(HttpMethod.GET, "/api/incidents/**").authenticated()
    .requestMatchers(HttpMethod.DELETE, "/api/incidents/**").hasRole("ADMIN")
    .anyRequest().denyAll());
The workshop API uses HTTP Basic and demo credentials only to make security behavior visible. Production systems should use a proper identity provider, TLS, secret management and short-lived credentials.
11

Sessions and tokens carry identity in different ways.

ApproachHow it worksUseful whenWatch for
Server sessionCookie references server-side stateTraditional web applicationsShared session storage and CSRF
Access tokenClient sends a bearer tokenAPIs, mobile and distributed systemsExpiry, audience, storage and revocation
OAuth 2.0Delegated authorization flowsApplications accessing protected APIsChoose the correct flow; OAuth is not itself login
OpenID ConnectIdentity layer on OAuth 2.0Login and SSOValidate issuer, audience, nonce and signatures
UserIdentity providerAccess tokenAPI validatesPolicy authorizes
A valid token answers “who issued this identity?” It does not automatically mean the caller may access every record.
12

Safe APIs survive abuse, retries and hostile input.

Rate limiting

Protect capacity with a per-user, API key or IP budget. Return 429 and retry guidance.

Idempotency

A repeated create request with the same idempotency key returns the original result instead of duplicating work.

Parameterized SQL

Keep code and values separate so input cannot become executable SQL.

Unsafe versus safe query
// UNSAFE: input changes SQL meaning
String sql = "SELECT * FROM incidents WHERE title LIKE '%" + term + "%'";

// SAFE: the driver binds input as data
String sql = "SELECT * FROM incidents WHERE title LIKE ?";
jdbcTemplate.query(sql, mapper, "%" + term + "%");
Demo requestExpected resultLesson
Unsafe search: ' OR '1'='1Returns all rowsString concatenation changed the query
Safe search: same textReturns no matchesThe payload remained a value
16+ rapid calls429 Too Many RequestsCapacity is bounded
13

Scale by finding the bottleneck, not by guessing.

Stateless backend horizontal scaling

Vertical

Add CPU or memory to one machine. Simple, but it has an upper bound and larger failure impact.

Horizontal

Add instances behind a load balancer. Requires stateless processes and coordinated shared dependencies.

Measure

Track throughput, error rate, P50/P95 latency, saturation and dependency time.

A slow API may be waiting on SQL, locks, external APIs, connection pools, CPU or serialization. More application instances can make an overloaded database worse.
14

Containers package; orchestration operates.

Docker image

Application, runtime and dependencies packaged into a repeatable artifact.

Container

A running, isolated process created from the image.

Kubernetes

Schedules replicas, provides service discovery, health checks, rolling releases and recovery.

Minimal Java container
FROM eclipse-temurin:21-jre
COPY target/incident-api.jar app.jar
USER 10001
ENTRYPOINT ["java", "-jar", "/app.jar"]
Kubernetes does not repair poor service boundaries, unsafe state or missing observability. It automates the operation of containers.
15

A cache trades freshness and complexity for speed.

GET incident 42Check RedisHit: return/Miss: DB → cache → return
QuestionDesign decision
What is cached?Derived, expensive-to-read data—not every value
How long?TTL based on acceptable staleness
What is the key?Include tenant, permissions and relevant query dimensions
How is it invalidated?Expire, update or delete after authoritative changes
What if Redis fails?Fallback behavior must protect the database from a stampede
Caching authorization-sensitive responses under the wrong key can leak one user’s data to another.
16

A monolith and microservices are deployment choices—not maturity levels.

Monolith microservices and event broker comparison
ShapeStrengthCostGood starting point
Modular monolithSimple deployment, calls and transactionsShared release and scale boundaryMost new products and smaller teams
MicroservicesIndependent ownership, release and scalingNetwork failures, eventual consistency, observability and platform burdenClear bounded contexts with real independent needs
Microservices move complexity from code boundaries into the network and operations. Extract a service because evidence demands independence, not because the architecture diagram looks modern.
17

Queues decouple time; events decouple ownership.

Incident createdBrokerNotify team+Update analytics+Open audit record

Queue

Work waits until a consumer is ready. Useful for load leveling and background jobs.

Event stream

Durable ordered facts can be consumed by multiple independent readers.

Delivery reality

Duplicates and retries happen. Consumers should be idempotent; poison messages need a dead-letter path.

A broker improves decoupling but introduces eventual consistency. Design what users see while downstream work is still pending.
18

Modernize legacy systems one controlled seam at a time.

Legacy modernization roadmap
  1. Discover: map dependencies, data ownership, change frequency, risk and business value.
  2. Stabilize: add tests, telemetry and reliable deployment around the current system.
  3. Wrap: create a stable API or event seam.
  4. Strangle: route one bounded capability to a new implementation.
  5. Migrate data: backfill, reconcile, shadow-read or dual-write with care, then cut over.
  6. Retire: remove old paths only after evidence, rollback planning and stakeholder sign-off.
Cloud migration is not automatically modernization. Rehosting may reduce data-center work; redesigning changes architecture and carries greater risk and opportunity.
19

Test the behavior and observe the production journey.

Unit test

Fast checks of service rules with dependencies replaced.

Integration test

Real framework, database, serialization and security boundaries.

Contract test

Confirms consumer and provider agree on the API shape.

End-to-end test

A few critical journeys across deployed components.

Service rule test
@Test
void p0RequiresOwner() {
  var request = new CreateIncident("Database down", Severity.P0, null);
  assertThrows(ValidationException.class, () -> service.create(request));
}
SignalQuestion answered
LogsWhat discrete event happened?
MetricsHow often and how much?
TracesWhere did one request spend time?
Audit recordsWho performed which sensitive action?
Coverage is evidence that code ran, not proof that the right behavior was asserted.
20

An AI capability is still a backend dependency.

ClientBackend policyPrompt / retrievalModelValidate response

Protect

Keep model keys server-side, authorize data retrieval and redact sensitive inputs.

Control

Set timeouts, budgets, model fallbacks and approval boundaries for side effects.

Observe

Measure quality, safety, latency, token cost, tool calls and business outcomes.

Do not let a browser call a privileged model or production tool directly. The backend remains the policy boundary.
21

Complete incident API blueprint.

The same small service can demonstrate routing, layers, data, security, safe SQL, rate limits, documentation, tests and operations.

JourneyExpectedConcept
GET /api/incidents200 + JSON listRead endpoint and serialization
POST /api/incidents201 + created recordValidation, service rule and persistence
DELETE without credentials401Authentication required
DELETE as permitted admin204Authorization and empty success body
Unsafe injection payloadIncorrectly returns rowsWhy concatenated SQL is dangerous
Safe injection payloadEmpty resultParameterized query
Rapid repeated traffic429 after limitRate limiting
Open Swagger UIInteractive contractOpenAPI documentation

The full request in one sentence

Client requestsGateway protectsController translatesService decidesRepository persistsTelemetry explains
Final mental model: backend engineering is the disciplined conversion of an untrusted request into a secure, correct, observable business outcome.

Architecture review checklist

  1. Who is calling, and how is identity verified?
  2. Which action and record is that principal allowed to access?
  3. Where are inputs validated and business rules enforced?
  4. Which store owns the truth, and which data is cached or derived?
  5. What happens when a dependency is slow, unavailable or called twice?
  6. Can one request be traced without exposing confidential data?
  7. Can the system scale horizontally and deploy safely?
  8. Is the API contract documented and backward compatible?