Development Guidelines

Development Guidelines

Code Structure Conventions

Controller Pattern

// controllers/<feature>/<feature>.controller.js

exports.functionName = async (req, res) => {
  try {
    // 1. Extract parameters
    const { param1, param2 } = req.body;
    
    // 2. Validate input (AJV schema)
    const validate = ajv.compile(schema);
    if (!validate(req.body)) {
      return res.status(400).json({
        message: "Validation error",
        errors: validate.errors
      });
    }
    
    // 3. Business logic
    const result = await performOperation(param1, param2);
    
    // 4. Return response
    return res.status(200).json({
      message: "Success",
      data: result
    });
    
  } catch (error) {
    console.error(error);
    return res.status(500).json({
      message: "Internal server error"
    });
  }
};

Route Pattern

// routes/<feature>.routes.js

const controller = require('../controllers/<feature>/<feature>.controller');
const { authJwt } = require('../middleware');

module.exports = function(app) {
  app.post(
    '/api/<feature>/<action>',
    [authJwt.verifyToken],
    controller.functionName
  );
};

Model Pattern

// models/<model>.model.js

module.exports = (sequelize, Sequelize) => {
  const Model = sequelize.define("model_name", {
    id: {
      type: Sequelize.INTEGER,
      primaryKey: true,
      autoIncrement: true
    },
    field1: {
      type: Sequelize.STRING,
      allowNull: false
    },
    created_at: {
      type: Sequelize.DATE,
      defaultValue: Sequelize.NOW
    }
  }, {
    tableName: 'table_name',
    timestamps: false
  });
  
  return Model;
};

Naming Conventions

Files:

Functions:

Variables:

Database:

Error Handling

Standard Error Response:

{
  "message": "Error description",
  "error": "Error code or type",
  "details": { /* additional context */ }
}

HTTP Status Codes:

Error Handler Middleware:

Location: app/middleware/error_param_handler.js

Usage: Automatically applied to all routes

Input Validation

AJV Schema Example:

// schemas/<feature>.schema.js

const createWaybillSchema = {
  type: "object",
  properties: {
    origin_code: { type: "string", minLength: 3 },
    destination_code: { type: "string", minLength: 3 },
    weight: { type: "number", minimum: 0 },
    service_type: { type: "string", enum: ["REG", "EXP", "CARGO"] }
  },
  required: ["origin_code", "destination_code", "weight", "service_type"],
  additionalProperties: false
};

module.exports = { createWaybillSchema };

Usage in Controller:

const ajv = new Ajv();
const { createWaybillSchema } = require('../schemas/waybill.schema');

const validate = ajv.compile(createWaybillSchema);
if (!validate(req.body)) {
  return res.status(400).json({
    message: "Validation failed",
    errors: validate.errors
  });
}

Database Best Practices

Transactions:

const t = await db.sequelize.transaction();

try {
  // Multiple operations
  await Waybill.create(data, { transaction: t });
  await Scan.create(scanData, { transaction: t });
  
  await t.commit();
} catch (error) {
  await t.rollback();
  throw error;
}

Query Optimization:

// Use specific fields instead of SELECT *
await Waybill.findAll({
  attributes: ['id', 'awb_number', 'status'],
  where: { status: 'BOOKED' },
  limit: 100
});

// Use includes for relationships
await Waybill.findOne({
  where: { id: waybillId },
  include: [
    { model: Scan, as: 'scans' },
    { model: Partner, as: 'partner' }
  ]
});

Logging Best Practices

Console Logging:

// Use cli-color for important logs
const clc = require('cli-color');

console.log(clc.green('Success: Waybill created'));
console.log(clc.yellow('Warning: Weight discrepancy detected'));
console.log(clc.red('Error: Database connection failed'));

Morgan HTTP Logging:

Already configured in ondeliv-backend.js with custom colored format.

Testing

Manual Testing Scripts:

Run Tests:

node check_fee_test.js
node check_price.js

Git Workflow

Branch Strategy (from README.md):

Commit Messages:

feat: Add new courier partner integration
fix: Resolve fee calculation bug
docs: Update API documentation
refactor: Improve waybill creation logic
test: Add unit tests for scanning operations

Code Review Checklist

Before submitting code:

Troubleshooting

Common Issues and Solutions

1. Database Connection Failed

Error:

Unable to connect Osas database: SequelizeConnectionError

Solutions:

2. JWT Token Invalid

Error:

{
  "message": "Unauthorized",
  "error": "Invalid token"
}

Solutions:

3. Rate Limit Exceeded

Error:

{
  "message": "You are sending requests too quickly. Please wait 1 second."
}

Solutions:

4. File Upload Failed

Error:

{
  "message": "File too large"
}

Solutions:

5. Courier Webhook Not Working

Error: Webhooks not updating status

Solutions:

6. Fee Calculation Returns 0

Error:

{
  "fee": 0
}

Solutions:

7. Sequelize Migration Issues

Error:

SequelizeDatabaseError: relation does not exist

Solutions:

8. CORS Errors

Error:

Access to fetch blocked by CORS policy

Solutions:

9. Image Not Loading

Error: 404 on image URLs

Solutions:

10. Cron Job Not Running

Error: Lion Parcel pickup not scheduling

Solutions:

Debug Mode

Enable Verbose Logging:

// Add to ondeliv-backend.js temporarily
app.use((req, res, next) => {
  console.log(`${req.method} ${req.url}`);
  console.log('Headers:', req.headers);
  console.log('Body:', req.body);
  next();
});

Database Query Logging:

// In db.config.js
module.exports = {
  // ... existing config
  logging: console.log,  // Enable SQL query logging
};

Health Check Endpoint

Check Server Status:

curl http://localhost:4220/

Expected Response:

{
  "message": "This backend osas works well for now"
}

Performance Monitoring

Check Database Connection:

// Test database connectivity
const testConnection = async () => {
  try {
    await db.sequelize.authenticate();
    console.log('Database connected');
  } catch (error) {
    console.error('Database connection failed:', error);
  }
};

Monitor Response Times:

Morgan logs include response time in cyan color.

Getting Help

Resources:

Contact:

Additional Resources

Key Files for Reference

Third-Party Documentation

  1. Start with ondeliv-backend.js to understand application initialization
  2. Review app/routes/auth.routes.js for authentication flow
  3. Study app/controllers/waybill/create-waybill.controller.js for core business logic
  4. Examine app/models/scans.model.js for tracking data structure
  5. Check app/controllers/3p/ for courier integration patterns

Appendix

Status Code Reference

Code Description Usage
BKD Booked Initial waybill creation
PKD Packed Package prepared for shipping
HND Handover Transferred to courier/hub
DPT Departure Left origin hub
TRS Transit In transit between hubs
ARV Arrival Arrived at destination hub
RCV Receiving Received at DC
OFD Out for Delivery With delivery driver
DLV Delivered Successfully delivered
PRB Problem Issue encountered
RTN Return Package being returned
CNL Cancel Shipment cancelled

Service Type Codes

Code Description
REG Regular Service
EXP Express Service
CARGO Cargo Service
SAME Same Day Delivery
NEXT Next Day Delivery

Problem Type Codes

Code Description
DMG Damaged
LST Lost
RFS Refused by Recipient
INC Incomplete Address
CLO Closed/Not Available
WTH Weather Issues
OTH Other