Init commit

This commit is contained in:
2026-02-27 21:40:40 -04:00
commit 2946e724ab
3 changed files with 488 additions and 0 deletions

0
README.md Normal file
View File

293
cppbessot.md Normal file
View File

@@ -0,0 +1,293 @@
This is a sophisticated, "bulletproof" architecture. By treating your database schema versions as immutable snapshots and forcing the generators to run as a deliberate manual step, youre eliminating the "it worked on my machine" drift that plagues C++ development.
The following summary is designed to be pasted into **Cursor's** composer or chat. It provides the exact technical constraints and folder logic the AI needs to write modular, high-quality CMake files without making "lucky guesses" about your intent.
---
# Design Spec: CppBeSSOT (C++ Backend Single-Source-of-Truth)
## 1. Context & Objectives
**CppBeSSOT** is a modular system for managing a C++ backend SSOT. It uses **OpenAPI YAML** files (one per table) as the source to drive C++ ORM code (ODB), JSON serialization, TypeScript types, and Zod validation schemas.
* **Backend:** C++ (ODB ORM + JSON library).
* **Preferred JSON Serdes Provider:** `nlohmann::json`.
* **JSON Serdes Placement:** Generated model classes should expose JSON serde in class definitions as class methods (not only external helpers).
* **Frontend:** TypeScript + Zod.
* **Migrations:** Automated SQL diffs generated by ODB's Schema Evolution engine.
* **Integration:** Designed as a git submodule to be included in larger projects.
**Dependencies (C++):** Generated C++ models depend on the **nlohmann/json** header-only library for JSON serialization (`toJson()` / `fromJson()` and the `NLOHMANN_DEFINE_TYPE_INTRUSIVE` macro). The build must have access to nlohmann headers (e.g. package `nlohmann-json3-dev` on Debian/Ubuntu). Treat this as a build-time (and runtime, if you ship the generated code) dependency; the dependency check or project README should document it.
## 2. Directory Structure & Configuration
* **`${CPPBESSOT_WORKDIR}`**: Configurable via CMake (default: `db`). Contains the versioned data.
* **Submodule Path**: The CMake logic resides in a submodule (e.g., `cmake/cppbessot/`).
* **Folder Structure**:
```text
${CPPBESSOT_WORKDIR}/
├── v<N>/ # Immutable version snapshots
│ ├── openapi/ # Source YAMLs + Mustache templates
│ ├── generated-ts-types/ # Output: TS interfaces
│ ├── generated-zod/ # Output: Zod TS schemas
│ ├── generated-cpp-source/ # Output: C++ Headers (with ODB & JSON macros)
│ ├── generated-sql-ddl/ # Output: ODB-generated SQL DDL snapshots for this schema version
│ │ ├── sqlite/ # SQLite DDL output for this version
│ │ └── postgre/ # PostgreSQL DDL output for this version
│ └── generated-odb-source/ # Output: ODB compiler artifacts (+ per-backend changelog .xml)
│ ├── sqlite/ # SQLite ORM + changelog (e.g. Agent.xml, DeliveryRequest.xml)
│ └── postgre/ # PostgreSQL ORM + changelog
└── migrations/ # Version-to-version SQL diffs
└── v<a>-v<b>/
├── sqlite/
└── postgre/
```
**Schema version numbering:** CppBeSSOT schema version folders (e.g. `v1.1`, `v1.2`) **must start at 1.x**. ODBs schema evolution uses `#pragma db model version(base, current)` for migration diffing, and both `base` and `current` must be **non-zero** positive integers. Using 0.x (e.g. `v0.0`, `v0.1`) would require a zero version in the pragma, which ODB rejects. Therefore the first schema version is `v1.1`, the next `v1.2`, and so on.
## 3. Modular CMake Architecture
All CMake files are located in the submodule directory. The entry point is `CppBeSSOT.cmake`.
* **`CppBeSSOT.cmake`**: The master include file.
* **`dbDependencyCheck.cmake`**: Checks for `odb`, `npx`, `java`, `git`, `openapi-zod-client`, and availability of **nlohmann/json** headers (e.g. include path or package). Fails if missing.
* **`dbGenerationCommon.cmake`**: Internal utility functions (path resolution, version validation).
* **Individual Logic Files**: `dbGenTS.cmake`, `dbGenZod.cmake`, `dbGenCpp.cmake`, `dbGenODB.cmake`, `dbGenSqlDDL.cmake`.
## 4. Primary Build Targets
### Target: `db_check_schema_changes`
* **Action**: Runs `git status --porcelain ${CPPBESSOT_WORKDIR}/`.
* **Behavior**: If changes are detected in git-tracked files within the workdir, it issues a `WARNING` or `SEND_ERROR` advising the dev to create a new version folder and re-run generation.
### Target: `db_gen_orm_serdes_and_zod`
* **Variable**: `-DDB_SCHEMA_VERSION_TO_GENERATE="v1"`
* **Sub-targets** (One for each `generated-*` folder):
1. `db_gen_ts`: `openapi-generator-cli` -> TS types.
2. `db_gen_zod`: `openapi-zod-client --export-schemas` -> Zod schemas.
3. `db_gen_cpp_headers`: `openapi-generator-cli` + Mustache templates -> C++ headers with ODB `#pragma` and JSON macros. Do not run in models-only mode; generate supporting files too (for example `ModelBase.h` and related runtime support headers/sources required by generated models).
4. `db_gen_odb_logic`: `odb` compiler (with `--changelog-dir` to the same backend subdir under generated-odb-source) -> generated-odb-source.
5. `db_gen_sql_ddl`: `odb --generate-schema --schema-format sql` with `--changelog-dir` pointing at the corresponding generated-odb-source backend subdir -> generated-sql-ddl (sqlite/postgre DDL snapshots); changelog XML remains in generated-odb-source.
### Target: `db_gen_migrations`
* **Variables**: `-DDB_SCHEMA_MIGRATION_VERSION_FROM="v1"` and `-DDB_SCHEMA_MIGRATION_VERSION_TO="v2"`
* **Action**: Uses ODB's Schema Evolution engine to compare headers in `FROM` vs `TO`.
* **Output**: SQL migration scripts for both SQLite and PostgreSQL.
### Target: `db_gen_sql_ddl`
* **Variable**: `-DDB_SCHEMA_VERSION_TO_GENERATE="v1"`
* **Action**: Runs ODB schema generation for each supported backend for the selected version.
* **Output**: Backend-specific SQL DDL under `${CPPBESSOT_WORKDIR}/v1/generated-sql-ddl/` (for example `sqlite/` and `postgre/`).
## 5. Implementation Requirements for Cursor
1. **No Absolute Paths**: All paths must be relative to `PROJECT_SOURCE_DIR` or calculated via `CMAKE_CURRENT_LIST_DIR`.
2. **Persistence**: Generated files are **Git-tracked** and must not be deleted by `make clean`.
3. **Manual Trigger**: Targets should be `EXCLUDE_FROM_ALL`.
4. **Submodule Awareness**: The CMake files will be in a subdirectory of the `bigproject`. Ensure `CppBeSSOT.cmake` correctly includes its sibling `.cmake` files.
5. **Generated Library Names**:
- Build a library from `db/v<N>/generated-cpp-source/` named `libcppBeSsotOpenAiModelGen` (static or shared is allowed).
- Build backend-specific libraries from `db/v<N>/generated-odb-source/` named:
- `libcppBeSsotOdbSqlite`
- `libcppBeSsotOdbPgSql`
- Treat ODB backend libs as likely shared objects.
6. **Prompt/Instruction File for OpenAPI Authors**: In the final generated project, add an instruction file for LLM agents that create or update OpenAPI schema files. The instruction file must state:
- Use `lowerCamelCase` for property names.
- Use `UpperCamelCase` for class/schema names.
- Do not use underscores in class names or property names.
7. **No Version in C++ Namespace**: Generated C++ model namespaces must not encode schema version names. The wider project should not need version-coupled source code identifiers; schema version selection should be done via include path selection (for example, `include_directories` pointing at the desired generated version).
8. **Template Bootstrap Input**: Use the current checked-in Mustache templates under `${CPPBESSOT_WORKDIR}/v<N>/openapi/templates/` as initial test inputs when bringing up generation and CMake flows. Treat these templates as the baseline that should work first before further refactoring.
### Minimum annotations for ODB migration diffing
For ODBs schema evolution to produce migration diffs between two schema versions, the following annotations are required.
**In each OpenAPI schema YAML (per-table, under `openapi/schema/`):**
* **`x-odbModelVersion: "M, N"`** — Model version for this schema (e.g. `"1, 1"` for v1.1, `"1, 2"` for v1.2). Used only for documentation; the Mustache template must emit the actual ODB pragma with **non-zero** integers (e.g. `(1, 1)` for first version, `(1, 2)` for next).
* **`x-odbTable: TableName`** — Exact table name for `#pragma db object table("...")` (e.g. `Agent`, `DeliveryRequest`).
* **`x-odbId: true`** — On the primary-key property (e.g. `id`) so the template can emit `#pragma db id` for that member.
* **`x-odbAddedIn: "M.N"`** — On every persistent property, indicating the schema version where the column was added (e.g. `"1.0"`, `"1.1"`). Enables correct versioning of new columns in migrations.
**In the Mustache model-header template:**
* **`#include <odb/core.hxx>`** — So ODB sees the pragmas.
* **`#pragma db model version(base, current)`** — One per model; `base` and `current` must be non-zero. Typically the first schema version uses `(1, 1)` and the next `(1, 2)`. The template may hardcode these per version or derive from `x-odbModelVersion` (mapping 1.0→1,1 and 1.1→1,2).
* **`#pragma db object table("...")`** — From `x-odbTable` (or `classname` fallback).
* **`#pragma db id`** — Placed immediately before the member that has `x-odbId: true`.
Without these, ODB will not generate schema DDL or migration diffs correctly.
### Keeping changelog XML per backend in `generated-odb-source`
ODB writes schema evolution changelog files (e.g. `Agent.xml`, `DeliveryRequest.xml`) next to the **input** `.h` files by default; `--output-dir` does **not** change that. Changelog files are database-specific, so if you run SQLite then PostgreSQL (or vice versa) without redirecting them, the second run sees the first backends changelog and can fail with "wrong database" errors.
Use **`--changelog-dir`** so changelog is read from and written to the same backend-specific directory as the ORM output:
* For **ORM** (`odb ... -q -o .../generated-odb-source/sqlite`): add `--changelog-dir .../generated-odb-source/sqlite` so any changelog lives under `generated-odb-source/sqlite/`.
* For **SQL DDL** (`odb ... --generate-schema --schema-format sql -o .../generated-sql-ddl/sqlite`): add `--changelog-dir .../generated-odb-source/sqlite` so the changelog stays in `generated-odb-source` (not next to the headers or in `generated-sql-ddl`). Same for `postgre` with `generated-odb-source/postgre` and `generated-sql-ddl/postgre`.
Result: each backend has its own `generated-odb-source/<backend>/*.xml`; you can run SQLite and PostgreSQL in any order without deleting changelog between runs. CMake/scripts should pass `--changelog-dir` on every `odb` invocation (ORM and DDL) for each backend.
---
## 6. Manual generation commands (OpenAPI → migrations)
Run all commands from the project repository root. Prerequisites: `npx`, `odb` compiler, and nlohmann/json headers. The current proof-of-concept uses schema versions **v1.1** (first) and **v1.2** (second, adds e.g. `booyah` to Agent).
### v1.1 — from OpenAPI through SQL DDL
```bash
# 1. C++ model headers
npx @openapitools/openapi-generator-cli generate -i db/v1.1/openapi/openapi.yaml -g cpp-restsdk -t db/v1.1/openapi/templates/cpp-odb-json -c db/v1.1/openapi/templates/cpp-odb-json/config.yaml -o db/v1.1/generated-cpp-source
# 2. Create ODB and DDL output dirs
mkdir -p db/v1.1/generated-odb-source/sqlite db/v1.1/generated-odb-source/postgre \
db/v1.1/generated-sql-ddl/sqlite db/v1.1/generated-sql-ddl/postgre
# 3. ODB ORM (changelog goes to generated-odb-source/<backend>)
odb -I db/v1.1/generated-cpp-source/include --std c++11 -d sqlite -q \
-o db/v1.1/generated-odb-source/sqlite --changelog-dir db/v1.1/generated-odb-source/sqlite \
db/v1.1/generated-cpp-source/include/cppbessot_v1_1/model/Agent.h db/v1.1/generated-cpp-source/include/cppbessot_v1_1/model/DeliveryRequest.h
odb -I db/v1.1/generated-cpp-source/include --std c++11 -d pgsql -q \
-o db/v1.1/generated-odb-source/postgre --changelog-dir db/v1.1/generated-odb-source/postgre \
db/v1.1/generated-cpp-source/include/cppbessot_v1_1/model/Agent.h db/v1.1/generated-cpp-source/include/cppbessot_v1_1/model/DeliveryRequest.h
# 4. SQL DDL
odb -I db/v1.1/generated-cpp-source/include --std c++11 -d sqlite --generate-schema --schema-format sql -q \
-o db/v1.1/generated-sql-ddl/sqlite --changelog-dir db/v1.1/generated-odb-source/sqlite \
db/v1.1/generated-cpp-source/include/cppbessot_v1_1/model/Agent.h db/v1.1/generated-cpp-source/include/cppbessot_v1_1/model/DeliveryRequest.h
odb -I db/v1.1/generated-cpp-source/include --std c++11 -d pgsql --generate-schema --schema-format sql -q \
-o db/v1.1/generated-sql-ddl/postgre --changelog-dir db/v1.1/generated-odb-source/postgre \
db/v1.1/generated-cpp-source/include/cppbessot_v1_1/model/Agent.h db/v1.1/generated-cpp-source/include/cppbessot_v1_1/model/DeliveryRequest.h
```
### v1.2 — from OpenAPI through SQL DDL
```bash
# 1. C++ model headers
npx @openapitools/openapi-generator-cli generate -i db/v1.2/openapi/openapi.yaml -g cpp-restsdk -t db/v1.2/openapi/templates/cpp-odb-json -c db/v1.2/openapi/templates/cpp-odb-json/config.yaml -o db/v1.2/generated-cpp-source
# 2. Create ODB and DDL output dirs
mkdir -p db/v1.2/generated-odb-source/sqlite db/v1.2/generated-odb-source/postgre \
db/v1.2/generated-sql-ddl/sqlite db/v1.2/generated-sql-ddl/postgre
# 3. ODB ORM
odb -I db/v1.2/generated-cpp-source/include --std c++11 -d sqlite -q \
-o db/v1.2/generated-odb-source/sqlite --changelog-dir db/v1.2/generated-odb-source/sqlite \
db/v1.2/generated-cpp-source/include/cppbessot_v1_2/model/Agent.h db/v1.2/generated-cpp-source/include/cppbessot_v1_2/model/DeliveryRequest.h
odb -I db/v1.2/generated-cpp-source/include --std c++11 -d pgsql -q \
-o db/v1.2/generated-odb-source/postgre --changelog-dir db/v1.2/generated-odb-source/postgre \
db/v1.2/generated-cpp-source/include/cppbessot_v1_2/model/Agent.h db/v1.2/generated-cpp-source/include/cppbessot_v1_2/model/DeliveryRequest.h
# 4. SQL DDL
odb -I db/v1.2/generated-cpp-source/include --std c++11 -d sqlite --generate-schema --schema-format sql -q \
-o db/v1.2/generated-sql-ddl/sqlite --changelog-dir db/v1.2/generated-odb-source/sqlite \
db/v1.2/generated-cpp-source/include/cppbessot_v1_2/model/Agent.h db/v1.2/generated-cpp-source/include/cppbessot_v1_2/model/DeliveryRequest.h
odb -I db/v1.2/generated-cpp-source/include --std c++11 -d pgsql --generate-schema --schema-format sql -q \
-o db/v1.2/generated-sql-ddl/postgre --changelog-dir db/v1.2/generated-odb-source/postgre \
db/v1.2/generated-cpp-source/include/cppbessot_v1_2/model/Agent.h db/v1.2/generated-cpp-source/include/cppbessot_v1_2/model/DeliveryRequest.h
```
### Migration v1.1 → v1.2
Uses v1.1 changelog XML as input and v1.2 headers; writes migration SQL to `db/migrations/v1.1-v1.2/<backend>/`. One ODB invocation per model per backend (ODB requires one `--changelog-in` / `--changelog-out` pair per input header).
```bash
mkdir -p db/migrations/v1.1-v1.2/sqlite db/migrations/v1.1-v1.2/postgre
# SQLite
odb -I db/v1.2/generated-cpp-source/include --std c++11 -d sqlite --generate-schema --schema-format sql -q \
-o db/migrations/v1.1-v1.2/sqlite \
--changelog-in db/v1.1/generated-odb-source/sqlite/Agent.xml \
--changelog-out db/v1.2/generated-odb-source/sqlite/Agent.xml \
db/v1.2/generated-cpp-source/include/cppbessot_v1_2/model/Agent.h
odb -I db/v1.2/generated-cpp-source/include --std c++11 -d sqlite --generate-schema --schema-format sql -q \
-o db/migrations/v1.1-v1.2/sqlite \
--changelog-in db/v1.1/generated-odb-source/sqlite/DeliveryRequest.xml \
--changelog-out db/v1.2/generated-odb-source/sqlite/DeliveryRequest.xml \
db/v1.2/generated-cpp-source/include/cppbessot_v1_2/model/DeliveryRequest.h
# PostgreSQL
odb -I db/v1.2/generated-cpp-source/include --std c++11 -d pgsql --generate-schema --schema-format sql -q \
-o db/migrations/v1.1-v1.2/postgre \
--changelog-in db/v1.1/generated-odb-source/postgre/Agent.xml \
--changelog-out db/v1.2/generated-odb-source/postgre/Agent.xml \
db/v1.2/generated-cpp-source/include/cppbessot_v1_2/model/Agent.h
odb -I db/v1.2/generated-cpp-source/include --std c++11 -d pgsql --generate-schema --schema-format sql -q \
-o db/migrations/v1.1-v1.2/postgre \
--changelog-in db/v1.1/generated-odb-source/postgre/DeliveryRequest.xml \
--changelog-out db/v1.2/generated-odb-source/postgre/DeliveryRequest.xml \
db/v1.2/generated-cpp-source/include/cppbessot_v1_2/model/DeliveryRequest.h
```
---
### Suggested First Prompt for Cursor:
> "Based on the CppBeSSOT Design Spec, please create the entry-point `cmake/cppbessot/CppBeSSOT.cmake` and the `cmake/cppbessot/dbDependencyCheck.cmake` file. Ensure the dependency check specifically looks for the `odb` compiler and `npx`, and provide clear error messages for Ubuntu users if they are missing."
**Would you like me to draft a sample `dbGenerationCommon.cmake` that handles the boilerplate of resolving the folder paths for a specific version?**
----
Prompt that generated this output from Gemini:
Yea: so I've decided my tech stack for SSOT, JSON serdes, ORM and DB migrations will be ODB + a C++ Json lib. The migration diffs are more powerful and maintainable; the cost of just adding a line to the openapi template is much lower than the cost of potentially having to deal with [semi-]manual migrations. Ok. Write up a summary of the design I'm trying to get done here, in a format that is accurate enough to immediately inform Cursor of what I'm trying to build, and therefore able to help Cursor to generate the build system commands for CMake that are required to construct the chain of operations from the OpenAPI SSOT to the end result of the generated ODB headers, JSON serdes support, migrations, ODB ORM, and Zod schema enforcement.
The ideal thing is that I have a folder structure like this:
/project
* db/ # DB related stuff.
  * v<N>/ # Each version of the DB is saved in its own folder. We can look at past versions. Creating a new version just consists of copying the old one and then modifying it and incrementing the version number.
    * openapi/ # OpenAPI stuff in here.
      * <template files>
      * schema/ # OpenAPI yaml files for each table in here.
    * generated-ts-types/ # In here we place the OpenAPI-generated TS types.
    * generated-zod/ # In here we place the openapi-zod-client generated Zod TS schema files.
    * generated-cpp-source/ # In here we place the openapi-generator-cli generated C++ headers and JSON serdes.
    * generated-odb-source/ # In here we place the ODB generated C++ ORM stuff.
  * migrations/ # Subfolders here contain SQL statements to go from v<a> to v<b>.
    * v<a>-v<b>/
      * sqlite/ # Migrations SQL specific to SQLite.
      * postgre/ # Migrations SQL specific to postgre.
