create-qs 0.0.0 → 0.8.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +140 -2
  2. package/index.js +1884 -0
  3. package/package.json +31 -5
  4. package/template/default/.quicksilver/.gitattributes +4 -0
  5. package/template/default/.quicksilver/manual/en-US/00-setup.md +199 -0
  6. package/template/default/.quicksilver/manual/zh-CN/00-setup.md +199 -0
  7. package/template/default/.quicksilver/manual/zh-TW/00-setup.md +199 -0
  8. package/template/default/AGENTS.md +333 -0
  9. package/template/default/README.md +5 -0
  10. package/template/default/_gitignore +70 -0
  11. package/template/default/build.gradle.kts +5 -0
  12. package/template/default/eslint.config.js +137 -0
  13. package/template/default/gradle/repo.settings.gradle.kts +90 -0
  14. package/template/default/gradle/wrapper/gradle-wrapper.jar +0 -0
  15. package/template/default/gradle/wrapper/gradle-wrapper.properties +7 -0
  16. package/template/default/gradle.properties +15 -0
  17. package/template/default/gradlew +248 -0
  18. package/template/default/gradlew.bat +93 -0
  19. package/template/default/modules/{{MODULE_DIRECTORY}}/api/build.gradle.kts +8 -0
  20. package/template/default/modules/{{MODULE_DIRECTORY}}/api/data/demo/README.md +11 -0
  21. package/template/default/modules/{{MODULE_DIRECTORY}}/api/data/init/rows/menus.jsons +1 -0
  22. package/template/default/modules/{{MODULE_DIRECTORY}}/api/data/init/rows/misc.jsons +15 -0
  23. package/template/default/modules/{{MODULE_DIRECTORY}}/api/data/upgrade/draft.jsons +1 -0
  24. package/template/default/modules/{{MODULE_DIRECTORY}}/api/src/main/kotlin/{{API_PACKAGE}}/AutoConfiguration.kt +25 -0
  25. package/template/default/modules/{{MODULE_DIRECTORY}}/api/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +1 -0
  26. package/template/default/modules/{{MODULE_DIRECTORY}}/api/src/test/kotlin/{{API_PACKAGE}}/SmokeTests.kt +61 -0
  27. package/template/default/modules/{{MODULE_DIRECTORY}}/api/src/test/kotlin/{{API_PACKAGE}}/TestConfiguration.kt +6 -0
  28. package/template/default/modules/{{MODULE_DIRECTORY}}/module.yaml +8 -0
  29. package/template/default/modules/{{MODULE_DIRECTORY}}/web/package.json +25 -0
  30. package/template/default/modules/{{MODULE_DIRECTORY}}/web/src/module.ts +16 -0
  31. package/template/default/modules/{{MODULE_DIRECTORY}}/web/src/vite-env.d.ts +10 -0
  32. package/template/default/modules/{{MODULE_DIRECTORY}}/web/tsconfig.app.json +7 -0
  33. package/template/default/modules/{{MODULE_DIRECTORY}}/web/tsconfig.json +7 -0
  34. package/template/default/modules/{{MODULE_DIRECTORY}}/web/tsconfig.node.json +7 -0
  35. package/template/default/modules/{{MODULE_DIRECTORY}}/web/vite.config.ts +11 -0
  36. package/template/default/package.json +76 -0
  37. package/template/default/pnpm-workspace.yaml +40 -0
  38. package/template/default/publishing.yaml +52 -0
  39. package/template/default/quicksilver.yaml +13 -0
  40. package/template/default/run/api/build.gradle.kts +8 -0
  41. package/template/default/run/api/config/README.md +76 -0
  42. package/template/default/run/api/config/application-dev.yaml +45 -0
  43. package/template/default/run/api/config/application-h2.yaml +22 -0
  44. package/template/default/run/api/config/application-mariadb.yaml +22 -0
  45. package/template/default/run/api/config/application-mssql.yaml +22 -0
  46. package/template/default/run/api/config/application-oracle.yaml +22 -0
  47. package/template/default/run/api/config/application-postgresql.yaml +22 -0
  48. package/template/default/run/api/config/application-test.yaml +28 -0
  49. package/template/default/run/api/config/application.yaml +84 -0
  50. package/template/default/run/api/config/logback-test.xml +141 -0
  51. package/template/default/run/api/config/logback.xml +142 -0
  52. package/template/default/run/web/index.html +14 -0
  53. package/template/default/run/web/index.ts +6 -0
  54. package/template/default/run/web/package.json +18 -0
  55. package/template/default/run/web/static/config.js +15 -0
  56. package/template/default/run/web/tsconfig.app.json +4 -0
  57. package/template/default/run/web/tsconfig.json +7 -0
  58. package/template/default/run/web/tsconfig.node.json +4 -0
  59. package/template/default/run/web/vite.config.ts +21 -0
  60. package/template/default/settings.gradle.kts +19 -0
