I Built the Government Procurement Portal to be OCDS Compliant: What I Would Do Differently If I Had to Start Over

Want to Build a Government Procurement Portal that Meets OCDS Standards? Here’s How (And What to Avoid)

cengkuru michael
13 min readJan 27, 2023
Government Procurement Portal — Uganda

Introduction:

Building a government procurement portal compliant with the Open Contracting Data Standard (OCDS) is no easy feat. As an open data specialist, I have worked on several government procurement portals and learned much from my experiences. I remember the first time I took on the task of building a government procurement portal. I was excited but also overwhelmed by the complexity of the project. I remember thinking,

“If I had to do it all over again, what would I do differently?”

In this article, I will share my experience building a government procurement portal and what I would do differently if I had to start over.

High Level 5 step process summary

Building a government procurement portal compliant with the OCDS is a complex task requiring a lot of planning and attention to detail.

  1. The first step is understanding the OCDS data model and how it relates to government procurement. This includes understanding the data types that need to be collected and how they should be structured.
  2. Next, I would focus on building the database structure. This would involve creating tables to store the different data types, such as procurement, contract, and supplier data. I would also develop relationships between these tables to ensure that the data is linked correctly. Finally, I would also design the database in a way that is easy to maintain and scale.
  3. Once the database is set up, I would then build the API. This would involve creating routes for accessing the data and defining the methods for retrieving and updating the data. I would also test and deploy the API to a production server.
  4. Providing training and support: Providing training and support to users on how to use the new system and how to ensure compliance with the OCDS can help to ensure a smooth transition and ensure that users can take advantage of the system’s capabilities fully
  5. Finally, I would focus on monitoring and maintaining the API. This would involve monitoring the API for errors, tracking resource usage, and ensuring the API is accessible and responsive. I also keep the API updated with the latest security patches and updates.

Step 1: Understanding the OCDS data model

OCDS Model

I would conduct a thorough review of the existing Government Procurement Portal to understand its current data structure and functionality. I would then compare that to the Open Contracting Data Standard (OCDS) to identify discrepancies or gaps. This process is called Field-Level Mapping.

The Open Contracting Partnership (OCP) has a template that makes this process a breeze.

Next, I would create a plan to map the existing data fields to the OCDS fields and make any necessary adjustments to the data structure in the MySQL database. I would use Laravel’s built-in database migrations to make these changes.

Note: Field-level mapping is not a one-person show and would require working in tandem with a procurement policy expert no understand the different contexts and what is or is not possible under the government procurement low

Step 2: Building the database structure

This would involve creating tables to store the different data types, such as procurement, contract, and supplier data. I would also develop relationships between these tables to ensure that the data is linked correctly.

A possible database structure for aligning an existing Government Procurement Portal to the Open Contracting Data Standard (OCDS) could include the following tables:

  1. contracts: This table would contain information about the contracts being procured, such as the contract title, description, value, and date signed. It could also include foreign keys to related tables such as parties and awards.
  2. parties: This table would contain information about the parties involved in a contract, such as the buyer, supplier, and contracting entity. It could include fields such as the party's name, address, and contact information.
  3. awards: This table would contain information about the awards made under a contract, such as the award date, value, and supplier. It could also include foreign keys to related tables such as contracts and parties.
  4. tenders: This table would contain information about the tenders issued for a contract, such as the tender title, description, and submission deadline. It could also include foreign keys to related tables such as contracts and parties.
  5. milestones: This table would contain information about the milestones achieved under a contract, such as the milestone name, completion date, and status. It could also include foreign keys to related tables such as contracts.
  6. amendments: This table would contain information about any amendments made to a contract, such as the amendment date, description, and value. It could also include foreign keys to related tables such as contracts.
  7. documents: This table would contain information about any documents related to a contract, such as the document title, type, and date added. It could also include foreign keys to related tables such as contracts and parties.

This structure is just an example, and the actual structure will depend on the complexity of the current implementation and the data structure; a more detailed analysis will be needed.

It’s important to note that the above structure is optimised for data storage and management. Still, it’s better to use a data modeling tool like OLAP Cube or Data warehousing to make it more efficient and more flexible when it comes to data analysis and reporting.

Here is an example of a possible database structure for aligning an existing Government Procurement Portal to the Open Contracting Data Standard (OCDS), presented as tables with key fields as columns:

contracts table:

parties table:

awards table:

tenders table:

milestones table:

amendments table:

documents table:

Here is an example of sample source code that would produce the corresponding migration files using the Laravel framework:

php artisan make:migration create_contracts_table --create=contracts
php artisan make:migration create_parties_table --create=parties
php artisan make:migration create_awards_table --create=awards
php artisan make:migration create_tenders_table --create=

Build Models and Controllers

Building the portal is like constructing a house where the Database is the foundation, Models are the bricks, and the Controllers would be the cement that holds everything together.

So, once the migrations have successfully been added to the database, I would start working on the Models and then the Controllers.