The content in the generated-* subdirs will be added to git version control. The goal is to have them generated once on each schema change, and then accessible thereafter forever. So generating the content in the generated-* subdirs is not a standard build step. It's a separate build/make target which the dev must run manually when xe updates the schema. Perhaps we could have a build system step that checks the `git diff` or `git status`, and if any files under the db/ subdir have been changed, we have CMake print a warning, advising the dev to create a new version and re-run the generation targets.
There are 2 targets we want for the build system:
1. Generate all generated-* content in the generated-* subdirs of the v<N> subdir. The name of the "v<N>" subdir is supplied via CMake -DDB_SCHEMA_VERSION_TO_GENERATE="<version_folder_name>". The name of the target that runs this should be "db_gen_orm_serdes_and_zod".
2. This one should be basically agnostic of what the "current version" is, because it should be supplied with 2 input arguments via -DDB_SCHEMA_MIGRATION_VERSION_FROM="<from_version_folder_name>" and -DDB_SCHEMA_MIGRATION_VERSION_TO="<to_version_folder_name>". It should then output the migrations required to go from <from> to <to> inside of /db/migrations/v<from>-v<to>/. This build target's name should be "db_gen_migrations".
The name of the target that checks for git-tracked changes in the db/ subdir should be "db_check_schema_changes".
All of these build system targets should be built modularly, across multiple files to be placed in the top level /cmake subdir. Use subfunctions liberally. Split logically separate or repeated flows into their own callable functions. No long-ass CMake scrawl. For example, maybe each of the different generated-*/ subfolders has its own .cmake file with its specific functions, and there may be a dbGenerationCommon.cmake file with functions included and used by all of them in common.
Each of the generated-*/ subfolders should have its own CMake target, and all of them should be sub-targets of the main `db_gen_orm_serdes_and_zod` target.
The name of the top level "db" folder must be configurable as a CMake var -DCPPBESSOT_WORKDIR="foo", but its default value should be "db". The dev should be able to just change the value of that var and then manually rename the top-level dir, and the CMake scripts should run perfectly fine.
There should be a separate .cmake file (in /cmake) which checks for the availability of the dependencies (odb, npx, openapi-zod-client, and the various openapi cli tools) and fails if they're not available.
The goal is for this C++ backend SSOT (project name: cppbessot) system to be a git submodule of multiple such C++ backend-based systems I'm making. So in practice, the cmake files in /cmake will be part of a cppbessot/ submodule of a larger project. The CPPBESSOT_WORKDIR will be a subdir of the larger project, while the CMake files will be in the submodule. In practice, the deployed system will look something like:
/bigproject
CMakeLists.txt # Bigproject's own CMakeLists, which includes cppbessot/cmake/CppBeSSOT.cmake
* cmake/ # bigproject's own .cmake files.
* cppbessot/ # Git submodule containing the CppBeSSOT subproject and its .cmake files.
* ${CPPBESSOT_WORKDIR}
* v<N>/
* migrations/
So we need a single CMake file that we can include, maybe called CppBeSSOT.cmake, while will include the other .cmake files, and make the cppbessot system available to the larger project.