@@ -0,0 +1,61 @@
1
+ package {{API_PACKAGE}}
2
+
3
+ import com.qsrun.quicksilver.core.application.data.Databases
4
+ import com.qsrun.quicksilver.core.application.data.UnitInfoRepo
5
+ import com.qsrun.quicksilver.core.data.constant.DataSourceCodes
6
+ import com.qsrun.quicksilver.core.test.base.QsBaseTests
7
+ import org.junit.jupiter.api.Assertions.assertTrue
8
+ import org.junit.jupiter.api.Test
9
+ import org.springframework.beans.factory.annotation.Autowired
10
+
11
+ /**
12
+ * Environment smoke test: the Spring context starts, and provisioning has actually loaded the metadata.
13
+ *
14
+ * It also covers loading the data files into their tables, so units need no tests of their own for that. The
15
+ * test context runs every init data file on startup. When any command fails, the context cannot start, and this
16
+ * class fails together with every other test.
17
+ *
18
+ * It also guards `run/api/config/logback-test.xml`. Without a single `@Test` in the test tree, Spring never
19
+ * starts, and a broken logging configuration (for example one that references a converter Spring Boot has
20
+ * removed) goes unnoticed. Such an error makes **every** test throw `DynamicClassLoadingException` from
21
+ * `LogbackLoggingSystem` while the context initializes, with a message unrelated to the code under test, which
22
+ * is hard to trace back.
23
+ *
24
+ * The assertion uses plain JDBC instead of `DatabaseInspectors` on purpose. It depends only on the `Databases`
25
+ * of core, and does not rely on lib-database being on the test classpath of downstream projects.
26
+ */
27
+ class SmokeTests: QsBaseTests() {
28
+ @Autowired
29
+ private lateinit var unitInfoRepo: UnitInfoRepo
30
+
31
+ @Test
32
+ fun `spring context starts and metadata is provisioned`() {
33
+ val unitCount = Databases.getConnection(DataSourceCodes.METADATA).use { cn ->
34
+ cn.createStatement().use { st ->
35
+ st.executeQuery("select count(*) from ac_unit").use { rs ->
36
+ assertTrue(rs.next(), "select count(*) from ac_unit returned no row")
37
+ rs.getInt(1)
38
+ }
39
+ }
40
+ }
41
+ assertTrue(unitCount > 0, "ac_unit is empty: provisioning did not run")
42
+ }
43
+
44
+ /**
45
+ * Every unit, platform units included, passes the metadata self-check.
46
+ *
47
+ * When the self-check finds a problem on startup, it only logs an error and the service starts as usual. This
48
+ * test turns that into a test failure. A unit created with `$add: 'ac.unit'` that fails the self-check already
49
+ * stops provisioning, so what this test adds is catching a unit broken afterwards by other writes, for example
50
+ * data files that rewrite `ac_unit_field` directly. The self-check covers the metadata only (table name,
51
+ * fields, ID fields, the semantic columns of tree units), and does not compare it with the physical table.
52
+ */
53
+ @Test
54
+ fun `every unit passes the metadata self-check`() {
55
+ val problems = unitInfoRepo.all().flatMap { unit ->
56
+ unit.diagnostics.map { " [${it.kind}] ${unit.code}: ${it.message}" }
57
+ }
58
+ assertTrue(problems.isEmpty(),
59
+ "Unit metadata diagnostics found ${problems.size} problem(s):\n" + problems.joinToString("\n"))
60
+ }
61
+ }
@@ -0,0 +1,6 @@
1
+ package {{API_PACKAGE}}
2
+
3
+ import org.springframework.boot.SpringBootConfiguration
4
+
5
+ @SpringBootConfiguration
6
+ class TestConfiguration
@@ -0,0 +1,8 @@
1
+ id: {{MODULE_ID}}
2
+ code: {{MODULE_CODE}}
3
+ namespaces: ['{{MODULE_NAMESPACE}}']
4
+ description: Description of module {{MODULE_CODE}}
5
+ dependencies:
6
+ - {{PLATFORM_MODULE_DEPENDENCIES}}
7
+ web:
8
+ package-name: '{{WEB_PACKAGE_NAME}}'
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "{{WEB_PACKAGE_NAME}}",
3
+ "private": false,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "exports": {
7
+ "./module": "./src/module.ts"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc -b && vite build",
11
+ "clean": "shx rm -rf dist",
12
+ "lint": "eslint .",
13
+ "lint:fix": "eslint . --fix"
14
+ },
15
+ "dependencies": {
16
+ "@qs-charts/adapter-preact": "catalog:client",
17
+ "@qs-charts/core": "catalog:client",
18
+ "@qs-elements/web": "catalog:client",
19
+ "@qs-elements/web-preact": "catalog:client",
20
+ {{PLATFORM_WEB_DEPENDENCIES}}
21
+ },
22
+ "devDependencies": {
23
+ "@qs-platform/preset-vite-web": "catalog:quicksilver"
24
+ }
25
+ }
@@ -0,0 +1,16 @@
1
+ import { Module } from '@qs-platform/web-module-core';
2
+
3
+ const pages = {};
4
+
5
+ const plugins = {};
6
+
7
+ const components = {};
8
+
9
+ export const module: Module = {
10
+ pages,
11
+ plugins,
12
+ components,
13
+ styles: [],
14
+ icons: [],
15
+ routes: {},
16
+ };
@@ -0,0 +1,10 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ import { QeIntrinsicElements } from '@qs-elements/web-preact';
4
+ import { QChartsIntrinsicElements } from '@qs-charts/adapter-preact';
5
+
6
+ declare module 'preact' {
7
+ namespace JSX {
8
+ interface IntrinsicElements extends QeIntrinsicElements, QChartsIntrinsicElements {}
9
+ }
10
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "@qs-platform/preset-vite-web/tsconfig.quicksilver.json",
3
+ "compilerOptions": {
4
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo"
5
+ },
6
+ "include": ["src"]
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ]
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "@qs-platform/preset-vite-web/tsconfig.node.json",
3
+ "compilerOptions": {
4
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo"
5
+ },
6
+ "include": ["vite.config.ts"]
7
+ }
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from 'vite';
2
+ import { quicksilverBuildPlugins } from '@qs-platform/preset-vite-web';
3
+
4
+ export default defineConfig({
5
+ plugins: [...quicksilverBuildPlugins()],
6
+ resolve: {
7
+ alias: [
8
+ { find: /^~(.*)$/, replacement: '$1' },
9
+ ],
10
+ },
11
+ });
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "{{PROJECT_CODE}}",
3
+ "private": true,
4
+ "version": "0.0.1",
5
+ "type": "module",
6
+ "engines": {
7
+ "node": ">=22.13.0",
8
+ "pnpm": ">=11"
9
+ },
10
+ "scripts": {
11
+ "// --- start dev servers -------------------------------------------": "",
12
+ "dev": "quicksilver dev",
13
+ "dev:h2": "PORT=6210 API_PORT=6211 SPRING_PROFILES_ACTIVE=dev,h2 quicksilver dev",
14
+ "dev:postgresql": "PORT=6220 API_PORT=6221 SPRING_PROFILES_ACTIVE=dev,postgresql quicksilver dev",
15
+ "dev:mariadb": "PORT=6230 API_PORT=6231 SPRING_PROFILES_ACTIVE=dev,mariadb quicksilver dev",
16
+ "dev:mssql": "PORT=6240 API_PORT=6241 SPRING_PROFILES_ACTIVE=dev,mssql quicksilver dev",
17
+ "dev:oracle": "PORT=6250 API_PORT=6251 SPRING_PROFILES_ACTIVE=dev,oracle quicksilver dev",
18
+ "dev:debug": "quicksilver dev --debug",
19
+ "dev:api": "quicksilver gradle :run:bootRun",
20
+ "dev:web": "pnpm -C run/web dev",
21
+ "// --- build subprojects -------------------------------------------": "",
22
+ "build": "pnpm build:api && pnpm build:web",
23
+ "build:api": "quicksilver gradle build",
24
+ "build:web": "pnpm -r --fail-if-no-match --filter './modules/*/web' build",
25
+ "build:release": "pnpm build:web",
26
+ "// --- utils -------------------------------------------------------": "",
27
+ "i18n:extract": "quicksilver i18n extract",
28
+ "sources": "quicksilver sources",
29
+ "// --- lint --------------------------------------------------------": "",
30
+ "lint": "eslint .",
31
+ "lint:fix": "eslint . --fix",
32
+ "// --- test --------------------------------------------------------": "",
33
+ "test:api": "quicksilver gradle test",
34
+ "test:install:e2e": "quicksilver test run self-install-e2e",
35
+ "test:install-upgrade:e2e": "quicksilver test run self-install-upgrade-e2e",
36
+ "test:install:keepalive": "quicksilver test run self-install-keepalive",
37
+ "test:verify:dev": "quicksilver test verify --dev",
38
+ "test:list": "quicksilver test list",
39
+ "// --- packaging (output to build/release) -------------------------": "",
40
+ "package:full": "quicksilver gradle :package-current",
41
+ "package:full:exploded": "quicksilver gradle :package-current-exploded",
42
+ "package:full:all": "quicksilver gradle :package-all",
43
+ "package:full:darwin-x64": "quicksilver gradle :package-darwin-x64",
44
+ "package:full:darwin-arm64": "quicksilver gradle :package-darwin-arm64",
45
+ "package:full:linux-x64": "quicksilver gradle :package-linux-x64",
46
+ "package:full:linux-arm64": "quicksilver gradle :package-linux-arm64",
47
+ "package:full:windows-x64": "quicksilver gradle :package-windows-x64",
48
+ "package:full:windows-arm64": "quicksilver gradle :package-windows-arm64",
49
+ "package:module": "quicksilver gradle :package-module",
50
+ "package:module:exploded": "quicksilver gradle :package-module-exploded",
51
+ "// --- release (build is automatically included) -------------------": "",
52
+ "release": "qs release --target=internal",
53
+ "// --- clean -------------------------------------------------------": "",
54
+ "clean:all": "pnpm clean:api && pnpm -r run clean && pnpm clean:root",
55
+ "clean:api": "quicksilver gradle clean",
56
+ "clean:root": "shx rm -rf build/release build/test",
57
+ "clean:web": "pnpm -r --filter './modules/*/web' --filter './run/web' run clean",
58
+ "// --- lifecycle hooks (run automatically on install) --------------": "",
59
+ "postinstall": "quicksilver docs && playwright install chromium"
60
+ },
61
+ "devDependencies": {
62
+ "@qs-platform/cli": "catalog:quicksilver",
63
+ "@eslint/js": "^10.0.1",
64
+ "@playwright/test": "^1.62.1",
65
+ "@stylistic/eslint-plugin": "^5.10.0",
66
+ "@types/node": "catalog:tooling",
67
+ "@typescript-eslint/eslint-plugin": "^8.69.0",
68
+ "@typescript-eslint/parser": "^8.69.0",
69
+ "eslint": "^10.9.1",
70
+ "globals": "^17.11.0",
71
+ "sass": "catalog:tooling",
72
+ "shx": "catalog:tooling",
73
+ "typescript": "catalog:tooling",
74
+ "vite": "catalog:tooling"
75
+ }
76
+ }
@@ -0,0 +1,40 @@
1
+ # Quicksilver's own packages are not on the public registry. Point the @qs-platform, @qs-elements
2
+ # and @qs-charts scopes at your Nexus in ~/.npmrc, once per machine. To pin them to this project
3
+ # instead, add a `registries` section here. Either way, see .quicksilver/manual/en-US/00-setup.md.
4
+ packages:
5
+ - modules/{{MODULE_DIRECTORY}}/web
6
+ - run/web
7
+
8
+ allowBuilds:
9
+ '@parcel/watcher': true
10
+ esbuild: true
11
+
12
+ engineStrict: true
13
+
14
+ # The scripts in package.json use POSIX sh syntax (single-quoted arguments, `VAR=value command`).
15
+ # On Windows, pnpm runs scripts with cmd.exe by default, which supports neither. The shell emulator
16
+ # runs them the same way on every platform.
17
+ shellEmulator: true
18
+
19
+ minimumReleaseAgeExclude:
20
+ - '@qs-elements/*'
21
+ - '@qs-charts/*'
22
+ - '@qs-platform/*'
23
+
24
+ catalogs:
25
+ client:
26
+ "@qs-charts/adapter-preact": "0.2.11"
27
+ "@qs-charts/core": "0.2.11"
28
+ "@qs-elements/web": "1.0.158"
29
+ "@qs-elements/web-preact": "1.0.158"
30
+ quicksilver:
31
+ "@qs-platform/cli": "0.8.23"
32
+ "@qs-platform/preset-vite-web": "0.8.23"
33
+ "@qs-platform/web-module-core": "0.8.23"
34
+ "@qs-platform/web-module-org": "0.8.23"
35
+ tooling:
36
+ "@types/node": "^26.4.0"
37
+ "sass": "^1.103.1"
38
+ "shx": "^0.4.0"
39
+ "typescript": "^6.0.3"
40
+ "vite": "^7.3.6"
@@ -0,0 +1,52 @@
1
+ # Publishing targets: where artifacts go, and which packages get published.
2
+ #
3
+ # Read by `pnpm qs release --target=<name>`, which covers both halves — Maven artifacts and npm
4
+ # packages — and drives Gradle with the arguments it needs. **Do not run `./gradlew publish`
5
+ # directly**: the Maven URL and credentials prefix are resolved from this file and passed in by
6
+ # `pnpm qs release`. Use `pnpm qs release --only=maven` when you want the Maven half alone.
7
+ #
8
+ # The lookup starts at the **project root** (the directory holding pnpm-workspace.yaml) and walks
9
+ # up, stopping at the .git directory — or at the project root itself before the project is a git
10
+ # repository. The Gradle side uses the same rule; both must find the same file.
11
+ #
12
+ # At every level, local/publishing.yaml is checked first. local/ is not under version control, so a
13
+ # copy of this file placed there is a machine-local override: copy it as-is and edit the URLs, the
14
+ # `packages` paths stay valid (their base is still the parent of local/). When that copy is in
15
+ # effect, both the release summary and the Gradle log name the file being used.
16
+ #
17
+ # Credentials do NOT go here. Put the npm token in ~/.npmrc as `//<host>/:_authToken=<token>`,
18
+ # and the Maven account in ~/.gradle/gradle.properties as
19
+ # `<maven-credentials-prefix>.user` / `.password`.
20
+ #
21
+ # An empty URL means the target is not configured yet: publishing fails with an error rather
22
+ # than falling back to a default registry.
23
+ #
24
+ # Maven artifacts never carry a draft with changes (data/upgrade/draft.jsons): the release refuses
25
+ # them on every target. Run `pnpm qs data freeze` on the main branch and commit before releasing.
26
+ #
27
+ # Paths under `packages` are relative to this file — or, for the local/ copy, to the parent of
28
+ # local/ — and may contain globs.
29
+
30
+ default-target: internal
31
+
32
+ targets:
33
+ internal:
34
+ label: Internal repository
35
+ # Fill both in before the first release. Add more targets (staging, public, per-customer)
36
+ # by copying this block — the names are yours, the CLI does not know any of them.
37
+ npm-registry:
38
+ # Publishing Maven artifacts additionally requires enabling it in build.gradle.kts:
39
+ # quicksilverRoot { publishing { enabled = true } }
40
+ # Until then, leave this blank and pnpm release publishes npm packages only.
41
+ maven-url:
42
+ # quicksilver.repo is the default login for pulling the platform (quicksilver.repo.user /
43
+ # .password), so one account covers both. When gradle.properties names another prefix in
44
+ # quicksilver.repo.credentials, or publishing needs a different account, change this to match.
45
+ maven-credentials-prefix: quicksilver.repo
46
+ # Publishing straight from a dirty working tree is fine for an internal repository.
47
+ # Drop this line on a target that ships releases.
48
+ git-checks: false
49
+ allow-prerelease: true
50
+
51
+ packages:
52
+ - modules/*/web
@@ -0,0 +1,13 @@
1
+ display:
2
+ title: {{PROJECT_CODE}}
3
+ description: Description for your product here
4
+
5
+ names:
6
+ kotlin-package: {{API_PACKAGE}}
7
+ maven-group: {{API_PACKAGE}}
8
+ maven-prefix: {{PROJECT_CODE}}
9
+
10
+ packaging:
11
+ archive-name: {{PROJECT_CODE}}
12
+ fixed-modules: [{{PLATFORM_MODULE_CODES_QUOTED}}, '{{MODULE_CODE}}']
13
+ visible-modules:
@@ -0,0 +1,8 @@
1
+ plugins {
2
+ id("com.qsrun.quicksilver.gradle.run")
3
+ }
4
+
5
+ dependencies {
6
+ implementation(project(":modules:{{MODULE_DIRECTORY}}"))
7
+ // implementation("com.qsrun:quicksilver-module-sample")
8
+ }
@@ -0,0 +1,76 @@
1
+ # `run/api/config`
2
+
3
+ Configuration for the API server in development. Everything here is read by Spring Boot at
4
+ startup; nothing in this directory ships to your users.
5
+
6
+ ## Files
7
+
8
+ | File | What it is |
9
+ |---|---|
10
+ | `application.yaml` | Base configuration: ports, CORS, cache, upload, Atomikos. **Declares no datasources** — those live in the profile files below |
11
+ | `application-dev.yaml` | The `dev` profile, active by default. Datasources for local development, plus `auto-init` (with `draft-sync` on) and `fail-on-unregistered-data-source` |
12
+ | `application-<dialect>.yaml` | One overlay per database dialect (`h2`, `postgresql`, `mariadb`, `mssql`, `oracle`). Each carries its own datasources, log directory and Atomikos log directory, so several can run side by side |
13
+ | `application-test.yaml` | Used by `modules/*/api` tests. In-memory H2, wiped on every run |
14
+ | `logback.xml` / `logback-test.xml` | Logging |
15
+
16
+ ## Choosing a database
17
+
18
+ `pnpm dev` runs on a file-based H2 database with no setup. To use another dialect, run its script
19
+ — `pnpm dev:postgresql`, `pnpm dev:mariadb`, and so on — which sets
20
+ `SPRING_PROFILES_ACTIVE=dev,<dialect>` and its own ports.
21
+
22
+ The H2 profiles ship with working credentials (`sa` / `sa`) — H2 creates the database on first
23
+ connect, so there is nothing to change. In every other dialect file the user and `PASSWORD` are
24
+ placeholders you must replace.
25
+
26
+ **Do not drop the `dev,` prefix.** Without it `application-dev.yaml` is not loaded, and since
27
+ `application.yaml` declares no datasources, startup fails with `Missing required datasource code`.
28
+ That is deliberate: a missing datasource list must fail loudly rather than fall back to some
29
+ default database.
30
+
31
+ Create the databases before use — the server-based dialects only. Each of those files names its
32
+ database after this project — a project called `power-crm` gets `power_crm_dev` — so several
33
+ Quicksilver products can share one database server without colliding. Two files sit outside that
34
+ rule: Oracle, whose "database" is a PDB with a name fixed by the container image (`FREEPDB1`), and
35
+ the H2 profiles, whose databases are plain files under this project's own `local/data/h2/`
36
+ (`database1` for `dev`, `database2` for `dev:h2`) and so have nothing to collide with. The
37
+ datasource list is replaced as a whole, so when you change one entry, keep the other one listed
38
+ as well.
39
+
40
+ ## H2 URLs
41
+
42
+ The two H2 parameters below are not optional. Both failures are quiet and show up far from the
43
+ configuration, so keep them when you edit an H2 URL:
44
+
45
+ - File database — `DB_CLOSE_ON_EXIT=FALSE`. Without it H2 registers a JVM shutdown hook that races
46
+ Spring's own. On Ctrl+C H2 often closes the database first, and Atomikos' XA recovery scan then
47
+ hits "Database is already closed" and prints a screenful of stack traces.
48
+ - In-memory database — `DB_CLOSE_DELAY=-1`. The connection pool's `minSize` is 0, so when the last
49
+ idle connection is reclaimed H2 destroys the whole in-memory database with it, and the next
50
+ connection hands you an empty one.
51
+
52
+ ## MySQL
53
+
54
+ MySQL works, but **you have to supply the driver**: Connector/J is GPLv2, so it is not bundled.
55
+ Add `runtimeOnly("com.mysql:mysql-connector-j")` to `run/api/build.gradle.kts`, then add a
56
+ `application-mysql.yaml` overlay and a `dev:mysql` script of your own, modelled on the other
57
+ dialects. Every other dialect listed above ships with its driver.
58
+
59
+ ## The dev database
60
+
61
+ The `dev` profile turns on `draft-sync` and turns off `drop-first`. Every start runs the upgrade
62
+ drafts that changed since the last start, and keeps the data already in the dev database. To
63
+ rebuild the database from init and demo data, set `drop-first: true` for one start and then set it
64
+ back. Switching `draft-sync` on or off also needs one such rebuild: the two modes record drafts
65
+ differently, and startup refuses a database built in the other mode.
66
+
67
+ ## Local edits
68
+
69
+ `application-dev.yaml` is committed, but **by convention your local edits to it are not** — a
70
+ different database host, `drop-first` turned on for a rebuild, a different
71
+ `fail-on-unregistered-data-source`. Commit it only when you are deliberately changing the team
72
+ default, and say so in the commit message.
73
+
74
+ For an override that never enters version control, point `QUICKSILVER_CONFIG_LOCATION` at a config
75
+ directory of your own: it is appended to the tail of `spring.config.location`, so it wins over
76
+ every profile file.
@@ -0,0 +1,45 @@
1
+ #
2
+ # Overlay for the `dev` profile. Activated by default via `spring.profiles.active` in
3
+ # application.yaml, and by every `pnpm dev:*` script.
4
+ #
5
+ spring:
6
+ application.name: DEV
7
+
8
+ quicksilver:
9
+ datasource:
10
+ # Keep the quotes around passwords: special characters (# : @ ...) then paste in as is.
11
+ items:
12
+ - code: metadata
13
+ url: "jdbc:h2:./local/data/h2/database1;DB_CLOSE_ON_EXIT=FALSE;DATABASE_TO_UPPER=false;MODE=MySQL"
14
+ user: sa
15
+ password: "sa"
16
+ - code: business
17
+ url: "jdbc:h2:./local/data/h2/database1;DB_CLOSE_ON_EXIT=FALSE;DATABASE_TO_UPPER=false;MODE=MySQL"
18
+ user: sa
19
+ password: "sa"
20
+ # Each ac_table row records the datasource its table lives in. When a row names a code that is
21
+ # not listed under items, true stops startup with an error and false only logs a warning. Unset,
22
+ # it is false. Keep it true in development so that a datasource removed from this file is
23
+ # noticed at the next start.
24
+ fail-on-unregistered-data-source: true
25
+ auto-init:
26
+ # Install and upgrade the modules at every start by running their data files. Takes effect
27
+ # only when quicksilver.application.mode is development. In production the installer does it.
28
+ enabled: true
29
+ # Drop the tables and views that Quicksilver manages before provisioning, so the database is
30
+ # rebuilt from init and demo data. Set drop-first: true for one start, then set it back to false.
31
+ drop-first: false
32
+ # Draft sync. Every start runs the upgrade drafts that changed since the last start. Data in
33
+ # the dev database is kept, including rows entered through the UI. Switching draft-sync on or
34
+ # off needs one rebuild with drop-first.
35
+ draft-sync: true
36
+ # Demo data: on a fresh install of a module, the .jsons files in its data/demo/ run after its
37
+ # init. A database that already exists does not pick up demo files added later, rebuild it with
38
+ # drop-first as described above.
39
+ demo-data: true
40
+ webhook:
41
+ # Webhook targets that resolve to a private or loopback address (10.0.0.0/8, 127.0.0.0/8, ...)
42
+ # are refused unless the address falls in one of these CIDR ranges. The dev profile allows
43
+ # 127.0.0.1 so that a receiver running on this machine can be tested. Link-local addresses,
44
+ # which include the cloud metadata endpoint, are always refused whatever is listed here.
45
+ restricted-exceptions: ["127.0.0.1/32"]
@@ -0,0 +1,22 @@
1
+ #
2
+ # Overlay for the `h2` profile: only the keys that differ from application-dev.yaml,
3
+ # everything else is inherited key by key. Activate with SPRING_PROFILES_ACTIVE=dev,h2
4
+ # (or run `pnpm dev:h2`).
5
+ #
6
+ logging:
7
+ file.path: local/log/application/h2
8
+
9
+ quicksilver:
10
+ datasource:
11
+ # Keep the quotes around passwords: special characters (# : @ ...) then paste in as is.
12
+ items:
13
+ - code: metadata
14
+ url: "jdbc:h2:./local/data/h2/database2;DB_CLOSE_ON_EXIT=FALSE;DATABASE_TO_UPPER=false;MODE=MySQL"
15
+ user: sa
16
+ password: "sa"
17
+ - code: business
18
+ url: "jdbc:h2:./local/data/h2/database2;DB_CLOSE_ON_EXIT=FALSE;DATABASE_TO_UPPER=false;MODE=MySQL"
19
+ user: sa
20
+ password: "sa"
21
+ atomikos:
22
+ log_base_dir: local/log/atomikos/h2
@@ -0,0 +1,22 @@
1
+ #
2
+ # Overlay for the `mariadb` profile: only the keys that differ from application-dev.yaml,
3
+ # everything else is inherited key by key. Activate with SPRING_PROFILES_ACTIVE=dev,mariadb
4
+ # (or run `pnpm dev:mariadb`).
5
+ #
6
+ logging:
7
+ file.path: local/log/application/mariadb
8
+
9
+ quicksilver:
10
+ datasource:
11
+ # Keep the quotes around passwords: special characters (# : @ ...) then paste in as is.
12
+ items:
13
+ - code: metadata
14
+ url: "jdbc:mariadb://localhost:3308/{{DB_PREFIX}}_dev?characterEncoding=utf8mb4"
15
+ user: root
16
+ password: "PASSWORD"
17
+ - code: business
18
+ url: "jdbc:mariadb://localhost:3308/{{DB_PREFIX}}_dev?characterEncoding=utf8mb4"
19
+ user: root
20
+ password: "PASSWORD"
21
+ atomikos:
22
+ log_base_dir: local/log/atomikos/mariadb
@@ -0,0 +1,22 @@
1
+ #
2
+ # Overlay for the `mssql` profile: only the keys that differ from application-dev.yaml,
3
+ # everything else is inherited key by key. Activate with SPRING_PROFILES_ACTIVE=dev,mssql
4
+ # (or run `pnpm dev:mssql`).
5
+ #
6
+ logging:
7
+ file.path: local/log/application/mssql
8
+
9
+ quicksilver:
10
+ datasource:
11
+ # Keep the quotes around passwords: special characters (# : @ ...) then paste in as is.
12
+ items:
13
+ - code: metadata
14
+ url: "jdbc:sqlserver://localhost:1433;DatabaseName={{DB_PREFIX}}_dev;trustServerCertificate=true"
15
+ user: sa
16
+ password: "PASSWORD"
17
+ - code: business
18
+ url: "jdbc:sqlserver://localhost:1433;DatabaseName={{DB_PREFIX}}_dev;trustServerCertificate=true"
19
+ user: sa
20
+ password: "PASSWORD"
21
+ atomikos:
22
+ log_base_dir: local/log/atomikos/mssql
@@ -0,0 +1,22 @@
1
+ #
2
+ # Overlay for the `oracle` profile: only the keys that differ from application-dev.yaml,
3
+ # everything else is inherited key by key. Activate with SPRING_PROFILES_ACTIVE=dev,oracle
4
+ # (or run `pnpm dev:oracle`).
5
+ #
6
+ logging:
7
+ file.path: local/log/application/oracle
8
+
9
+ quicksilver:
10
+ datasource:
11
+ # Keep the quotes around passwords: special characters (# : @ ...) then paste in as is.
12
+ items:
13
+ - code: metadata
14
+ url: "jdbc:oracle:thin:@//localhost:1521/FREEPDB1"
15
+ user: system
16
+ password: "PASSWORD"
17
+ - code: business
18
+ url: "jdbc:oracle:thin:@//localhost:1521/FREEPDB1"
19
+ user: system
20
+ password: "PASSWORD"
21
+ atomikos:
22
+ log_base_dir: local/log/atomikos/oracle
@@ -0,0 +1,22 @@
1
+ #
2
+ # Overlay for the `postgresql` profile: only the keys that differ from application-dev.yaml,
3
+ # everything else is inherited key by key. Activate with SPRING_PROFILES_ACTIVE=dev,postgresql
4
+ # (or run `pnpm dev:postgresql`).
5
+ #
6
+ logging:
7
+ file.path: local/log/application/postgresql
8
+
9
+ quicksilver:
10
+ datasource:
11
+ # Keep the quotes around passwords: special characters (# : @ ...) then paste in as is.
12
+ items:
13
+ - code: metadata
14
+ url: "jdbc:postgresql://127.0.0.1/{{DB_PREFIX}}_dev?stringtype=unspecified"
15
+ user: postgres
16
+ password: "PASSWORD"
17
+ - code: business
18
+ url: "jdbc:postgresql://127.0.0.1/{{DB_PREFIX}}_dev?stringtype=unspecified"
19
+ user: postgres
20
+ password: "PASSWORD"
21
+ atomikos:
22
+ log_base_dir: local/log/atomikos/postgresql
@@ -0,0 +1,28 @@
1
+ #
2
+ # This file is for testing of modules/xxx/api. Paths use ${quicksilver.config.dir},
3
+ # which ModulePlugin sets to the absolute path of this config directory.
4
+ #
5
+ spring.application.name: QsTest
6
+ logging.config: ${quicksilver.config.dir}/logback-test.xml
7
+ quicksilver:
8
+ # Tests run with the module's api directory as the working directory, and a missing key file is
9
+ # auto-generated outside production mode. Without this line the key would land in the module's
10
+ # own config/ (the relative path inherited from application.yaml) instead of under build/.
11
+ security.cipher.key-file: build/test/cipher.key
12
+ datasource:
13
+ # Keep the quotes around passwords: special characters (# : @ ...) then paste in as is.
14
+ items:
15
+ - code: metadata
16
+ url: "jdbc:h2:mem:metadata;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL"
17
+ user: sa
18
+ password: "sa"
19
+ - code: business
20
+ url: "jdbc:h2:mem:business;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false;MODE=MySQL"
21
+ user: sa
22
+ password: "sa"
23
+ atomikos:
24
+ log_base_dir: build/test/log/atomikos
25
+ upload.directory: build/test/upload
26
+ # Tests run under the test profile, which does not inherit auto-init from
27
+ # application-dev.yaml, so it must be declared here.
28
+ auto-init.enabled: true