Creating Models

To write the models for the above tables in a Laravel application, you can use the following command to generate a model for each table:

php artisan make:model Contract
php artisan make:model Party
php artisan make:model Award
php artisan make:model Tender
php artisan make:model Milestone
php artisan make:model Amendment
php artisan make:model Document

Each model file will be created in the app directory and have a class corresponding to the table.

Each model will have attributes and methods corresponding to the columns in the table, and you can use Eloquent ORM to interact with the table.

Once the models are generated, you need to define the relationships between the models. In addition, I would also use Laravel’s built-in validation to ensure that the data being saved to the database meets certain criteria. You can add validation rules to the Contract model to ensure that the contract_id is unique and that the title is not empty:

For example, I would define the one-to-many relationship between Contracts and Awards, Tenders, Milestones, Amendments, and Documents by adding the following code to the Contract model:

class Contract extends Model
{
public function awards()
{
return $this->hasMany(Award::class);
}
public function tenders()
{
return $this->hasMany(Tender::class);
}
public function milestones()
{
return $this->hasMany(Milestone::class);
}
public function amendments()
{
return $this->hasMany(Amendment::class);
}
public function documents()
{
return $this->hasMany(Document::class);
}
public static $rules = [
'contract_id' => 'required|unique:contracts',
'title' => 'required',
];
}

and in the Party Model, you can define one-to-many relationship between Party and Award and Document by adding the following code:

class Party extends Model
{
public function awards()
{
return $this->hasMany(Award::class);
}

public function documents()
{
return $this->hasMany(Document::class);
}
}

Create Controllers

I would then use Laravel’s built-in controllers to handle the request and response to access the database; You can use the following command to generate a controller for each model:

php artisan make:controller ContractController --model=Contract
php artisan make:controller PartyController --model=Party
php artisan make:controller AwardController --model=Award
php artisan make:controller TenderController --model=Tender
php artisan make:controller MilestoneController --model=Milestone
php artisan make:controller AmendmentController --model=Amendment

I would use these controllers to handle the CRUD operations and also validation.

Finally, I would use Laravel’s built-in routing to map URLs to the controllers’ actions. For example, I would map the URL /contracts to the index action of the ContractController:

Route::get('/contracts', 'ContractController@index');

However, this is just a starting point, and one may need to customise the code and add additional features based on your specific requirements and use case.

Here’s an example of how a new contract would be created from the controller.

$contract = new Contract;
$contract->contract_id = 'OCDS-12345-ABC';
$contract->title = 'Construction of a new road';
$contract->save();

One can then retrieve an existing contract by using the find method on the Contract model:

$contract = Contract::find('OCDS-12345-ABC');

One can also retrieve all contracts using the all method:

$contracts = Contract::all();

One could update an existing contract by first retrieving it, updating its attributes, and then saving it:

$contract = Contract::find('OCDS-12345-ABC');
$contract->title = 'Construction of a new highway';
$contract->save();

One can delete an existing contract by first retrieving it and then calling the delete method:

$contract = Contract::find('OCDS-12345-ABC');
$contract->delete();

Getting a contract and all its other information.

You can also use Eloquent’s eager loading to retrieve the related models with a single query. For example, you can retrieve all contracts along with their related awards, tenders, milestones, amendments, and documents by using the with method:

$contracts = Contract::with('awards', 'tenders', 'milestones', 'amendments', 'documents')->get();

It’s important to note that you need to have the database and tables created before running these operations, and also make sure to configure your database connection in the .env file. Also, the above is just a sample code; you may need to adjust it based on your specific requirements and use case.

Paginating your results

In addition to the above, I would also use Laravel’s built-in pagination to display the contracts, awards, tenders, milestones, amendments, and documents in a more user-friendly way. For example, I would use the paginate method on the Contract model to retrieve a certain number of contracts per page:

$contracts = Contract::paginate(10);

Searching, Sorting and Filtering.

I would then use Laravel’s built-in search functionality to filter the data based on certain criteria. For example, you can use the where method on the Contract model to filter contracts by title:

$contracts = Contract::where('title', 'like', '%Construction%')->paginate(10);

I would use Laravel’s built-in sorting functionality to sort the data based on certain criteria. For example, you can use the orderBy method on the Contract model to sort contracts by date:

$contracts = Contract::orderBy('date', 'desc')->paginate(10);

Exporting to CSV

I would use Laravel’s built-in export functionality to export the data to different formats such as CSV, Excel, PDF, etc. For example, you can use the toArray method on the Contract model to export contracts to a CSV file:

$contracts = Contract::all();
$contracts_array = $contracts->toArray();
Excel::create('contracts', function($excel) use($contracts_array) {
$excel->sheet('contracts', function($sheet) use($contracts_array) {
$sheet->fromArray($contracts_array);
});
})->export('csv');

Step 3: Build the API.

Once the database is set up, I would then proceed to build the API. This would involve creating routes for accessing the data and defining the methods for retrieving and updating the data.

