This is a monorepo for the ASPA Project, it contains both the Frontend and the Backend of the project. The project is built using React for the frontend and Node.js's Express for the backend.
This is going to be pure technical README.md, here i will write about the technical details of the project, how to run it locally and
The Deployed URL : https://aspa-pradeepsahu.up.railway.app
Run all commands from the repository root (the folder that contains docker-compose.yml).
- Create backend env file:
cp Backend/.env.example Backend/.env- Update required values in
Backend/.env:
PORT=3000DATABASE_URL(for local compose, can be left as-is from compose override)REDIS_URL(for local compose, can be left as-is from compose override)ACCESS_TOKEN_SECRETDEEPSEEK_API_KEY
- Start all services:
docker compose up --build- Open the app:
- Frontend:
http://localhost:5173 - Backend:
http://localhost:3000
- Stop services:
docker compose downNotes for Docker startup:
- Backend container runs
npm run start:railway, which automatically runsprisma migrate deployandprisma db seedbefore starting the server. - This means migrations + seed run on backend container start/restart.
- If
docker compose upfails, make sure you are in the repo root, notBackend/.
Prerequisites:
- Node.js 20+
- Local Postgres and Redis running
- Backend:
cd Backend
npm install
npx prisma migrate deploy
npx prisma db seed
npm run dev- Worker (new terminal):
cd Backend
npm run worker- Frontend (new terminal):
cd Frontend
npm install
npm run dev- Open frontend:
http://localhost:5173
Default frontend API target is http://localhost:3000 if VITE_API_URL is not set.
This repository is now set up for Railway as two separate services:
- Backend service
- Frontend service
- Background Worker
- Postgres Database
- Redis Database
Create two Railway services from the same GitHub repository and set each service's root directory:
- Backend service root directory:
Backend - Frontend service root directory:
Frontend - Background Worker root directory:
BackgroundWorker
Each folder contains its own railway.json and Dockerfile, so Railway can build and deploy them independently.
- Root directory:
Backend - Start command: use the Dockerfile default
- Required environment variables:
PORT=3000DATABASE_URL=<your postgres connection string>REDIS_URL=<your redis connection string>ACCESS_TOKEN_SECRET=<your secret>CLIENT_URL=<your Railway frontend domain>ALLOWED_ORIGINS=<your Railway frontend domain>DEEPSEEK_API_KEY=<your api key>
The backend already uses CLIENT_URL and ALLOWED_ORIGINS for CORS and Socket.IO origin checks.
- Root directory:
Frontend - Start command: use the Dockerfile default
- Required environment variables:
PORT=4173VITE_API_URL=<your Railway backend domain>
The frontend reads VITE_API_URL at build time, so set it to the public backend URL before deploying.
- Create the backend service first and deploy it.
- Copy the backend public domain and set it as
VITE_API_URLin the frontend service. - Deploy the frontend service.
- Copy the frontend public domain and set it as
CLIENT_URLandALLOWED_ORIGINSin the backend service. - Redeploy the backend service so CORS and Socket.IO allow the frontend domain.
The root-level railway.json and Dockerfile.railway represent the older single-service backend deployment. For a split Railway deployment, use the per-service setup under Backend/ and Frontend/.
- PostgreSQL database running (either locally via Postgres.app or through Docker)
- Environment variable
DATABASE_URLconfigured in.env
The database schema has been defined using Prisma ORM. To initialize the database:
- Ensure your PostgreSQL database is running
- Create or update your
.envfile with the database connection string:DATABASE_URL="postgresql://username:password@localhost:5432/socialmedia" - Run the initial migration to create all tables:
cd Backend npx prisma migrate dev --name init - Generate the Prisma Client:
npx prisma generate
With Prisma 7 and the @prisma/adapter-pg driver adapter, DATABASE_URL is consumed by two separate systems at different stages:
| Where | Reads DATABASE_URL for |
When |
|---|---|---|
schema.prisma / prisma.config.ts datasource |
Prisma CLI: migrate, generate, db push | dev/build time |
index.js → PrismaPg({ connectionString }) |
Your app's live queries via the pg pool | runtime |
The application uses the following Prisma models:
- Fields: id, name, email, password, phone, city, accountNumber, joinedDate, updatedDate
- Relations:
books- Books written by the authortickets- Support tickets created by the author
- Table:
authors
- Fields: id, name, email, password, contactInfo, joinedDate, updatedDate
- Relations:
assigned- Tickets assigned to this adminticketNotes- Notes created by this admin
- Table:
admins
- Fields: id, authorId, title, isbn, status, genre, publicationDate, mrp, authorRoyaltyPerCopy, totalCopiesSold, totalRoyaltyEarned, royaltyPaid, royaltyPending, lastRoyaltyPayoutDate, printPartner, availableOn, createdDate, updatedDate
- Relations:
author- The author of the booktickets- Tickets related to this book
- Table:
books
- Fields: id, authorId, category, bookId, header, detailDescription, status, assignedId, priorityScore, aiDraft, createdDate, updatedDate, resolvedDate
- Relations:
author- Author who created the ticketbook- Book associated with the ticket (optional)assignedAdmin- Admin assigned to the ticket (optional)notes- Notes added to this ticketmessages- Messages in this ticket thread
- Table:
tickets
- Fields: id, ticketId, adminId, message, visibility
- Relations:
ticket- Parent ticketadmin- Admin who created the note
- Table:
ticket_notes
- Fields: id, ticketId, responseActor, message, createdAt
- Relations:
ticket- Parent ticket
- Table:
ticket_messages - ResponseActor Enum: AUTHOR, LLM, ADMIN
When you modify the Prisma schema, create a new migration:
cd Backend
npx prisma migrate dev --name <migration_name>Example:
npx prisma migrate dev --name add_user_statusTo apply migrations to a deployed database:
npx prisma migrate deployTo reset the entire database and re-run all migrations:
npx prisma migrate resetnpx prisma migrate statusAfter any schema changes, regenerate the Prisma Client:
npx prisma generateThis project uses LangChain with the DeepSeek API (OpenAI-compatible) for ticket analysis, categorization, prioritization, and draft generation.
Reference: LangChain Quickstart
LLM code lives under Backend/src/llm and is organized as follows:
-
lllm.js- Core LLM invocation layer used by controllers and worker jobs.
-
Prompts/- Prompt templates and prompt builders.
- Includes:
classificationAndPriorityScore.prompt.jsDatabase.prompt.jsgeneralInquiry.prompt.jsgenerateDraft.prompt.jsmasterResponseRules.prompt.jsticketUserPrompt.builder.js
-
Tools/- Task-specific tool modules used by the LLM flow.
- Includes:
AnalyzeTicketPriority.tool.jsDatabase.tool.jsUpdateTicketCategory.tool.jsUpdateTicketPriority.tool.jsfinalAnswer.tool.js
-
Registry/- Tool registration and discovery.
- Includes:
toolRegistry.js
-
Executor/- Central execution layer that runs selected tools.
- Includes:
toolExecutor.js
-
Resources/- Shared supporting resources used by the LLM layer.
The Deployed URL : https://aspa-pradeepsahu.up.railway.app
- A more powerful LLM for the Admin with more tools so that admins can use the LLMs for more information and insights about the tickets and the authors. It will also provide a single source of information leading to better decision making and faster resolution of tickets.
- Why i use the Knowledge Base in the Prompts and not build a RAG System?
-
The amount of data in the Knowledge Base is very small 2.5 pages of text, so it is not worth building a RAG system for this small amount of data. The LLM can easily handle this small amount of data in the prompt itself.
-
Also RAGs are best when the data is frequently updated and the LLM needs to be able to access the latest data. In the knowledge base the data is more from a business side and will mostly will remain more or less the same.
- What if we want to use dynamic Data in the future?
- I have a resource folder set which i didn't push to the repo, which will contain the way for the LLM to access the resources (dynamic data) in the future. The LLM will be able to access the resources and use them in the prompts. The resources will be updated as and when required.
- Why don't i use the memory (long term memory) of the LLM? in the Chat Conversation?
- Currently the LLM have user table and books table access, so it knows who is the user and about all this books etc. As per my assumption the chat conversation is usually not very long for the long term memory to be useful. (But can we do it?- Definitely Yes)



