9.9 KiB
name, description
| name | description |
|---|---|
| adminive-development | Use when implementing, modifying, debugging, reviewing, or integrating Adminive descriptors, field presentation, Form/Collection views, Composition manifests, JSON/AMIS generation, managed values, HTTP resources, adapters, Gallery frontend, tests, CMake, install/export, or packaging. Do not use for work confined to Structive internals; use the nested structive-development skill there. |
Adminive Development
Goal
Make changes through Adminive's existing semantic layers instead of bypassing them with framework-specific code. The backend remains the business-schema source of truth; adapters translate that truth into JSON, HTTP, AMIS, or frontend renderer contracts.
Start by reading the source of truth
For public behavior or architecture changes, inspect:
AGENTS.md.backend/library/DESIGN.md.- The closest public header and its focused tests.
README.mdfor the user-facing contract.- If the change reaches
third_party/Structive, readthird_party/Structive/AGENTS.mdand its skill before editing that subtree.
Do not infer an API from the Gallery alone. The public headers and tests define the actual contract.
Pick the correct layer
Use this decision table before editing:
| Need | Owner |
|---|---|
| Native property identity, intrinsic read/write, constraint, synchronization topology | Structive |
| Admin-facing field label/description/control/options/visible condition | Adminive Field Presentation |
| Display/create/edit field selection and logical field layout | Form View |
| Collection columns, query capability, CRUD layout, table/list/cards mode | Collection View |
| Composition of complete Form/Collection/Status components | Composition View |
| Slot source/kind/API contract for an independent frontend | Composition Manifest |
| JSON encoding/decoding protocol | Adminive Core adapter protocol + concrete JSON adapter |
| AMIS renderer JSON | AMIS adapter |
| HTTP route/body/query bridging | httplib/Drogon adapter |
| External prepare/commit/rollback | Resource_Transaction |
| In-process mutable consistency | Managed/Structive synchronization |
Pixel styling/responsive layout for a frontend node |
frontend renderer |
If a proposed feature crosses several rows, keep each concern in its owner instead of creating one all-purpose descriptor flag.
Common implementation recipes
Describe a business object
Prefer explicit field descriptors:
struct Config {
std::string host;
int port{};
};
template <>
struct adminive::Type_Descriptor<Config> {
static auto get() {
using T = Config;
return adminive::object<T>(
"config",
"Config",
ADMINIVE_FIELD(T, host).editable().creatable().label("Host").text_input(),
ADMINIVE_FIELD(T, port).editable().creatable().label("Port").number_input()
);
}
};
Do not add the same field list to React.
Define Form semantics
Put view-specific order/grouping in Type_View_Descriptor<T>, not in the field descriptor:
template <>
struct adminive::Type_View_Descriptor<Config> {
static auto edit() {
using T = Config;
return adminive::edit_form<T>(adminive::vertical(
adminive::use<&T::host>(),
adminive::use<&T::port>()
));
}
};
Keep display/create/edit semantics distinct when they differ.
Define Collection semantics
Start from one collection contract and derive the rendering mode:
const auto base = adminive::collection_view<Row>(
adminive::column<&Row::name>("Name").search(),
adminive::column<&Row::score>("Score").sort()
).default_sort("score");
const auto item = adminive::collection_item<&Row::name>().body<&Row::score>();
const auto table = base.as_table();
const auto list = base.as_list(item);
const auto cards = base.as_cards(item, 3);
sort(), search(), and filter() are backend capabilities. Both httplib and Drogon must pass dynamic query fields to Collection_Service, which rejects fields not authorized by the View Schema.
Compose complete components
Use Composition instead of hand-building AMIS containers:
const auto page = adminive::composition_view("device_page", adminive::compose::vertical(
adminive::compose::slot("config"),
adminive::compose::slot("devices")
));
Use compose::frontend(...) only when the backend intentionally delegates final positioning. For an independent frontend, expose a Composition Manifest with a unique Slot Contract for every referenced slot.
Adapt an external value type
Use Value_Adapter<T, Json> when a wrapper has a stable model value. Use Control_Adapter<T, Json> only when the renderer itself needs custom behavior. Keep JSON-framework details out of backend/library.
Adapt enums or reflected aggregates
- Enum semantics go through
Enum_Adapter<Enum>; includeadminive/adapters/magic_enum.hpponly when that bridge is desired. - Aggregate reflection goes through
Reflection_Adapter<T>; use the Boost.PFR bridge only in the service layer. - Do not make Adminive Core include magic_enum, Boost.PFR, nlohmann JSON, cpp-httplib, or Drogon.
Expose a mutable resource
Use Resource_Service through the transport wrapper. Build Request_Context only at the outer HTTP bridge. Put persistence/external side effects in Resource_Transaction, and preserve rollback behavior when runtime commit or external commit fails.
Work on the React Gallery
- Read
/descriptor,/view,/data,/amis, and Composition Manifest contracts from the backend. - Resolve frontend slots from the manifest/renderer registry; never hard-code business slot names or C++ field names into a parallel schema.
- When TypeScript receives
unknown, narrow it before rendering. Do not silence protocol problems withas any. - Keep
index.htmlnon-cacheable and content-hashed/versioned static resources immutable.
Invariants that must not regress
- Descriptors validate legal, unique field names.
- Readonly fields can be displayed but are not included in create/edit submit payloads unless the active View permits writing.
- Sensitive fields do not appear in frontend data or default-bearing descriptor output.
- Collection query fields and sort direction are rejected when the View does not authorize them.
- Httplib and Drogon expose the same Collection query contract even though their execution models differ.
frontendcomposition delegates layout;vertical/horizontal/flow/grid/list/group/card/tabsretain backend semantic composition.- Slot names in a Manifest have exactly one contract.
- AMIS generation translates semantic View/Composition data; it does not invent business layout or permissions.
- Managed synchronization and persistence transaction remain separate mechanisms.
Testing workflow
Use the smallest relevant tests first:
- Core descriptor/JSON/collection behavior:
Adminive_Core_Adapter_Testor focused library tests. - View/Composition/Manifest behavior:
Adminive_View_Schema_Test. - Managed behavior:
Adminive_Managed_Test. - Value/Object/Reflection/Polymorphic adapters:
Adminive_Advanced_Adapter_Test. - Httplib routes:
Adminive_Httplib_Adapter_Testwith a real localhost server/client. - Drogon routes:
Adminive_Drogon_Adapter_Test. - Gallery contract:
Adminive_Gallery_Test. - Install/export:
Adminive_Install_Consumer_Test. - Source archive:
Adminive_Package_Zip_Test.
After focused checks, run the repository gate appropriate to the change. For normal C++ changes:
cmake -S . -B verification/debug -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON
cmake --build verification/debug
ctest --test-dir verification/debug --output-on-failure
For release readiness, use python scripts/verify.py. If frontend code changed, run from frontend/:
npm run test:unit
npm run build
Run Playwright when the change affects browser behavior and dependencies are available.
Adding a public API
Before adding a public API:
- Confirm an existing semantic layer cannot express the requirement.
- Prefer additive APIs over changing old signature meaning.
- Do not create a compatibility implementation for a replaced design unless explicitly required.
- Add focused tests that prove the old semantics still hold.
- Add/update independent public-header compile coverage if a public header changes.
- Update
backend/library/DESIGN.mdandREADME.mdwhen the contract changes. - Update the Gallery Capability Case when the feature is user-visible and should be discoverable.
Review checklist
Before handoff, verify:
- The change is in the correct layer.
- No frontend business schema was duplicated.
- No sensitive/write/query boundary became weaker.
- Httplib/Drogon behavior remains contract-equivalent where they share
Collection_Service/Resource_Service. - Old implementations were removed rather than wrapped when the design was replaced.
- Tests use
ADMINIVE_CHECK, notassert(). - CMake paths are local to the owning CMake file.
- Install/export/package contents still match public headers and repo-local Codex guidance.
- Only verification steps actually executed are reported as passing.
Dependency and release workflow
Repository builds use pinned bundled nlohmann/json, magic_enum, and cpp-httplib headers, but installed adapter components use external CMake package targets. Never restore installation of bundled dependency headers under ${CMAKE_INSTALL_INCLUDEDIR}. When changing a dependency version, update the bundled source, AdminiveConfig.cmake.in, THIRD_PARTY_NOTICES.md, the matching license text, install consumer, and package test together.
The fast Drogon test uses a fake transport contract. Before release on a machine with real Drogon installed, run python scripts/verify.py --real-drogon; it must compile the real adapter and an installed-package consumer. Do not report that gate as passed when it was skipped.
Adminive/Structive project-owned code has no outbound license declared in this tree. Do not generate a project license unless the owner explicitly chooses one.