To create an API for the Government Procurement Portal, I would use Laravel’s built-in support for creating APIs. Here are the steps you can follow to create an API for your application:

  1. Create a new route group for your API routes: In your routes/web.php file, you can create a new route group for your API routes by prefixing them with /api. For example:
Route::prefix('api')->group(function () {
Route::get('/contracts', 'Api\ContractsController@index');
Route::get('/contracts/{id}', 'Api\ContractsController@show');
Route::post('/contracts', 'Api\ContractsController@store');
Route::put('/contracts/{id}', 'Api\ContractsController@update');
Route::delete('/contracts/{id}', 'Api\ContractsController@destroy');
});

Using an API would require making certain amendments in the controller so that JSON responses are returned.

class ContractsController extends Controller
{
public function index()
{
$contracts = Contract::all();
return response()->json($contracts);
}

public function show($id)
{
$contract = Contract::find($id);
return response()->json($contract);
}

public function store(Request $request)
{
$contract = Contract::create($request->all());
return response()->json($contract, 201);
}

public function update(Request $request, $id)
{
$contract = Contract::findOrFail($id);
$contract->update($request->all());
return response()->json($contract, 200);
}

public function destroy($id)
{
Contract::destroy($id);
return response()->json(null, 204);
}
}

Following those steps, you can create a basic API for the Portal that adheres to the Open Contracting Data Standard.

Depending on your specific requirements, you may need to customise the code and add additional features to your API.

The next step would be to test and deploy your API.

  1. Testing: Before deploying your API, it’s important to thoroughly test it to ensure it’s working as expected. You can use tools like Postman to test your API routes and check the responses.
  2. Deployment: Once you’ve tested your API and are satisfied with its performance, you can deploy it to a production server. You can use various hosting services such as Amazon Web Services, Google Cloud Platform, or Heroku to deploy your API or Government Hosted Server.
  3. Monitoring and Maintenance: After deploying your API, it’s important to monitor its performance and address any issues that arise. This can include monitoring for errors, tracking resource usage, and ensuring that the API is accessible and responsive. It would be best if you kept your API updated with the latest security patches and updates.
  4. Document the API: A final step would be to document the API to provide easy access to information on how to use the API, expected inputs and outputs, endpoints and other relevant information. This can be done by using tools like Swagger, Postman and others that allow creating a clear and interactive documentation.

By following these steps, one will have a properly deployed and maintained API that adheres to the Open Contracting Data Standard, allowing other parties to access the data and use it for different purposes.

Step 4: Providing training and support

Providing training and support is essential to ensuring the success of a government procurement portal that complies with the Open Contracting Data Standard (OCDS). The following are some key considerations for providing training and support to users of the portal:

  1. Offer comprehensive training: It is important to provide users with comprehensive training on how to use the portal and comply with OCDS standards. This can include on-demand video tutorials, webinars, and in-person training sessions.
  2. Provide user guides and documentation: User guides and documentation can help users understand how to use the portal and troubleshoot any issues they may encounter. These resources should be easily accessible and kept up-to-date.
  3. Establish a support team: A dedicated support team can help users with questions or issues. The team should be responsive and have the necessary knowledge and expertise to assist users.
  4. Encourage feedback and suggestions: Encouraging feedback and suggestions from users can help identify areas for improvement and ensure the portal is meeting users' needs.
  5. Continual training and support: As the technology or standards change, users must be offered continued training and support. This can include updates on new features, changes to the portal, and training on new OCDS standards or best practices.

Step 5: Monitoring and maintaining the API

Monitoring and maintaining the API of a government procurement portal that complies with the Open Contracting Data Standard (OCDS) is crucial for ensuring the portal’s performance and security. The following are some key considerations for monitoring and maintaining the API:

  1. Monitor API performance: Regularly monitoring the API’s performance, such as response time and error rates, can help identify and resolve any issues. This can be done through application performance monitoring (APM) software.
  2. Test the API: Regularly testing the API can help ensure it functions correctly and identify any bugs or vulnerabilities. This can include unit testing, integration testing, and penetration testing.
  3. Keep the API up-to-date: It’s important to keep the API up-to-date with the latest security patches and updates. This can help prevent security breaches and ensure the API complies with OCDS standards.
  4. Monitor for security threats: Regularly monitoring for security threats, such as hacking attempts, can help prevent security breaches and protect sensitive procurement data.
  5. Establish a backup and recovery plan: In case of any unexpected incidents, it is important to have a backup and recovery plan in place to restore the data and functionality of the API as quickly as possible.

By monitoring and maintaining the API, the government procurement portal can ensure the performance and security of the portal and comply with OCDS standards. This will ultimately lead to a more transparent and efficient procurement process for the government.

--

--

cengkuru michael
cengkuru michael

Written by cengkuru michael

I turn data into meaningful stories by analyzing and visualizing information to create a cohesive narrative. Love helping others see the world in a new light.

No responses yet