Portfolio
Loading Shiham's portfolio
Preparing the latest projects, skills, and contact paths with a quiet production-ready polish.
Initializing portfolio
Projects · Skills · Contact
Portfolio
Preparing the latest projects, skills, and contact paths with a quiet production-ready polish.
Initializing portfolio
Projects · Skills · Contact
A Spring Boot REST API for food delivery customers, managing accounts, food catalogues, carts, orders, Stripe checkout, and S3-hosted images.
BiteNow is a personal backend project created to explore how a food delivery service can manage customer accounts, menu data, carts, orders, and payments through a REST API. It was developed independently as a Java and Spring Boot learning project, with MongoDB used for application data.
Users can register, log in to receive a JWT, browse food records, and manage a cart linked to their authenticated account. The API also accepts multipart food entries with images stored in Amazon S3, creates Stripe Checkout sessions for orders, and processes signed checkout-completion webhooks to confirm payment and clear the related cart.
The code follows a layered structure of controllers, service interfaces and implementations, Spring Data repositories, MongoDB documents, and request/response DTOs. Spring Security runs stateless authentication through a custom JWT filter, while environment properties supply MongoDB, AWS, JWT, and Stripe credentials. I implemented the repository independently.
Related projects
Jan 2026 – Jun 2026
A multi-vendor commerce platform connecting buyers, sellers, and administrators through dedicated storefronts, dashboards, payments, chat, and personalized discovery.
Spring Boot exposes REST controllers that delegate business logic to service implementations and persist users, foods, carts, and orders through Spring Data MongoDB repositories. Spring Security adds stateless JWT processing, while the service layer communicates with Amazon S3 for images and Stripe Checkout/webhooks for payments.
A RESTful backend API for the BiteNow online food delivery application, built with Spring Boot. This project was developed to gain hands-on experience with Spring Boot, Spring Data MongoDB, Spring Security, and third-party integrations including AWS S3 and Stripe payments.
BiteNow is a full-featured food delivery REST API that handles user authentication, food catalogue management, shopping cart operations, and order processing with real payment integration. The backend is stateless, secured with JWT, and connects to MongoDB as its primary data store.
| Layer | Technology |
|---|---|
| Framework | Spring Boot 3.5.9 |
| Language | Java 17 |
| Database | MongoDB (Spring Data MongoDB) |
| Security | Spring Security + JWT (jjwt 0.11.5) |
| File Storage | AWS S3 (AWS SDK v2 2.40.17) |
| Payments | Stripe Java SDK 24.10.0 |
| Boilerplate Reduction | Lombok 1.18.36 |
| Serialisation | Jackson, Gson 2.10.1 |
| Build Tool | Maven |
src/main/java/com/dev/BiteNowAPI/
├── BiteNowApiApplication.java # Application entry point
│
├── config/
│ ├── AWSConfig.java # AWS S3 client bean
│ └── SecurityConfig.java # Spring Security + CORS configuration
│
├── controller/
│ ├── AuthController.java # Login endpoint
│ ├── UserController.java # User registration
│ ├── FoodController.java # Food CRUD + image upload
│ ├── CartController.java # Cart management
│ ├── OrderController.java # Order creation + Stripe checkout
│ └── StripeWebhookController.java # Stripe payment webhook handler
│
├── entity/
│ ├── UserEntity.java # MongoDB users collection
│ ├── FoodEntity.java # MongoDB foods collection
│ ├── CartEntity.java # MongoDB carts collection
│ └── OrderEntity.java # MongoDB orders collection
│
├── filters/
│ └── JwtAuthenticationFilter.java # Per-request JWT validation filter
│
├── io/ # DTOs (Request / Response objects)
│ ├── AuthenticationRequest.java
│ ├── AuthenticationResponse.java
│ ├── UserRequest.java / UserResponse.java
│ ├── FoodRequest.java / FoodResponse.java
│ ├── CartRequest.java / CartResponse.java
│ ├── OrderRequest.java / OrderResponse.java
│ └── OrderItem.java
│
├── repository/
│ ├── UserRepository.java
│ ├── FoodRepository.java
│ ├── CartRepository.java
│ └── OrderRepository.java
│
├── service/
│ ├── AppUserDetailsService.java # UserDetailsService implementation
│ ├── AuthenticationFacade.java # Interface for SecurityContext access
│ ├── AuthenticationFacadeImpl.java
│ ├── UserService.java / UserServiceImpl.java
│ ├── FoodService.java / FoodServiceImpl.java
│ ├── CartService.java / CartServiceImpl.java
│ └── OrderService.java / OrderServiceImpl.java
│
└── util/
└── JwtUtil.java # JWT generation & validation helpers
| Method | Endpoint | Description | Auth |
|---|---|---|---|
POST | /api/register | Register a new user | ❌ None |
POST | /api/login | Login and receive a JWT | ❌ None |
Register — Request Body
{
"name": "John Doe",
"email": "john@example.com",
"password": "secret123"
}
Login — Request Body
{
"email": "john@example.com",
"password": "secret123"
}
Login — Response
{
"email": "john@example.com",
"token": "<JWT>"
}
| Method | Endpoint | Description | Auth |
|---|---|---|---|
GET | /api/foods | Retrieve all food items | ❌ None |
GET | /api/foods/{id} | Retrieve a single food item | ❌ None |
POST | /api/foods | Add a new food item with image | ✅ JWT |
DELETE | /api/foods/{id} | Delete a food item | ✅ JWT |
The POST /api/foods endpoint accepts a multipart/form-data request:
food — JSON string with name, description, price, and categoryfile — image file (uploaded to AWS S3)| Method | Endpoint | Description | Auth |
|---|---|---|---|
GET | /api/cart | Get the current user's cart | ✅ JWT |
POST | /api/cart | Add an item to cart | ✅ JWT |
POST | /api/cart/remove | Remove one item from cart | ✅ JWT |
DELETE | /api/cart | Clear the entire cart | ✅ JWT |
Add/Remove — Request Body
{
"foodId": "<food_document_id>"
}
| Method | Endpoint | Description | Auth |
|---|---|---|---|
POST | /api/orders/create | Create order + get Stripe checkout URL | ✅ JWT |
POST | /api/webhook/stripe | Receive Stripe payment events | ❌ None (Stripe) |
Create Order — Request Body
{
"orderItems": [
{
"foodID": "<id>",
"name": "Burger",
"quantity": 2,
"price": 850.00,
"category": "Fast Food",
"imageUrl": "https://...",
"description": "Juicy beef burger"
}
],
"phoneNumber": "0771234567",
"email": "john@example.com",
"userAddress": "123 Main St, Colombo",
"amount": 1700.00
}
Create Order — Response (includes Stripe checkout URL)
{
"id": "<order_id>",
"userAddress": "123 Main St, Colombo",
"phoneNumber": "0771234567",
"email": "john@example.com",
"amount": 1700.00,
"paymentStatus": "PENDING",
"orderStatus": "CREATED",
"stripeOrderId": "<stripe_session_id>",
"checkoutUrl": "https://checkout.stripe.com/..."
}
JwtAuthenticationFilter intercepts every request, extracts the Bearer token from the Authorization header, validates it, and populates the SecurityContext.http://localhost:5173 and http://localhost:5174 (typical Vite/React dev ports).Public routes (no token required):
POST /api/register
POST /api/login
GET /api/foods/**
POST /api/webhook/stripe
All other routes require a valid Authorization: Bearer <token> header.
| Collection | Document | Description |
|---|---|---|
users | UserEntity | Stores user credentials and profile |
foods | FoodEntity | Food item catalogue with S3 image URLs |
carts | CartEntity | Per-user cart (Map of foodId → quantity) |
orders | OrderEntity | Order records with Stripe session linkage |
POST /api/orders/create with order details.paymentStatus: PENDING and orderStatus: CREATED.checkout.session.completed event to POST /api/webhook/stripe.paymentStatus: PAID and orderStatus: CONFIRMED, and clears the user's cart.Food images are uploaded to an S3 bucket (amzn-s3-bitenow) with public-read ACL. Each image is stored under a UUID-based key. The public URL is persisted in the FoodEntity.imageUrl field. On food deletion, the image is also removed from S3.
All sensitive configuration is externalised through environment variables. Never commit real secrets to version control.
| Variable | Description |
|---|---|
MONGODB_URI | MongoDB connection string |
AWS_ACCESS_KEY | AWS IAM access key ID |
AWS_SECRET_KEY | AWS IAM secret access key |
AWS_REGION | AWS region (e.g. ap-south-1) |
JWT_SECRET_KEY | Secret used to sign JWT tokens |
STRIPE_SECRET_KEY | Stripe secret API key |
STRIPE_WEBHOOK_SECRET | Stripe webhook signing secret |
amzn-s3-bitenowgit clone https://github.com/theShihamAhamed/BiteNow-food-delivery-backend.git
cd BiteNow-food-delivery-backend
Create a .env file or export the variables in your shell:
export MONGODB_URI="mongodb+srv://<user>:<password>@cluster.mongodb.net/bitenow"
export AWS_ACCESS_KEY="your-access-key"
export AWS_SECRET_KEY="your-secret-key"
export AWS_REGION="ap-south-1"
export JWT_SECRET_KEY="your-very-long-random-secret"
export STRIPE_SECRET_KEY="sk_test_..."
export STRIPE_WEBHOOK_SECRET="whsec_..."
./mvnw spring-boot:run
The server starts on port 8081 by default.
You can use Postman or any REST client:
# Register
curl -X POST http://localhost:8081/api/register \
-H "Content-Type: application/json" \
-d '{"name":"Test User","email":"test@example.com","password":"pass123"}'
# Login and grab the token
curl -X POST http://localhost:8081/api/login \
-H "Content-Type: application/json" \
-d '{"email":"test@example.com","password":"pass123"}'
Install the Stripe CLI and forward events to your local server:
stripe listen --forward-to localhost:8081/api/webhook/stripe
This project was built to gain practical experience with:
findByEmail, findByUserId, findByStripeOrderId)UserDetailsService, AuthenticationManager, PasswordEncoderOncePerRequestFilterS3ClientPOST requestThis project is for educational purposes. No license has been specified.
The case-study preview is collapsed. Activate the button to make the full content available.
Aug 2025 – Oct 2025
A marketplace for verified Sri Lankan homestays, supporting guest bookings, host onboarding, admin approval, and test-mode payments.
Oct 2025 – Nov 2025
A full-stack developer Q&A platform where programmers can ask, answer, vote, save questions, explore tags, and generate AI-assisted responses.