Built a book store for a client using ServiceNow which has
- User authentication
- Fuzzy searching using natural language processing
- CRUD operations for managing books inventory
- Razorpay integration for online payements
My code is highly decoupled. This is possible because I have used ports and adapters architecture
throughtout my code base(basically different interfaces for different jobs). Took some inspiration from the onion architecture
to build my logging service completly detached from my bussiness logic and to make middlewares for my json api
I wrote the background workers from scratch
for the task which should not block the user to further request my api (eg:- while email is sent to user and when user deleted their account). I have used semaphore
to make a simple task queue for my worker. You can see the power of background workers here
- Working of email background worker for
email verification
- Working of deletion operation in background to support
soft delete
I have made a complete fuzzy search
implementation using NLP in postgres. Uses stop word removal
, lexeme
formation and similarity match
in postgres to rank the results and give it to users. You can see some eaxmple below but please try out the search yourself to see its true magic
The query that went into this goes like this. I know this maybe unoptimized but I am open to learn
WITH book_search_cte AS (
SELECT
b.id,
b.title,
b.author,
array_agg(t.tag_name) AS tags_array,
r.average_ratings AS ratings,
b.description
FROM "Books" AS b
LEFT JOIN "Tags" AS t ON t.id = ANY(b.tags_array)
LEFT JOIN (
SELECT book_id, AVG(rating) AS average_ratings FROM "Reviews"
GROUP BY book_id
) AS r ON r.book_id = b.id
GROUP BY b.id, b.title, b.author, r.average_ratings, b.description
),
final_cte AS (
SELECT *,
ts_rank(
to_tsvector('english', title) || ' ' ||
to_tsvector('english', author) || ' ' ||
setweight(to_tsvector('english', array_to_string(COALESCE(tags_array, '{}'), ' ')), 'A') || ' ' ||
to_tsvector('english', description),
websearch_to_tsquery('english', $1)
) AS ranks,
difference(array_to_string(COALESCE(tags_array, '{}'), ' '), $2) AS tags_difference,
difference(title, $2) AS title_difference,
difference(author, $2) AS author_difference,
difference(description, $2) AS description_difference
FROM book_search_cte
)
SELECT *,
GREATEST(title_difference, author_difference, description_difference, tags_difference) AS max_difference
FROM final_cte
ORDER BY ranks DESC, max_difference DESC, tags_difference DESC, title_difference DESC, author_difference DESC, description_difference DESC
LIMIT $3
OFFSET $4;
Complete razorpay integration for orders. Operational flow is like
- Add books to cart
Screencast from 02-09-23 07:46:57 PM IST.webm
- Place order
Screencast from 02-09-23 07:49:03 PM IST.webm
- Verify Order
You can test the api routes through this postman
link
https://www.postman.com/mission-physicist-26981670/workspace/balkanid-book-store
-
How would you get to know from where has the error come from ? To solve this I have created a structured logging system in which you can
trace user-id
and even trace the function calls -
Lets say there something wrong with the json transport layer that is, our gateway service/api. In that case you just need to change the code in the
api folder
and literlly dont care about rest of the code. This is because interfaces are used which creates a contract between different parts of the code. So basically the function name remains the same its functionality you can change anytime. Similarly if there is any error in the auth or book manamement logic then check in theauthService
orbookService
folder. -
All of my errors are declared in
erros.go
handled in amiddleware
to make it organized. -
Rest of the folders like
database
,email
,token
andworker
all can be think of as a external tool(adapters) and are independent in themselves. So if you need to use these tools then just do like this
type authManager struct {
config util.Config
tokenMaker token.Maker
db database.Storer
worker worker.Worker
}
- Secure user registration and authentication
- Account Deactivation and Deletion: Allow users to deactivate or delete their accounts, if applicable. Implement a mechanism to handle account deletion securely while considering data retention policies.
- Protection against vulnerabilities like SQL injection attacks
- Have Proper system logging with retention policies upon system failure
- Users can easily search and filter books and add them to shopping cart
- Users can easily download their bought books and leave a review on the books they bought
- Admins have the ability to manage inventory and others
- Make the necessary APIs to expose
- SQL based database - PostgreSQL
- Use a reverse-proxy of your choice
- You can choose to write your program in Golang only. It is crucial to ensure that your code is well organized and easy to understand, and that you provide clear instructions on how to run your program.
- All plagiarized submissions will be disqualified. Please ensure that you use a VCS Platform like Github and commit and push all your contributions on time. Kindly share the same.
- The Github repository must have a file called “README.md” which contains information about how to install and run your project, along with a clear understanding of your project, including relevant diagrams, if any. If you have deployed your application, you may include a link in the README.
- You can use Docker and containerize your application code to run, including the database
- You can test your code by adding unit test cases and workflow test cases
- You can add recommendation system to recommend books to user