Description
Description
In new smart scope forms, for project cost estimation we are using building blocks as primitive elements which stores the price/time configuration per valid combination of answers to the various questions. We are storing those building blocks, at the time of project creation, in project_estimations
table. This table has single record per building block identified for the project created, so there may be more than one record per project in this table. Schema of this table is as follows:
CREATE TABLE project_estimations
(
id bigint NOT NULL,
"buildingBlockKey" character varying(255) NOT NULL,
conditions character varying(512) NOT NULL,
price double precision NOT NULL,
quantity integer NOT NULL,
"minTime" integer NOT NULL,
"maxTime" integer NOT NULL,
metadata json NOT NULL DEFAULT '{}'::json,
"projectId" bigint NOT NULL,
"deletedAt" timestamp with time zone,
"createdAt" timestamp with time zone,
"updatedAt" timestamp with time zone,
"deletedBy" bigint,
"createdBy" integer NOT NULL,
"updatedBy" integer NOT NULL,
CONSTRAINT project_estimations_pkey PRIMARY KEY (id)
);
The price per block is the amount topcoder charges to the customer and it includes community budget, topcoder services budget and topcoder fee. We need to store this breakup per block in database so that we can control the access to the price breakup. In ideal scenario:
- A customer would be able to see only total price per block
- A Copilot would be able to see only the community budget per block
- A topcoder employee (CA) would be able to see full price breakup
First approach
We have to add following more field to support the price breakup:
communityBudget double precision NULL,
servicesBudget double precision NULL,
fee double precision NULL,
markupUsed bigint NULL, // reference to `project_markup` table
We have to limit the visibility of these fields based on user role as follows:
- Customer should not be able to view any of these new fields
- Copilot should be able to view ONLY
communityBudget
from these new fields - CA should be able to view all of these fields
We have to make sure that we don't leak any of the fields to unintended users and I think for that we need to use middleware which is applied after the route processing and that middleware should ensure that we follow the rules as specified above.
This table has a column markupUsed
which is a foreign key to another table project_markup
having following schema:
CREATE TABLE project_settings
(
id bigint NOT NULL,
key varchar(255), // e.g. 'markup'
value varchar(255),
valueType enum(int, long, double, string),
"projectId" bigint NOT NULL,
metadata json NOT NULL DEFAULT '{}'::json,
"readRoles": array(varchar),
"writeRoles": array(varchar),
"deletedAt" timestamp with time zone,
"createdAt" timestamp with time zone,
"updatedAt" timestamp with time zone,
"deletedBy" bigint,
"createdBy" integer NOT NULL,
"updatedBy" integer NOT NULL,
CONSTRAINT project_markup_pkey PRIMARY KEY (id)
);
User with roles mentioned in readRoles
(e.g. Customers and Copilots for markup setting) would be able to read the value of that particular setting.
User with roles mentioned in writeRoles
( e.g., CAs) would be able to update that particular setting.
We need to profile follow endpoints for this table:
GET /projects/{id}/settings
- returns settings which contains roles of the caller user
PATCH /projects/{id}/settings/{id}
- update settings which contains roles of the caller user
For now, we don't need POST
and DELETE
endpoints.
Second Approach
Another option is to have the same capability by filtering at row level instead of column level by introducing a new table for storing the price breakup as follows
Proposed schema for such table project_estimations_items
CREATE TABLE project_estimations_items
(
id bigint NOT NULL,
"projectEstimationId" bigint NOT NULL,
price double precision NOT NULL,
type enum(community, topcoder_services, fee) NOT NULL,
markupUsed bigint NULL, // reference to `project_markup` table
"projectId" bigint NOT NULL,
metadata json NOT NULL DEFAULT '{}'::json,
"deletedAt" timestamp with time zone,
"createdAt" timestamp with time zone,
"updatedAt" timestamp with time zone,
"deletedBy" bigint,
"createdBy" integer NOT NULL,
"updatedBy" integer NOT NULL,
CONSTRAINT project_estimations_items_pkey PRIMARY KEY (id)
);
Customer would never get any data from this table via any endpoint.
CAs would get all records from this table (GET /projects/{id}/estimations/{id}/items
)
Copilot would be able to see only community
(it might be configurable via env variables) type records from this table. (GET /projects/{id}/estimations/{id}/items
)
This table has a column markupUsed
which is a foreign key to another table project_markup
having schema as described in first approach
@maxceem Let me know your thoughts. I was kind of inclined towards second approach initially at the start of writing the spec, however the by the time I ended up this spec, I am inclined towards first approach as it seems it is less prone to accidental leaking of the information.