diff --git a/.circleci/config.yml b/.circleci/config.yml index 8828026..32df77b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,9 +1,14 @@ version: 2.1 - +setup: true orbs: - qqq-orb: kingsrook/qqq-orb@0.5.0 - + qqq-orb: kingsrook/qqq-orb@0.8 workflows: - build: - jobs: - - qqq-orb/mvn_test + setup: + jobs: + - qqq-orb/generate_pipeline: + orb_version: '0.8' + filters: + branches: + ignore: automation/qbit-rc-pending + tags: + ignore: /.*/ diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..e7d84f9 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @KofTwentyTwo diff --git a/.qqq-ci.yml b/.qqq-ci.yml new file mode 100644 index 0000000..d65dd23 --- /dev/null +++ b/.qqq-ci.yml @@ -0,0 +1,16 @@ +profile: qbit +orb_version: '0.8' +default_branch: main +java_version: '21' +browsers: true +api_checks: false +docs_only: false +release_on_main: false +release_tag_policy: none +test_branch_policy: all +publish: + snapshot: false + release_candidate: false + release: false + asciidoc: false +release_completion: false diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..e9917d3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,17 @@ +# qbit-template-extension + +GitHub template repository for scaffolding QQQ "Extension QBits" (infrastructure-level plugins: table customizers, auth, audit, action wrappers). Not a shipping library — consumers click "Use this template" and rename the `com.kingsrook.qbits.example` package. + +## QQQ 4.0 baseline — 2026-09-24 + +The historical review below predates the 4.0 migration. This template targets Java 21 and the public QQQ 4.0.0 release from Maven Central. The corrected APIs, license references and actual template commands are in README.md and docs/00-getting-started.md. Preserve the documented multi-instance and scaffold limitations. + +## Knowledge base + +Reviewed dossiers for this repo and the wider QQQ platform live in the second-brain vault: + +- Hub / entry point: `R:/Git.Local/KofTwentyTwo/second-brain/knowledge/qqq/qqq-hub.md` +- This repo's dossier: `R:/Git.Local/KofTwentyTwo/second-brain/knowledge/qqq/repos/qbit-template-extension.md` +- QBit mechanics refresher: `R:/Git.Local/KofTwentyTwo/second-brain/knowledge/qqq/architecture/metadata-model.md` + +Reviewed at commit `e7d4b4d672cc` (branch `main`, 2026-05-21). Known drift as of that review: no `qbit-build-parent` parent pom (org convention), qqq pinned at 0.35.0 on main (0.40.0-SNAPSHOT on develop), README still claims AGPL-3.0 while LICENSE/NOTICE are Apache-2.0, and README references `scripts/customize_template.py` / `actions/ExampleActionCustomizer.java` which do not exist. See the dossier's "Maturity & risks" and "v4.0 impact" sections before modifying the scaffold. diff --git a/README.md b/README.md index 15ea3b1..4b03f15 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,7 @@ Extension QBits extend or enhance how QQQ operates at the infrastructure/framewo ## Quick Start -1. Click "Use this template" to create your QBit -2. Run `scripts/customize_template.py` to rename the example -3. Implement your extension logic -4. Add tests -5. Publish to Maven repository +Requires **Java 21**, **Maven 3.8+**, and QQQ **4.0.0**. Create your repository, customize its Maven coordinates and Java package/classes, implement the table customizer, then run `mvn clean verify`. See [Getting Started](docs/00-getting-started.md). ## Structure @@ -25,10 +21,8 @@ Extension QBits extend or enhance how QQQ operates at the infrastructure/framewo src/main/java/com/kingsrook/qbits/example/ ├── ExampleExtensionQBitConfig.java # Configuration ├── ExampleExtensionQBitProducer.java # Entry point -├── customizers/ -│ └── ExampleTableCustomizer.java # Table customization -└── actions/ - └── ExampleActionCustomizer.java # Action handling +└── customizers/ + └── ExampleTableCustomizer.java # Table customization ``` ## Key Characteristics @@ -45,4 +39,4 @@ src/main/java/com/kingsrook/qbits/example/ ## License -AGPL-3.0 - See [LICENSE](LICENSE) +See [LICENSE](LICENSE) and [NOTICE](NOTICE). diff --git a/docs/00-getting-started.md b/docs/00-getting-started.md index f019f1e..fe1538c 100644 --- a/docs/00-getting-started.md +++ b/docs/00-getting-started.md @@ -1,42 +1,28 @@ # Getting Started -## Prerequisites +Targets Java 21, Maven 3.8 or later, and QQQ 4.0.0. Maven resolves the framework dependencies from Maven Central. -- Java 17+ -- Maven 3.8+ -- QQQ 0.23.0+ +1. Choose **Use this template** on GitHub, then clone the repository you created. +2. In `pom.xml`, set your own `groupId`, `artifactId`, name, description, and version. +3. Use your IDE's package refactoring to rename `com.kingsrook.qbits.example` throughout `src/`. Rename the `Example*` classes and update their imports and references with the IDE's rename refactoring. +4. Update the QBit producer's `GROUP_ID`, `ARTIFACT_ID`, and `VERSION` constants to match your project. Give the metadata names their own stable names before combining the QBit with other examples. +5. Build the generated project: -## Creating Your Extension QBit - -1. Click "Use this template" on GitHub -2. Clone your new repository -3. Run the customization script: - ```bash - python scripts/customize_template.py - ``` -4. Enter your QBit name when prompted - -## Project Structure - -``` -src/main/java/com/kingsrook/qbits/yourextension/ -├── YourExtensionQBitConfig.java -├── YourExtensionQBitProducer.java -├── customizers/ -└── actions/ +```bash +mvn clean verify ``` -## Using Your QBit +The repository provides example Java sources; customization uses normal package/class refactoring. Keep example coordinates unpublished. After customizing, add tests for your QBit's behavior before setting up its publishing workflow. + +## Register with a host application + +The following uses the original example names; substitute the names chosen above: ```java -new YourExtensionQBitProducer() - .withConfig(new YourExtensionQBitConfig() +new ExampleExtensionQBitProducer() + .withConfig(new ExampleExtensionQBitConfig() .withTargetTableName("order")) - .produce(qInstance, "myExtension"); + .produce(qInstance, "my-extension"); ``` -## Next Steps - -- Read [Extension Patterns](01-extension-patterns.md) -- Implement your customization logic -- Add tests +Register the target table before producing the extension, then implement its customizer. See [Extension Patterns](01-extension-patterns.md). diff --git a/docs/01-extension-patterns.md b/docs/01-extension-patterns.md index 5c90fdc..55ccff7 100644 --- a/docs/01-extension-patterns.md +++ b/docs/01-extension-patterns.md @@ -1,58 +1,16 @@ # Extension Patterns -## Table Customizers - -Add behavior to existing tables: +[ExampleExtensionQBitProducer](../src/main/java/com/kingsrook/qbits/example/ExampleExtensionQBitProducer.java) registers the QBit identity and calls `applyTableCustomizations` for the configured target. That method is the extension point: look up the table, validate that it exists, and call your customized [ExampleTableCustomizer](../src/main/java/com/kingsrook/qbits/example/customizers/ExampleTableCustomizer.java). ```java -public class AuditTableCustomizer +QTableMetaData table = qInstance.getTable(tableName); +if(table == null) { - public void customize(QTableMetaData table) - { - table.withField(new QFieldMetaData("createdAt", QFieldType.DATE_TIME)); - table.withField(new QFieldMetaData("modifiedAt", QFieldType.DATE_TIME)); - - table.withCustomizer( - TableCustomizers.PRE_INSERT_RECORD, - new QCodeReference(AuditPreInsert.class)); - } + throw new QException("Target table not found: " + tableName); } +new ExampleTableCustomizer().customize(table); ``` -## Action Customizers +When implementing this method, add `throws QException` to its declaration. Run the config's `validate(QInstance, List)` before registering metadata, and report validation errors rather than silently ignoring a missing target. The uncustomized template contains placeholders for this behavior. -Wrap actions with additional behavior: - -```java -public class LoggingActionWrapper implements PreInsertRecordInterface -{ - @Override - public void preInsertRecord(InsertInput input, QRecord record) throws QException - { - LOG.info("Inserting record", logPair("table", input.getTableName())); - } -} -``` - -## Config Validation - -Validate that required components exist: - -```java -@Override -public void validate(QInstance qInstance, List errors) -{ - if(qInstance.getTable(targetTableName) == null) - { - errors.add("Target table required: " + targetTableName); - } -} -``` - -## When to Use Extension QBits - -- Adding audit logging to tables -- Implementing authentication/authorization -- Adding encryption to fields -- Custom validation rules -- Performance monitoring +For record hooks, use QQQ's existing table customizer interfaces or `AbstractPreInsertCustomizer`. Its `apply(List)` method returns the records for the next stage; register the customizer through the table's `TableCustomizers.PRE_INSERT_RECORD` role. Check the actual QQQ interface before adding another hook. Add tests proving that the intended table changes and invalid configurations are handled. diff --git a/pom.xml b/pom.xml index 8a76bd5..56a062c 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ 21 21 UTF-8 - 0.40.0-SNAPSHOT + 4.0.0 @@ -36,7 +36,7 @@ org.assertj assertj-core - 3.24.2 + 3.27.7 test