We have been gradulally adding support to cht-datasource for persons, places, and reports.
I am proposing that we continue expanding the formal CHT data model to include “target intervals” (aka the data currently recorded in target docs). The motivation here is provided by the new effort to Display targets from the previous month. As a part of that effort, @paulalogno has been working to add support at the webapp service layer for getting a users target doc from the previous month.
The code Paul is adding is very similar to code we already have in the target aggregates service that is also getting target docs. That existing code in the target aggregate service feeds the analytics.getTargetDocs
function that is currently available to targets/tasks/contact-summary.
All of this got me to thinking that target data should exist as a first-class citizen in the CHT data model and should be accessible via cht-datasource and its related REST endpoints. This would give the various code in webapp a single place to go for accessing historical target data (instead of various places all manually querying the db for it).
Thoughts? Does this seem like a bad idea for some reason? Do targets not belong in the data model? I liked this example as a good test case around what really should belong (since persons/places/reports are pretty obvious).
Here is the proposed TS api code that we could start with:
qualifier.ts
/**
* A qualifier that identifies entities based on a reporting period. (e.g. "2025-07")
*/
export interface ReportingPeriodQualifier {
readonly reportingPeriod: string;
}
/**
* A qualifier that identifies entities based on a username (without the "org.couchdb.user:" prefix).
*/
export interface UsernameQualifier {
readonly username: string
}
target-interval.ts
/** */
export namespace v1 {
/**
* Data from an interval about a particular target for a user.
*/
export interface Target extends DataObject {
readonly id: string;
readonly value: {
readonly pass: number;
readonly total: number;
readonly percent?: number;
}
}
/**
* Data about a user's targets from a particular interval.
*/
export interface TargetInterval extends Doc {
readonly user: string;
readonly owner: string;
readonly reporting_period: string;
readonly updated_date: number;
readonly targets: Target[];
}
/**
* Returns a target interval for the given qualifier.
* @param context the current data context
* @returns the target interval or `null` if no target interval is found for the qualifier
* @throws Error if no context is provided or if the context is invalid
*/
export const get = (
context: DataContext
) => {
/**
* Returns the target interval identified by the given qualifier.
* @param qualifier the limiter defining which target interval to return
* @returns the identified target interval
* @throws InvalidArgumentError if no qualifier is provided or if the qualifier is invalid
*/
return (
qualifier: ReportingPeriodQualifier & UsernameQualifier
): Promise<Nullable<TargetInterval>> => ...
}
}
Cons:
- More effort than just centralizing logic in a webapp service or something.
- Possibly makes it harder to evolve the target functionality in the future by making the structure of the target docs part of the public api.
Pros:
- Further reduces direct DB access from client-side code (encapsulating the data-access in cht-datasource provides an abstraction layer, both logical an actual, between client code and Couch).
- Provide consistent, documented access to target data both to internal cht-code as well as externally via the REST apis.
- Gives us a version-able interface that can allow for future revisions while coherently maintaining backwards compatibility.