Backend API for the Assign Meter application.
Assign Meter is a workforce and equipment-management backend designed to manage electrical meters and related field equipment, assign equipment to field engineers/supervisors, track installation status, generate operational reports, process CSV/XLSX files, maintain equipment locations, provide real-time updates, and export operational data.
The backend is built with Node.js, Express, MongoDB/Mongoose, JWT authentication, AWS S3, DuckDB, ExcelJS, Multer, and Server-Sent Events (SSE).
The Assign Meter Backend provides the server-side infrastructure for managing field operations around electrical meter deployment.
The application supports:
- User authentication
- Admin/workforce management
- Meter assignment
- NIC assignment
- SIM assignment
- Meter seal assignment
- Meter status processing
- Meter searching and filtering
- Meter location tracking
- BLE device tracking
- CSV/XLSX processing
- Unmapped-meter reporting
- Supervisor-specific reports
- Excel exports
- ZIP exports
- AWS S3 report storage
- Email notifications
- Push-notification token storage
- Real-time meter events using SSE
The server exposes REST APIs under /api/* and a Server-Sent Events endpoint under /events.
The main application entry point is index.js. The server connects to MongoDB during startup and registers all API routes from the routes directory.
The backend uses:
- JWT
- bcrypt password hashing
- Bearer-token authentication
- Admin authorization for workforce-management operations
JWTs generated during sign-in currently expire after 7 days.
The backend supports:
- Adding multiple meters at once
- Meter-number validation
- Duplicate detection
- Meter deletion
- Meter searching
- Meter filtering
- Pagination
- Sorting
- Status updates
- Supervisor-based filtering
- Package-based filtering
- Excel export
Meter numbers submitted through the assignment API are normalized and validated as seven-digit numeric values.
Administrators can:
- Create users
- View users
- Update users
- Delete users
- Change administrator privileges
- Reset user passwords
Workforce-management endpoints verify the current user's JWT and require administrator privileges.
The system separately tracks:
- Meters
- NIC devices
- SIM cards
- Meter seals
- BLE devices
This keeps equipment-specific attributes separate while still associating assignments with supervisors and installers.
The backend provides:
- Unmapped-meter report generation
- Supervisor-specific unmapped reports
- Last generated report retrieval
- Report last-modified information
- Pivot/report data access
- Excel exports
- ZIP exports
The unmapped report is generated using DuckDB and stored in AWS S3.
| Technology | Purpose |
|---|---|
| Node.js | JavaScript runtime |
| Express 5 | HTTP server and REST API |
| MongoDB | Primary database |
| Mongoose | MongoDB ODM |
| JWT | Authentication |
| bcrypt | Password hashing |
| CORS | Cross-origin API access |
| Cookie Parser | Cookie handling |
| Multer | Multipart/file uploads |
| XLSX | Spreadsheet parsing |
| ExcelJS | Excel generation |
| Archiver | ZIP generation |
| DuckDB | CSV analytics/report processing |
| AWS SDK S3 | Cloud report storage |
| Nodemailer | Gmail-based email transport |
| Resend | Email notifications |
| Server-Sent Events | Real-time browser updates |
The current package.json defines Express 5, Mongoose 9, AWS S3 SDK, DuckDB, bcrypt, JWT, Multer, ExcelJS, XLSX, Archiver, Nodemailer, Resend and related dependencies.
The application follows a straightforward Express + MongoDB backend architecture.
Client / Frontend
|
| HTTP / HTTPS
v
+-----------------------+
| Express API |
+-----------------------+
|
+-------------------+
| |
v v
JWT Auth Route Handlers
|
+-------------+-------------+
| | |
v v v
Models Services Utilities
|
v
MongoDB
Additional integrations:
Express
|
+---- AWS S3
|
+---- DuckDB
|
+---- Resend / Nodemailer
|
+---- SSE
|
+---- ExcelJS / XLSX
Assign-Meter-Backend/
│
├── config/
│ ├── mongoose.js
│ ├── nodemailer.js
│ └── sse.config.js
│
├── doc/
│ └── plan.md
│
├── models/
│ ├── bleDevices.js
│ ├── meter.js
│ ├── meterLocation.js
│ ├── meterSeal.js
│ ├── nicDevice.js
│ ├── simCard.js
│ └── user.js
│
├── public/
│ └── web/
│
├── routes/
│ ├── assign/
│ │ ├── meter/
│ │ │ ├── deleteMeters.js
│ │ │ ├── download.js
│ │ │ ├── getMeterDetails.js
│ │ │ ├── meterAssign.js
│ │ │ ├── searchMeter.js
│ │ │ └── updateMeterStatus.js
│ │ │
│ │ ├── nicAssign.js
│ │ ├── sealAssign.js
│ │ └── simAssign.js
│ │
│ ├── auth/
│ │ ├── signin.js
│ │ └── signup.js
│ │
│ ├── others/
│ │ ├── bleDevices.js
│ │ ├── getInvalidMeters.js
│ │ ├── meterLocation.js
│ │ └── notification.js
│ │
│ ├── reports/
│ │ ├── generate_pivot_table.js
│ │ ├── generate_unmapped_report.js
│ │ ├── generate_unmapped_report_for_supervisor.js
│ │ └── get_last_unmapp_report.js
│ │
│ ├── sse/
│ │ └── sse.js
│ │
│ └── workforce/
│ ├── createUser.js
│ ├── deleteUser.js
│ ├── readUser.js
│ └── updateUser.js
│
├── utils/
│
├── .env.example
├── .gitignore
├── index.js
├── meters.csv
├── migrate.js
├── package.json
├── package-lock.json
└── README.md
The repository currently contains separate route groups for authentication, assignments, reports, workforce management, other utilities, and SSE.
Install:
- Node.js
- npm
- MongoDB
- Git
Optional infrastructure required for specific features:
- AWS S3 account/bucket
- AWS credentials
- Resend account/API key
- Gmail account/app password if Nodemailer is used
git clone https://github.com/Codewithajoydas/Assign-Meter-Backend.gitMove into the project:
cd Assign-Meter-BackendInstall dependencies:
npm installCreate a .env file in the project root.
The repository provides .env.example with the currently expected variables.
Example:
PORT=9000
MONGOOSE_URL=mongodb://localhost:27017/mydatabase
JWT_SECRET=your-super-secret-jwt-key
EMAIL=your-email@gmail.com
PASSWORD=your-email-password
RESEND_API_KEY=your-resend-api-key
AWS_ACCESS_KEY_ID=your-aws-access-key
AWS_SECRET_ACCESS_KEY=your-aws-secret-key
AWS_REGION=your-aws-region
AWS_S3_BUCKET_NAME=your-s3-bucket| Variable | Description |
|---|---|
PORT |
Port on which the Express server runs |
MONGOOSE_URL |
MongoDB connection URI |
JWT_SECRET |
Secret used to sign and verify JWTs |
EMAIL |
Gmail address used by Nodemailer |
PASSWORD |
Gmail credential/app password |
RESEND_API_KEY |
Resend API key |
AWS_ACCESS_KEY_ID |
AWS access key |
AWS_SECRET_ACCESS_KEY |
AWS secret key |
AWS_REGION |
AWS region |
AWS_S3_BUCKET_NAME |
S3 bucket used for reports |
Never commit .env or real credentials to Git.
npm run devThe development script uses Nodemon and ignores:
temp/uploads/
reports/
according to the project's package.json.
npm startThis executes:
node index.jsThe application listens on the port defined by process.env.PORT.
Checks whether the backend is running.
{
"message": "Server is running"
}Creates a user account.
{
"name": "John Doe",
"email": "john@example.com",
"password": "password123",
"isAdmin": false
}The password is hashed using bcrypt before being stored.
The current User model requires pkg, but the signup route does not currently include pkg when creating the user.
Therefore, depending on the current MongoDB/Mongoose validation behavior, this route can fail unless the implementation is updated.
A production-ready version should explicitly handle:
{
"pkg": "ASS1"
}or assign a default package server-side.
Authenticates a user.
{
"email": "john@example.com",
"password": "password123"
}{
"status": "success",
"data": {
"token": "JWT_TOKEN",
"user": {
"id": "USER_ID",
"name": "John Doe",
"email": "john@example.com",
"isAdmin": false
}
}
}The generated JWT currently expires after seven days.
Protected APIs expect:
Authorization: Bearer YOUR_JWT_TOKENExample:
curl http://localhost:9000/api/getmeterdetails \
-H "Authorization: Bearer YOUR_JWT_TOKEN"Assigns one or more meters to the authenticated supervisor.
{
"meterNumber": [
"1234567",
"7654321"
],
"equipCategory": "METER",
"meterType": "1P,2W,5-30A",
"installationType": "LTWC",
"storeLocation": "Nagaon",
"agency": "Example Agency",
"installerId": "INSTALLER001"
}The endpoint:
- Validates the JWT.
- Finds the authenticated user.
- Validates required fields.
- Requires
meterNumberto be an array. - Removes whitespace/newline/tab characters.
- Validates meter numbers as seven-digit numbers.
- Removes duplicates from the request.
- Checks for already submitted meters for the same agency/installer.
- Creates meter records.
- Associates the authenticated user as supervisor.
- Associates the supervisor's package.
- Broadcasts a
meter-addedSSE event.
{
"status": "success",
"message": "Meters sent to MIS successfully, Kindly wait for approval.",
"insertedCount": 2,
"data": []
}Returns meters with filtering and pagination.
status
agency
store
meterType
installationType
startDate
endDate
pageNumber
limit
sort
Example:
/api/getmeterdetails?status=pending&pageNumber=1&limit=20&sort=desc
Supported status values:
active
pending
installed
rejected
The endpoint also automatically filters meters according to the authenticated user's pkg.
{
"status": "success",
"count": 10,
"data": [],
"totalPages": 5,
"currentPage": 1,
"totalData": 42
}Returns meters belonging to the authenticated supervisor.
sort
search
status
agency
store
meterType
installationType
Supported sort values include:
newold
oldnew
meterid
status
The endpoint searches meter numbers using a case-insensitive regular expression and restricts results to the authenticated supervisor.
Searches for a specific meter number.
/api/searchmeter?meterNumber=1234567
{
"status": "success",
"data": {
"meters": []
}
}Deletes selected meters.
{
"meters": [
"MONGO_OBJECT_ID_1",
"MONGO_OBJECT_ID_2"
]
}The endpoint requires a valid Bearer token and expects a non-empty array.
Assigns a NIC device.
{
"equipmentNumber": "NIC001",
"agency": "Example Agency",
"type": "3 Phase",
"nicCommType": "Cellular",
"installerNumber": "INSTALLER001"
}Supported communication types:
RF
Cellular
The equipment number must be unique.
Assigns a SIM card.
{
"equipmentNumber": "SIM001",
"agency": "Example Agency",
"nsp": "Airtel",
"installerNumber": "INSTALLER001"
}Supported network providers:
Airtel
Jio
The equipment number must be unique.
Assigns a meter seal.
{
"equipmentNumber": "SEAL001",
"agency": "Example Agency",
"sealType": "Box Seal",
"installerNumber": "INSTALLER001"
}Supported seal types:
Box Seal
GTW Seal
Left Seal
NIC Seal
Right Seal
Terminal Seal
Workforce APIs are intended for administrative user management.
All four workforce endpoints verify JWT authentication and enforce admin privileges where appropriate.
Creates a new workforce user.
Admin authentication is required.
{
"name": "Field Engineer",
"email": "engineer@example.com",
"password": "password123",
"isAdmin": false
}The new user's pkg is inherited from the authenticated administrator.
Returns all users.
Admin authentication is required.
{
"status": "success",
"count": 3,
"users": []
}Updates user information.
{
"email": "engineer@example.com",
"name": "Updated Name",
"password": "newpassword",
"isAdmin": false
}Supported updates:
- Name
- Password
- Admin status
Passwords must contain at least six characters when changed.
Deletes a user by email.
{
"email": "engineer@example.com"
}The current administrator cannot delete their own account.
Bulk-updates meter status using an uploaded spreadsheet.
The endpoint accepts a multipart form-data upload with:
file
Maximum file size:
5 MB
The spreadsheet must contain:
Equipment Number
Field Engineer
Status
Remarks
Headers are matched case-insensitively.
active
pending
installed
rejected
Aliases include:
success
successful
approved
failed
failure
reject
The endpoint:
- Authenticates the user.
- Reads the XLSX/CSV file.
- Validates required headers.
- Normalizes status values.
- Removes duplicate meter/engineer entries.
- Finds existing meters.
- Performs bulk database updates.
- Marks conflicting assignments as rejected.
- Returns processing results.
- Sends supervisor notification emails asynchronously.
Generates downloadable meter reports.
The endpoint supports filtering by:
startDate
endDate
agency
store
meterType
installationType
status
The current implementation generates three Excel workbooks:
store-data-<timestamp>.xlsx
agency-data-<timestamp>.xlsx
dispatch-data-<timestamp>.xlsx
These are packaged into:
meters-<timestamp>.zip
Streams a complete meter Excel report.
The workbook contains:
Equip Category
Equip Number
Material Type
Store Name
Asset Received Date
Agency Name
Field Engineer
Installation Type
Supervisor Name
Dispatch Date
Status
The implementation uses ExcelJS's streaming workbook writer so large datasets can be written directly to the HTTP response.
Generates the unmapped-meter report.
Three files are required:
comm
issue
mi
The backend processes these CSV files using DuckDB.
The generated report calculates:
- Mapping status
- Last communication date
- Issue age
- Meter/subcontractor information
- Store information
- Installer information
- Subdivision information
The SQL logic determines:
Mapped
Never Comm.
Pending
Unmapped
Below 30 Days
30-60 Days
60-90 Days
90-180 Days
180 Days Above
Unknown
The resulting CSV is uploaded to:
reports/unmapped-report.csv
in the configured S3 bucket and is also returned as a downloadable file.
Downloads the most recently generated unmapped report from S3.
The endpoint also sends:
X-Report-Last-Modifiedcontaining the S3 object's last-modified timestamp.
Returns the timestamp of the latest report.
{
"lastModified": "2026-08-25T12:00:00.000Z"
}Returns only the portion of the latest unmapped report associated with meters belonging to the authenticated supervisor.
Flow:
JWT
↓
Find supervisor
↓
Find supervisor's meters
↓
Download latest S3 report
↓
DuckDB filtering
↓
Return matching records
Accesses the latest generated report stored in S3.
The current implementation retrieves the reports/unmapped-report.csv object and returns the S3 SDK result.
Stores or updates the geographical location of a meter.
{
"meterNumber": "1234567",
"consumerNumber": "CONSUMER001",
"location": {
"latitude": 26.12345,
"longitude": 92.12345
}
}The endpoint:
- Validates the JWT
- Validates latitude/longitude types
- Associates the record with the authenticated supervisor
- Uses an upsert operation
Therefore, if the meter location doesn't exist, it is created; otherwise it is updated.
Stores an Expo push-notification token against the authenticated user.
{
"expoNotificationToken": "ExponentPushToken[...]"
}The token is stored in the user's expoNotificationToken field.
Stores a scanned BLE device.
{
"deviceId": "BLE-001",
"name": "Meter Device",
"localName": "Meter",
"rssi": -55,
"location": {
"latitude": 26.12345,
"longitude": 92.12345,
"accuracy": 10
},
"scannedAt": "2026-08-25T12:00:00.000Z"
}The endpoint associates the device with the authenticated user and prevents duplicate device names.
Returns stored BLE devices.
The current implementation populates the associated supervisor field.
Downloads BLE device data as an XLSX file.
The exported columns include:
Device ID
Name
Local Name
RSSI
Location
Scanned At
The backend exposes an SSE endpoint for real-time browser updates.
Connect using JavaScript:
const eventSource = new EventSource(
"http://localhost:9000/events"
);
eventSource.addEventListener("meter-added", (event) => {
const data = JSON.parse(event.data);
console.log("New meters:", data);
});The SSE implementation:
- Sets
text/event-stream - Keeps the connection alive
- Registers connected clients
- Removes clients when connections close
- Supports broadcasting named events
When meters are successfully assigned, the backend broadcasts:
meter-added
with:
{
"insertedCount": 2,
"meters": []
}This allows the frontend to update the UI without polling the backend.
Returns meter records whose meter number contains non-numeric characters.
This can be useful for detecting malformed/imported meter numbers.
The User model contains:
name
email
password
isAdmin
pkg
expoNotificationToken
createdAt
updatedAt
The password field is configured with select: false, meaning it isn't selected by default.
ASS1
ASS2
ASS3
ASS4
ASS5
ASS6
ASS7
ASS8
ASS9
ASS10
The Meter model contains:
meterNumber
pkg
supervisor
equipCategory
meterType
installationType
storeLocation
agency
installerId
status
remarks
createdAt
updatedAt
CT
METER
NIC
PT
SEAL
SIM
DTMeter
FeederMeter
HTCT
LTCT
LTWC
active
pending
installed
rejected
The NIC model contains:
equipmentNumber
supervisor
equipCategory
meterType
storeLocation
agency
installerId
nicCommType
status
createdAt
updatedAt
Communication types:
RF
Cellular
The SIM model contains:
equipmentNumber
supervisor
equipCategory
storeLocation
agency
installerId
nsp
status
createdAt
updatedAt
Supported network providers:
Airtel
Jio
The seal model contains:
equipmentNumber
supervisor
equipCategory
storeLocation
agency
installerId
sealType
status
createdAt
updatedAt
Supported seal types:
Box Seal
GTW Seal
Left Seal
NIC Seal
Right Seal
Terminal Seal
The MeterLocation model contains:
meterNumber
consumerNumber
location.latitude
location.longitude
supervisor
The BLE device model contains:
deviceId
name
localName
rssi
location.latitude
location.longitude
location.accuracy
supervisor
scannedAt
createdAt
updatedAt
A typical meter workflow looks like this:
Meter received
|
v
Meter assigned to supervisor
|
v
Meter assigned to field engineer
|
v
Installation / field update
|
v
Status uploaded
|
+-------------------+
| |
v v
Active Rejected
|
v
Installed
The status-update endpoint normalizes spreadsheet values before writing them to MongoDB.
The unmapped report pipeline is one of the more advanced parts of the backend.
COMM CSV
|
|
ISSUE CSV ----+
| |
| v
MI CSV ---> DuckDB
|
v
Mapping Analysis
|
v
Unmapped Report CSV
|
v
AWS S3
|
+---------+---------+
| |
v v
Admin Download Supervisor Report
DuckDB performs the CSV joins and calculations before the final report is uploaded to S3.
The backend processes several types of files:
Used primarily for:
- Communication data
- Issue data
- Meter installation/import data
- Unmapped report generation
Used primarily for:
- Meter status updates
- Excel report generation
- BLE device exports
Used for:
- Packaging store data
- Agency data
- Dispatch data
The project uses:
Multer
XLSX
ExcelJS
Archiver
DuckDB
for these workflows.
Generated unmapped reports are stored in:
reports/unmapped-report.csv
The same S3 key is reused, meaning a newly generated report replaces the previous report.
S3 is used as persistent report storage rather than keeping generated reports only on the application server.
This is particularly useful for deployments where the backend filesystem may be temporary.
The project contains two email mechanisms:
The configured Nodemailer transport uses Gmail:
nodemailer.createTransport({
service: "gmail",
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD
}
});The meter status update workflow uses Resend to send supervisor notifications after spreadsheet processing.
The notification work is intentionally performed asynchronously after the HTTP response is sent so email failures don't block the API response.
The backend currently implements several security mechanisms.
Protected routes verify:
Authorization: Bearer <token>JWTs are signed using:
JWT_SECRETPasswords are hashed using bcrypt.
Example:
const hashedPassword = await bcrypt.hash(password, 10);Workforce operations check:
currentUser.isAdminNon-admin users receive:
403 Forbidden
for protected administrative operations.
The current server configuration allows:
https://assign-meter-web.vercel.app
http://localhost:3000
and enables credentials.
The meter-status upload endpoint limits uploads to:
5 MB
and one file per request.
The API generally follows a consistent JSON structure.
{
"status": "success",
"data": {}
}{
"status": "error",
"message": "Something went wrong"
}Typical HTTP status codes include:
| Status | Meaning |
|---|---|
200 |
Successful request |
201 |
Resource created |
400 |
Invalid request |
401 |
Authentication failure |
403 |
Insufficient permissions |
404 |
Resource not found |
409 |
Duplicate/conflicting resource |
500 |
Server/database error |
npm run devnpm startOpen:
http://localhost:9000/
Expected:
{
"message": "Server is running"
}A typical frontend workflow can look like this:
POST /api/signinReceive:
JWT
The frontend stores the JWT according to its authentication strategy.
POST /api/meterassign
Authorization: Bearer <JWT>const events = new EventSource(
`${BACKEND_URL}/events`
);
events.addEventListener("meter-added", event => {
const payload = JSON.parse(event.data);
console.log(payload);
});GET /api/getmeterdetails
Authorization: Bearer <JWT>GET /api/getmeterdetails
?status=pending
&store=Nagaon
&pageNumber=1
&limit=20
Upload an XLSX/CSV file:
POST /api/statusupdate
Authorization: Bearer <JWT>
Content-Type: multipart/form-datawith:
file=<spreadsheet>
POST /api/generateReportwith:
comm=<communication.csv>
issue=<issue.csv>
mi=<meter-installation.csv>
The generated report is uploaded to:
AWS S3
GET /api/last-unmapped-report| Method | Endpoint | Purpose |
|---|---|---|
| GET | / |
Health check |
| POST | /api/signin |
Sign in |
| POST | /api/signup |
Sign up |
| POST | /api/meterassign |
Assign meters |
| DELETE | /api/deletemeter |
Delete meters |
| GET | /api/getmeterdetails |
Get/filter meters |
| GET | /api/getmeterdetails/supervisor |
Get supervisor meters |
| POST | /api/nicassign |
Assign NIC |
| POST | /api/simassign |
Assign SIM |
| POST | /api/sealassign |
Assign seal |
| GET | /api/download |
Download meter ZIP |
| GET | /api/download/whole |
Download complete meter XLSX |
| GET | /api/searchmeter |
Search meter |
| POST | /api/createuser |
Create workforce user |
| DELETE | /api/deleteuser |
Delete workforce user |
| GET | /api/getusers |
Get workforce users |
| PATCH | /api/updateuser |
Update workforce user |
| POST | /api/statusupdate |
Bulk meter status update |
| GET | /api/wrongmeter |
Find invalid meter numbers |
| POST | /api/assign-location |
Save meter location |
| POST | /api/notification/add |
Save Expo notification token |
| POST | /api/generateReport |
Generate unmapped report |
| GET | /api/last-unmapped-report |
Download latest report |
| GET | /api/last-unmapped-report/last-modified |
Get report timestamp |
| GET | /api/generate_unmapped_report_for_supervisor |
Supervisor report |
| GET | /api/pivottabls/getallinstallername |
Retrieve report/S3 data |
| GET | /api/bledevices |
Get BLE devices |
| POST | /api/bledevices |
Add BLE device |
| GET | /api/bledevices/download |
Export BLE devices |
| GET | /events |
SSE connection |
The route registrations are defined centrally in index.js.
This section intentionally documents things that should be understood by anyone maintaining the project.
The User model requires:
pkg
but /api/signup currently doesn't pass it into UserDB.create().
This should be fixed before relying on public signup in production.
The signup endpoint accepts:
isAdmin
directly from the request body.
That means a public caller may potentially request an administrator account.
For production, administrator creation should be restricted to an existing administrator or an explicit bootstrap process.
JWT security depends entirely on:
JWT_SECRETUse a strong, random secret in production.
The current allowed-origin list is hard-coded in index.js.
For different environments, consider moving allowed origins to environment variables.
The project uses Bearer JWT authentication extensively, while cookie-parser is also installed and enabled.
The current protected API implementations primarily read the JWT from the Authorization header.
SSE clients are stored in an in-memory array.
Therefore:
- It works well for a single server instance.
- Multiple backend instances would require shared event infrastructure.
- Restarting the server removes all connected clients.
The unmapped report uses a fixed S3 object key:
reports/unmapped-report.csv
Generating a new report replaces the previous report.
The status update workflow maps spreadsheet values into the database's canonical enum values.
For example:
success -> active
approved -> active
failed -> rejected
failure -> rejected
These mappings represent business logic and should be reviewed whenever the field workflow changes.
Before deploying this backend to production, the following areas should be reviewed.
- Add refresh tokens.
- Consider shorter access-token lifetimes.
- Add logout/token revocation if required.
- Move admin creation behind a privileged workflow.
Add dedicated validation middleware using a schema validation library such as:
Zod
Joi
express-validator
Introduce centralized Express error middleware instead of repeating:
try {
...
} catch (error) {
...
}inside every route.
Consider structured logging with:
Pino
Winston
rather than relying primarily on console.log.
Add rate limiting to:
signin
signup
file upload
report generation
endpoints.
Consider:
/api/v1/...
instead of permanently keeping APIs under /api.
Add appropriate MongoDB indexes for frequently queried fields such as:
meterNumber
agency
installerId
supervisor
status
pkg
createdAt
Report generation and email notifications can eventually move into background workers.
Possible technologies:
BullMQ
Redis
AWS SQS
For multiple backend instances, use a shared pub/sub layer:
Redis Pub/Sub
AWS SNS
AWS EventBridge
rather than an in-memory client array.
Potential next steps for the project include:
- API documentation with OpenAPI/Swagger
- Automated API tests
- Unit tests
- Integration tests
- Request validation
- Centralized authentication middleware
- Centralized authorization middleware
- Service layer
- Repository/data-access layer
- Structured logging
- Rate limiting
- Helmet security headers
- API versioning
- Database indexes
- Background report generation
- Job queues
- Redis caching
- S3 signed URLs
- Refresh-token authentication
- Audit logs
- Role-based access control
- CI/CD using GitHub Actions
- Docker support
- Automated database backups
- Production monitoring
- Error tracking
A practical evolution of the backend could be:
Current
|
+-- Express REST APIs
+-- MongoDB
+-- JWT
+-- S3
+-- DuckDB
+-- SSE
+-- Excel/CSV processing
|
v
Phase 1
|
+-- Validation layer
+-- Centralized errors
+-- API documentation
+-- Automated tests
|
v
Phase 2
|
+-- Service layer
+-- Middleware architecture
+-- Role-based authorization
+-- Audit logging
|
v
Phase 3
|
+-- Redis
+-- Background workers
+-- Queue-based reports
+-- Scalable SSE/event system
|
v
Phase 4
|
+-- Docker
+-- CI/CD
+-- Monitoring
+-- Production observability
Source code:
https://github.com/Codewithajoydas/Assign-Meter-Backend
The repository currently declares the ISC license in package.json.
Codewithajoydas
GitHub:
https://github.com/Codewithajoydas
Assign Meter Backend is a Node.js/Express backend focused on field workforce and electrical-meter management.
Its core responsibilities are:
Authentication
+
Workforce Management
+
Meter Management
+
Equipment Assignment
+
Status Processing
+
Location Tracking
+
BLE Device Tracking
+
CSV/XLSX Processing
+
DuckDB Analytics
+
AWS S3 Reports
+
Excel/ZIP Exports
+
Email Notifications
+
Real-Time SSE Events
The backend provides the infrastructure required for an operational meter-assignment workflow, from equipment allocation through field installation/status updates and reporting.