diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..5f000d3
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,57 @@
+
+---
+
+# CHANGELOG.md
+
+```markdown id="changelog_final"
+# CHANGELOG
+
+---
+
+## [1.0.0] - 2026-05-25
+
+### Added
+- Implemented full Sequence Processing REST API using Spring Boot.
+- Added `/sequences/convert-measurements` endpoint for stream-based sequence computation.
+- Introduced stateful streaming algorithm for dynamic grouping of input characters.
+- Added Oracle Database persistence layer (SEQUENCE_HISTORY table).
+- Implemented full history management (GET, PUT, DELETE operations).
+- Added SLF4J logging for request tracing and debugging.
+- Added input validation for allowed characters (a-z and underscore `_`).
+
+### Changed
+- Refactored architecture to a clean layered design (Controller → Service → Repository).
+- Updated processing logic to support dynamic stream traversal instead of static parsing.
+- Improved grouping logic to support runtime state transitions.
+
+### Fixed
+- Fixed schema mismatch issues between Oracle CLOB and entity mappings.
+- Resolved Spring Boot ApplicationContext startup issues caused by schema validation conflicts.
+- Fixed history persistence inconsistencies in output formatting.
+
+---
+
+## [0.2.0] - 2026-05-24
+
+### Added
+- Introduced sequence processing service layer.
+- Added Oracle JPA repository integration.
+- Enabled automatic persistence of conversion results into database.
+
+---
+
+## [0.1.0] - 2026-05-23
+
+### Added
+- Initial implementation of REST API.
+- Basic sequence processing logic.
+- Simple endpoint for conversion testing.
+
+---
+
+## [0.0.1] - 2026-05-21
+
+### Added
+- Project initialization using Spring Boot.
+- Maven configuration setup.
+- Base REST controller structure created.
\ No newline at end of file
diff --git a/README.md b/README.md
index b1cccfd..9ecea13 100644
--- a/README.md
+++ b/README.md
@@ -1,61 +1,74 @@
-## Submission Instructions
-
-To submit your Oracle JAVA Spring Boot Maven project as a solution, please follow these steps:
-
-### Step 1: Install git on your PC
-- Install "git" as shown in this tutorial: [How to install git](https://youtu.be/iYkLrXobBbA?si=_l0haibv_X9NpIjJ)
-- Open command prompt and run
- ```bash
- git version
- ```
-- If you see the version, then git is successfully installed.
-
-### Step 2: Fork the Repository
-- Navigate to [this repository](https://github.com/CodelineAtyab/oraclequantapi) provided by Codeline.
-- Click on the "Fork" button at the top-right corner of the page to create a copy of the repository under your own GitHub account.
-
-### Step 3: Clone the Forked Repository
-- Open your terminal or command prompt.
-- Clone the forked repository to your local machine using the following command:
- ```bash
- git clone https://github.com/your-username/repo-name.git
- ```
-
-### Step 4: Create a new branch
-- Navigate to the cloned repository directory
- ```bash
- cd repo-name
- ```
-- Create a new branch for your code submissions (Replace your-name with your name in your-name-submission-branch):
- ```bash
- git checkout -b your-name-submission-branch
- ```
-
-
-### Step 5: Add Your Code
-- Implement the API
-
-### Step 6: Commit your changes
-- Run the following commands in order to commit your changes:
- ```bash
- git add *
- git commit -m "Meaningful commit message here"
- ```
-
-### Step 7: Push Your Branch to GitHub
-- Run the following commands to upload the changes to the forked github repository (Replace your-name with your name in your-name-submission-branch):
- ```bash
- git push origin your-name-submission-branch
- ```
-
-### Step 8: Create a Pull Request
-- Go to your forked repository on GitHub.
-- You should see a prompt to create a pull request. Click on "Compare & pull request".
-- Provide a title and description for your pull request, then click "Create pull request".
-
-### Step 9: Notify Codeline
-- Notify on slack that you have created a PR for your solution.
-
-## Note: If you face any issues in the process above, Please do the following:
-- Watch [this youtube tutorial](https://www.youtube.com/watch?v=a_FLqX3vGR4)
-- Contact Ikhlas or Atyab.
+# Oracle Quant Sequence API
+
+## Overview
+This is a Spring Boot REST API that processes input character sequences using a custom stateful streaming algorithm.
+
+The system converts sequences into numeric package results, applies dynamic grouping logic based on control characters, and persists all transactions into an Oracle Database.
+
+---
+
+## Core Concept
+The algorithm processes input as a **stream of characters**, not static chunks.
+
+- The character `z` acts as a **control/boundary modifier**
+- The character `_` is treated as **neutral (value = 0)**
+- Processing is based on **stateful traversal and lookahead accumulation**
+- Groups are dynamically formed during runtime execution
+
+---
+
+## Tech Stack
+- Java 17+
+- Spring Boot
+- Spring Web
+- Spring Data JPA
+- Oracle Database (XE / XEPDB1)
+- SLF4J Logging
+- Maven
+
+---
+
+## Base URL
+
+
+http://localhost:8080/sequences
+
+
+---
+
+## API Endpoints
+
+### 1. Convert Measurements
+Processes a sequence and returns computed package totals.
+
+
+GET /sequences/convert-measurements?input=abbcc
+
+
+**Example Response**
+```json
+[2, 6]
+2. Get All History
+GET /sequences/history
+3. Get History By ID
+GET /sequences/history/{id}
+4. Update History
+PUT /sequences/history/{id}
+
+Body
+
+{
+ "input": "abc",
+ "output": "[2,6]",
+ "sourceIpAddress": "127.0.0.1"
+}
+5. Delete All History
+DELETE /sequences/history
+6. Delete History By ID
+DELETE /sequences/history/{id}
+ # Algorithm Behavior
+Input is processed as a continuous stream
+z acts as a state modifier / boundary controller
+_ contributes value 0 without breaking flow
+Output is generated using dynamic grouping + lookahead accumulation
+Final result is a list of computed package totals
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 20909d2..cdd8302 100644
--- a/pom.xml
+++ b/pom.xml
@@ -34,7 +34,15 @@
org.springframework.boot
spring-boot-starter-web
-
+
+ org.springframework.boot
+ spring-boot-starter-data-jpa
+
+
+ com.oracle.database.jdbc
+ ojdbc11
+ runtime
+
org.springframework.boot
spring-boot-starter-test
diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/controllers/SequenceController.java b/src/main/java/com/oraclequantapi/oraclequantapi/controllers/SequenceController.java
new file mode 100644
index 0000000..c813ffb
--- /dev/null
+++ b/src/main/java/com/oraclequantapi/oraclequantapi/controllers/SequenceController.java
@@ -0,0 +1,139 @@
+package com.oraclequantapi.oraclequantapi.controllers;
+import com.oraclequantapi.oraclequantapi.models.Sequence;
+import com.oraclequantapi.oraclequantapi.models.SequenceHistory;
+import com.oraclequantapi.oraclequantapi.services.SequenceService;
+import jakarta.servlet.http.HttpServletRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@RestController
+@RequestMapping("/sequences")
+public class SequenceController {
+ private static final Logger log = LoggerFactory.getLogger(SequenceController.class);
+
+ private final SequenceService service;
+
+ public SequenceController(SequenceService service) {
+ this.service = service;
+ }
+
+ // =========================
+ // CONVERT ENDPOINT
+ // =========================
+ @GetMapping("/convert-measurements")
+ public ResponseEntity> convertMeasurements(
+ @RequestParam("input") String input,
+ HttpServletRequest request) {
+
+ String sourceIp = request.getRemoteAddr();
+
+ log.info("Conversion request - input: \"{}\", source IP: {}", input, sourceIp);
+
+ Sequence sequence = new Sequence(input);
+
+ if (!sequence.is_valid()) {
+ log.warn("Invalid input received: \"{}\"", input);
+ return ResponseEntity.badRequest().build();
+ }
+
+ List result = service.process_sequence(sequence, sourceIp);
+
+ log.info("Conversion result - input: \"{}\", output: {}", input, result);
+
+ return ResponseEntity.ok(result);
+ }
+
+ // =========================
+ // HISTORY - GET ALL
+ // =========================
+ @GetMapping("/history")
+ public ResponseEntity> getAllHistory() {
+
+ log.info("Fetching all history records");
+
+ List records = service.getAllHistory();
+
+ log.info("Fetched {} history records", records.size());
+
+ return ResponseEntity.ok(records);
+ }
+
+ // =========================
+ // HISTORY - GET BY ID
+ // =========================
+ @GetMapping("/history/{id}")
+ public ResponseEntity getHistoryById(@PathVariable Long id) {
+
+ log.info("Fetching history record by id: {}", id);
+ return service.getHistoryById(id).map(record -> {
+ log.info("Found history record: {}", id);
+ return ResponseEntity.ok(record);
+ })
+ .orElseGet(() -> {
+ log.warn("History record not found: {}", id);
+ return ResponseEntity.notFound().build();
+ });
+ }
+
+ // =========================
+ // HISTORY - UPDATE
+ // =========================
+ @PutMapping("/history/{id}")
+ public ResponseEntity updateHistory(
+ @PathVariable Long id,
+ @RequestBody SequenceHistory record) {
+
+ log.info("Updating history record: {}", id);
+
+ try {
+ SequenceHistory updated = service.updateHistory(id, record);
+ log.info("Updated history record: {}", id);
+ return ResponseEntity.ok(updated);
+
+ } catch (RuntimeException e) {
+ log.warn("Update failed - record not found: {}", id);
+ return ResponseEntity.notFound().build();
+ }
+ }
+
+ // =========================
+ // HISTORY - DELETE ALL
+ // =========================
+ @DeleteMapping("/history")
+ public ResponseEntity clearHistory() {
+
+ log.info("Clearing all history records");
+
+ service.deleteHistory();
+
+ log.info("All history records cleared");
+
+ return ResponseEntity.noContent().build();
+ }
+
+ // =========================
+ // HISTORY - DELETE BY ID (ADDED like sample solution)
+ // =========================
+ @DeleteMapping("/history/{id}")
+ public ResponseEntity deleteHistoryById(@PathVariable Long id) {
+
+ log.info("Deleting history record: {}", id);
+
+ boolean exists = service.getHistoryById(id).isPresent();
+
+ if (!exists) {
+ log.warn("Delete failed - record not found: {}", id);
+ return ResponseEntity.notFound().build();
+ }
+
+ service.deleteHistoryById(id);
+
+ log.info("Deleted history record: {}", id);
+
+ return ResponseEntity.noContent().build();
+ }
+}
diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/models/Sequence.java b/src/main/java/com/oraclequantapi/oraclequantapi/models/Sequence.java
new file mode 100644
index 0000000..16a9ccd
--- /dev/null
+++ b/src/main/java/com/oraclequantapi/oraclequantapi/models/Sequence.java
@@ -0,0 +1,45 @@
+package com.oraclequantapi.oraclequantapi.models;
+import java.util.ArrayList;
+import java.util.List;
+public class Sequence {
+ private final List value;
+
+ public Sequence() {
+ this.value = new ArrayList<>();
+ }
+
+ public Sequence(String rawInput) {
+ this.value = new ArrayList<>();
+ set_value(rawInput);
+ }
+
+ public void set_value(String rawInput) {
+ this.value.clear();
+ if (rawInput != null) {
+ for (char ch : rawInput.toCharArray()) {
+ this.value.add(String.valueOf(ch));
+ }
+ }
+ }
+
+ public String get_value_as_str() {
+ return String.join("", this.value);
+ }
+
+ public boolean is_valid() {
+ if (this.value == null || this.value.isEmpty()) {
+ return false;
+ }
+ for (String s : this.value) {
+ char ch = s.charAt(0);
+ if ((ch < 'a' || ch > 'z') && ch != '_') {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public List getValue() {
+ return value;
+ }
+}
diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/models/SequenceHistory.java b/src/main/java/com/oraclequantapi/oraclequantapi/models/SequenceHistory.java
new file mode 100644
index 0000000..36cbfe0
--- /dev/null
+++ b/src/main/java/com/oraclequantapi/oraclequantapi/models/SequenceHistory.java
@@ -0,0 +1,73 @@
+package com.oraclequantapi.oraclequantapi.models;
+
+import jakarta.persistence.*;
+
+import java.time.LocalDateTime;
+
+@Entity
+@Table(name = "SEQUENCE_HISTORY")
+public class SequenceHistory {
+ @Id
+ @GeneratedValue(strategy = GenerationType.IDENTITY)
+ private Long id;
+
+ @Column(name = "TIMESTAMP", nullable = false)
+ private LocalDateTime timestamp;
+
+ @Column(name = "SOURCE_IP_ADDRESS", nullable = false)
+ private String sourceIpAddress;
+
+ @Lob
+ @Column(name = "INPUT_STRING")
+ private String input;
+
+ @Lob
+ @Column(name = "OUTPUT_STRING")
+ private String output;
+
+ public SequenceHistory() {
+ }
+
+ public SequenceHistory(LocalDateTime timestamp, String sourceIpAddress, String input, String output) {
+ this.timestamp = timestamp;
+ this.sourceIpAddress = sourceIpAddress;
+ this.input = input;
+ this.output = output;
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public LocalDateTime getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(LocalDateTime timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ public String getSourceIpAddress() {
+ return sourceIpAddress;
+ }
+
+ public void setSourceIpAddress(String sourceIpAddress) {
+ this.sourceIpAddress = sourceIpAddress;
+ }
+
+ public String getInput() {
+ return input;
+ }
+
+ public void setInput(String input) {
+ this.input = input;
+ }
+
+ public String getOutput() {
+ return output;
+ }
+
+ public void setOutput(String output) {
+ this.output = output;
+ }
+}
diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/repositories/SequenceHistoryRepository.java b/src/main/java/com/oraclequantapi/oraclequantapi/repositories/SequenceHistoryRepository.java
new file mode 100644
index 0000000..a786126
--- /dev/null
+++ b/src/main/java/com/oraclequantapi/oraclequantapi/repositories/SequenceHistoryRepository.java
@@ -0,0 +1,10 @@
+package com.oraclequantapi.oraclequantapi.repositories;
+
+import com.oraclequantapi.oraclequantapi.models.SequenceHistory;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public interface SequenceHistoryRepository extends JpaRepository {
+
+}
diff --git a/src/main/java/com/oraclequantapi/oraclequantapi/services/SequenceService.java b/src/main/java/com/oraclequantapi/oraclequantapi/services/SequenceService.java
new file mode 100644
index 0000000..6719b77
--- /dev/null
+++ b/src/main/java/com/oraclequantapi/oraclequantapi/services/SequenceService.java
@@ -0,0 +1,122 @@
+package com.oraclequantapi.oraclequantapi.services;
+
+import com.oraclequantapi.oraclequantapi.models.Sequence;
+import com.oraclequantapi.oraclequantapi.models.SequenceHistory;
+import com.oraclequantapi.oraclequantapi.repositories.SequenceHistoryRepository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+@Service
+public class SequenceService {
+ private static final Logger log = LoggerFactory.getLogger(SequenceService.class);
+ private final SequenceHistoryRepository repository;
+
+ public SequenceService(SequenceHistoryRepository repository) {
+ this.repository = repository;
+ }
+
+ public List process_sequence(Sequence sequence, String clientIp) {
+
+ List packageTotals = new ArrayList<>();
+ List chars = sequence.getValue();
+
+ int index = 0;
+ int n = chars.size();
+
+ while (index < n) {
+
+ int packageItemCount = getNextEncodedValue(chars, index);
+ index = moveIndexPastValue(chars, index);
+
+ if (packageItemCount == 0) {
+ packageTotals.add(0);
+ continue;
+ }
+
+ int currentPackageSum = 0;
+
+ for (int i = 0; i < packageItemCount; i++) {
+ if (index < n) {
+ int value = getNextEncodedValue(chars, index);
+ currentPackageSum += value;
+ index = moveIndexPastValue(chars, index);
+ }
+ }
+
+ packageTotals.add(currentPackageSum);
+ }
+
+ save_curr_seq(sequence.get_value_as_str(), packageTotals.toString(), clientIp);
+
+ return packageTotals;
+ }
+
+ private int getNextEncodedValue(List chars, int startIndex) {
+ int sum = 0;
+ int i = startIndex;
+
+ while (i < chars.size()) {
+ char ch = chars.get(i).charAt(0);
+ int val = (ch == '_') ? 0 : (ch - 'a' + 1);
+ sum += val;
+ i++;
+
+ if (ch != 'z') {
+ break;
+ }
+ }
+
+ return sum;
+ }
+
+ private int moveIndexPastValue(List chars, int startIndex) {
+ int i = startIndex;
+
+ while (i < chars.size()) {
+ char ch = chars.get(i).charAt(0);
+ i++;
+
+ if (ch != 'z') {
+ break;
+ }
+ }
+
+ return i;
+ }
+ public void deleteHistoryById(Long id) {
+ repository.deleteById(id);
+ }
+
+ private void save_curr_seq(String input, String output, String ip) {
+ SequenceHistory record = new SequenceHistory(LocalDateTime.now(), ip, input, output);
+
+ repository.save(record);
+ }
+
+ public List getAllHistory() {
+ return repository.findAll();
+ }
+
+ public Optional getHistoryById(Long id) {
+ return repository.findById(id);
+ }
+
+ public void deleteHistory() {
+ repository.deleteAll();
+ }
+
+ public SequenceHistory updateHistory(Long id, SequenceHistory updatedDetails) {
+ return repository.findById(id).map(record -> {
+ record.setInput(updatedDetails.getInput());
+ record.setOutput(updatedDetails.getOutput());
+ record.setSourceIpAddress(updatedDetails.getSourceIpAddress());
+ return repository.save(record);
+ }).orElseThrow(() -> new RuntimeException("Record not found: " + id));
+ }
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 99d0060..74f48ea 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1 +1,12 @@
spring.application.name=oraclequantapi
+
+# Oracle XE datasource
+spring.datasource.url=jdbc:oracle:thin:@localhost:1521/XEPDB1
+spring.datasource.username=system
+spring.datasource.password=29999login
+spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
+
+# JPA / Hibernate settings
+# "update" creates/updates tables automatically ? safe for development
+spring.jpa.hibernate.ddl-auto=validate
+spring.jpa.show-sql=true
\ No newline at end of file