195
system-spec.md Normal file
View File

@@ -0,0 +1,195 @@
# System Spec:
The system must be able to handle anonymous one-off agents initiating requests.
Persistent users can claim agents to create persistent identities in the system.
Agents are the core actor object.
Agents can have different roles associated with them. Main roles:
*
----
/* I don't know yet how to integrate govt address labels.
* Our system shouldn't care about gov't addresses except as
* search designators. The users think in terms of gov't addresses,
* but we design for coords and polygons. We are trying to move
* pkgs from one MapRegion to another.
*
* The user's supplied address is just a lookup designator for what we
* internally know as a MapRegion. This model automatically gives us
* some resilience against political addressing scheme changes, street
* name changes, etc.
* When a property is sold and consolidated, or split up though, that may
* still be difficult to handle.
*/
class GovernmentAddress
{
};
----
struct MapCoordinate
{
Longitude longitude;
Latitude latitude;
};
MapRegion
{
vector<MapCoordinate> coordinates;
};
----
// This is for information relevant to package delivery.
LogisticsEndpoint: MapRegion
{
sh_ptr<Agent> owner;
};
PackageSource: LogisticsEndpoint
{
};
PackageDestination: LogisticsEndpoint
{
};
class Warehouse: PackageSource, PackageDestination
{};
----
DeliveryRequest
{
sh_ptr<Agent> requester;
sh_ptr<Package> package;
sh_ptr<PackageSource> source;
sh_ptr<PackageDestination> destination;
};
----
/* BridgedTripAttempts routes are how we link couriers together using
* our internal logic. All requests, including those which aren't
* actually bridged (i.e: hops.size()==1), are modeled as bridged trips.
*/
class BridgedTripPlan
{
sh_ptr<DeliveryRequest> deliveryRequest;
vector<sh_ptr<TripPlan>> hops;
};
BridgedTripAttempt
{
sh_ptr<TripAttempt>
};
/* We don't have a notion of persistent "routes". We only have "TripPlans".
* A TripPlan is a proposed path for getting a pkg from a source to a dest.
* It has no persistent hysteretical effect on other future TripPlans.
*
* To whatever extent we have "routes" they are just suggested optimizations
* for fast lookup based on criteria like crime rates, favoured couriers,
* package loss rate, package damage rate, etc.
*/
class TripPlan
{
sh_ptr<Agent> courier;
sh_ptr<PackageSource> source;
sh_ptr<PackageDestination> destination;
sh_ptr<OptimizedRoute> optimizedRoute;
};
/*
* When a TripAttempt is unsuccessful, we just set the TripAttempt's Result
* appropriately
* and then potentially spawn a new Trip object to re-attempt.
*/
class TripAttempt
{
TripAttemptResult result;
sh_ptr<TripPlan> tripPlan;
HandoverRecord handoverRecord;
};
class HandoverRecord
{
string signatureFileName;
};
class TripAttemptResult
{
/* Gov't suspension/termination is when an agent of gov't intervenes in
* a pkg's delivery.
* Compliance suspension/termination is when we internally intervene in
* pkg's delivery in order to enforce government's policy.
* Policy suspension/termination is when we internally intervene in a
* pkg's delivery because it violates an internal policy of ours.
*/
enum Result {
SUCCESS, RETRY, GOVT_SUSPENSION, GOVT_TERIMATION, COMPLIANCE_SUSPENSION, COMPLIANCE_TERMINATION, POLICY_SUSPENSION, POLICY_TERMINATION, CANCELED, FAILURE;
} result;
enum RetryReason { RETRY_WEATHER, RETRY_ROUTE_DISREPAIR, RETRY_LABOUR_STRIKE, RETRY_UNEXPECTED_DANGER } retryReason;
enum GovernmentSuspensionReason { GOVT_SUSPENSION_AWAIT_LICENSE, GOVT_SUSPENSION_AWAIT_INSPECTION } governmentSuspensionReason;
enum GovernmentTermination {
GOVT_TERMINATION_UNKNOWN, GOVT_TERIMINATION_AWAIT_LICENCE_TIMEOUT, GOVT_TERMINATION_SIEZED
} governmentTerminationReason;
enum ComplianceSuspensionReason {
COMPLIANCE_SUSPENSION_MISSING_DOCUMENTATION, COMPLIANCE_SUSPENSION_INSURANCE_EXPIRED,
COMPLIANCE_SUSPENSION_SAFETY_VIOLATION, COMPLIANCE_SUSPENSION_LEGAL_CHECK_PENDING,
COMPLIANCE_SUSPENSION_TEMPORARY_AUDIT
} complianceSuspensionReason;
enum ComplianceTerminationReason {
COMPLIANCE_TERMINATION_DOCUMENTATION_FAILED, COMPLIANCE_TERMINATION_INSURANCE_INVALID,
COMPLIANCE_TERMINATION_PERSISTENT_SAFETY_VIOLATION,
COMPLIANCE_TERMINATION_LEGAL_NONCOMPLIANCE,
COMPLIANCE_TERMINATION_REGULATORY_ORDER
} complianceTerminationReason;
enum PolicySuspensionReason {
POLICY_SUSPENSION_VIOLATED_INTERNAL_RULE,
POLICY_SUSPENSION_PAYMENT_ISSUE,
POLICY_SUSPENSION_TEMPORARY_BAN,
POLICY_SUSPENSION_FRAUD_RISK, POLICY_SUSPENSION_MANUAL_REVIEW
} policySuspensionReason;
enum PolicyTerminationReason {
POLICY_TERMINATION_BLACKLISTED,
POLICY_TERMINATION_REPEATED_POLICY_VIOLATION,
POLICY_TERMINATION_PAYMENT_DEFAULT, POLICY_TERMINATION_FRAUD_CONFIRMED,
POLICY_TERMINATION_MANUAL_BLOCK
} policyTerminationReason;
enum CancelationReason { USER_CANCELED } cancelationReason;
enum FailureReason { FAILURE_PKG_LOST, FAILURE_PKG_STOLEN } failureReason;
string details;
};
----
CrimeProfile
{
};
----
class Courier
{
vector<sh_ptr<MapRegion>> reach;
};
----
Courier: A courier is not the same as an org. A multi-region courier is represented as an org with multiple member couriers. We internally model each branch/repo of a big org as an individual "courier". A courier is a region-locked agent with vehicles for moving packages.
* MapRegion.
*
* ResidentialLocation.
* WarehouseLocation.
*