create-windy 0.1.0
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.
- package/README.md +114 -0
- package/assets/LICENSE-Apache-2.0.txt +201 -0
- package/dist/cli.js +1662 -0
- package/package.json +37 -0
- package/template/.dockerignore +11 -0
- package/template/.oxfmtrc.json +9 -0
- package/template/.oxlintrc.json +119 -0
- package/template/.windy-template.json +71 -0
- package/template/AGENTS.md +87 -0
- package/template/README.md +128 -0
- package/template/apps/server/Dockerfile +34 -0
- package/template/apps/server/package.json +30 -0
- package/template/apps/server/src/access-guards.ts +112 -0
- package/template/apps/server/src/admin/routes.test.ts +105 -0
- package/template/apps/server/src/admin/routes.ts +95 -0
- package/template/apps/server/src/agent/data-scope-routes.test.ts +143 -0
- package/template/apps/server/src/agent/routes.test.ts +244 -0
- package/template/apps/server/src/agent/routes.ts +257 -0
- package/template/apps/server/src/api-app.ts +32 -0
- package/template/apps/server/src/application-services.ts +154 -0
- package/template/apps/server/src/audit/contracts.ts +21 -0
- package/template/apps/server/src/audit/drizzle-log-store.ts +150 -0
- package/template/apps/server/src/audit/policy.ts +18 -0
- package/template/apps/server/src/audit/recovery-queue.test.ts +42 -0
- package/template/apps/server/src/audit/recovery-queue.ts +63 -0
- package/template/apps/server/src/audit/redaction.ts +55 -0
- package/template/apps/server/src/audit/reliable-writer.test.ts +200 -0
- package/template/apps/server/src/audit/reliable-writer.ts +201 -0
- package/template/apps/server/src/audit/search-summary.ts +32 -0
- package/template/apps/server/src/auth/actor-resolver.test.ts +138 -0
- package/template/apps/server/src/auth/actor-resolver.ts +109 -0
- package/template/apps/server/src/auth/authentication-provider.test.ts +180 -0
- package/template/apps/server/src/auth/authentication-provider.ts +117 -0
- package/template/apps/server/src/auth/authorization-snapshot.test.ts +117 -0
- package/template/apps/server/src/auth/authorization-snapshot.ts +98 -0
- package/template/apps/server/src/auth/bearer-token.ts +5 -0
- package/template/apps/server/src/auth/bootstrap-admin.ts +33 -0
- package/template/apps/server/src/auth/credential-restriction.ts +29 -0
- package/template/apps/server/src/auth/credential-routes.test.ts +190 -0
- package/template/apps/server/src/auth/credential-service.ts +165 -0
- package/template/apps/server/src/auth/development-bypass.ts +22 -0
- package/template/apps/server/src/auth/drizzle-repository.ts +315 -0
- package/template/apps/server/src/auth/drizzle-session-operations.ts +119 -0
- package/template/apps/server/src/auth/login-routes.ts +121 -0
- package/template/apps/server/src/auth/own-session-routes.test.ts +248 -0
- package/template/apps/server/src/auth/own-session-routes.ts +110 -0
- package/template/apps/server/src/auth/password.test.ts +30 -0
- package/template/apps/server/src/auth/password.ts +46 -0
- package/template/apps/server/src/auth/repository.test.ts +61 -0
- package/template/apps/server/src/auth/repository.ts +305 -0
- package/template/apps/server/src/auth/routes.test.ts +350 -0
- package/template/apps/server/src/auth/routes.ts +237 -0
- package/template/apps/server/src/auth/runtime.ts +20 -0
- package/template/apps/server/src/auth/service.ts +329 -0
- package/template/apps/server/src/auth/session-service.ts +123 -0
- package/template/apps/server/src/background/task-guard.test.ts +66 -0
- package/template/apps/server/src/background/task-guard.ts +49 -0
- package/template/apps/server/src/bulk-data/artifact-store.ts +82 -0
- package/template/apps/server/src/bulk-data/dictionary-handler.ts +122 -0
- package/template/apps/server/src/bulk-data/drizzle-repository.integration.test.ts +156 -0
- package/template/apps/server/src/bulk-data/drizzle-repository.ts +298 -0
- package/template/apps/server/src/bulk-data/helpers.ts +36 -0
- package/template/apps/server/src/bulk-data/input-validation.ts +99 -0
- package/template/apps/server/src/bulk-data/repository.ts +246 -0
- package/template/apps/server/src/bulk-data/resource-handler.ts +27 -0
- package/template/apps/server/src/bulk-data/routes.test.ts +169 -0
- package/template/apps/server/src/bulk-data/routes.ts +248 -0
- package/template/apps/server/src/bulk-data/scheduler-integration.test.ts +142 -0
- package/template/apps/server/src/bulk-data/service.test.ts +347 -0
- package/template/apps/server/src/bulk-data/service.ts +319 -0
- package/template/apps/server/src/bulk-data/types.ts +73 -0
- package/template/apps/server/src/configuration/bootstrap.ts +59 -0
- package/template/apps/server/src/configuration/definition.ts +89 -0
- package/template/apps/server/src/configuration/drizzle-repository.ts +166 -0
- package/template/apps/server/src/configuration/repository.ts +138 -0
- package/template/apps/server/src/configuration/routes.test.ts +178 -0
- package/template/apps/server/src/configuration/routes.ts +260 -0
- package/template/apps/server/src/configuration/service.test.ts +128 -0
- package/template/apps/server/src/configuration/service.ts +187 -0
- package/template/apps/server/src/data-access/context.ts +162 -0
- package/template/apps/server/src/data-access/department-tree.ts +27 -0
- package/template/apps/server/src/data-access/drizzle-predicate.test.ts +86 -0
- package/template/apps/server/src/data-access/drizzle-predicate.ts +50 -0
- package/template/apps/server/src/data-access/errors.ts +5 -0
- package/template/apps/server/src/data-access/platform-actor.ts +25 -0
- package/template/apps/server/src/data-access/query-specification.test.ts +82 -0
- package/template/apps/server/src/data-access/query-specification.ts +77 -0
- package/template/apps/server/src/data-access/scoped-repository.integration.test.ts +203 -0
- package/template/apps/server/src/data-access/scoped-repository.ts +268 -0
- package/template/apps/server/src/data-access/scoped-resource.test.ts +158 -0
- package/template/apps/server/src/data-access/scoped-resource.ts +141 -0
- package/template/apps/server/src/data-governance/export/approval-port.ts +84 -0
- package/template/apps/server/src/data-governance/export/authorization-port.test.ts +103 -0
- package/template/apps/server/src/data-governance/export/authorization-port.ts +69 -0
- package/template/apps/server/src/data-governance/export/drizzle-repository.integration.test.ts +88 -0
- package/template/apps/server/src/data-governance/export/drizzle-repository.ts +97 -0
- package/template/apps/server/src/data-governance/export/job-runtime.test.ts +339 -0
- package/template/apps/server/src/data-governance/export/job-runtime.ts +242 -0
- package/template/apps/server/src/data-governance/export/ndjson-stream.ts +62 -0
- package/template/apps/server/src/data-governance/export/postgres-api-actors.ts +140 -0
- package/template/apps/server/src/data-governance/export/postgres-api-assertions.ts +76 -0
- package/template/apps/server/src/data-governance/export/postgres-api-fixture.ts +265 -0
- package/template/apps/server/src/data-governance/export/postgres-api.integration.test.ts +298 -0
- package/template/apps/server/src/data-governance/export/postgres-recovery.integration.test.ts +344 -0
- package/template/apps/server/src/data-governance/export/repository.test.ts +55 -0
- package/template/apps/server/src/data-governance/export/repository.ts +83 -0
- package/template/apps/server/src/data-governance/export/request-fingerprint.test.ts +51 -0
- package/template/apps/server/src/data-governance/export/request-fingerprint.ts +45 -0
- package/template/apps/server/src/data-governance/export/routes-integrity.test.ts +90 -0
- package/template/apps/server/src/data-governance/export/routes-test-fixture.ts +239 -0
- package/template/apps/server/src/data-governance/export/routes.test.ts +182 -0
- package/template/apps/server/src/data-governance/export/routes.ts +215 -0
- package/template/apps/server/src/data-governance/export/scope-snapshot.test.ts +45 -0
- package/template/apps/server/src/data-governance/export/scope-snapshot.ts +27 -0
- package/template/apps/server/src/data-governance/export/service.ts +337 -0
- package/template/apps/server/src/data-governance/export/source.ts +69 -0
- package/template/apps/server/src/data-governance/export/types.ts +55 -0
- package/template/apps/server/src/data-governance/plaintext-access.test.ts +70 -0
- package/template/apps/server/src/data-governance/plaintext-access.ts +88 -0
- package/template/apps/server/src/data-governance/plaintext-postgres.integration.test.ts +223 -0
- package/template/apps/server/src/data-governance/user-plaintext-routes.test.ts +287 -0
- package/template/apps/server/src/data-governance/user-plaintext-routes.ts +181 -0
- package/template/apps/server/src/data-governance/user-projection.ts +54 -0
- package/template/apps/server/src/data-governance/user-sensitive-read-service.ts +54 -0
- package/template/apps/server/src/example-modules.ts +62 -0
- package/template/apps/server/src/example-permissions.ts +5 -0
- package/template/apps/server/src/feature/manifest-feature-repository.test.ts +187 -0
- package/template/apps/server/src/feature/manifest-feature-repository.ts +200 -0
- package/template/apps/server/src/feature/routes.authorization.test.ts +199 -0
- package/template/apps/server/src/feature/routes.ts +193 -0
- package/template/apps/server/src/foundation-access.test.ts +50 -0
- package/template/apps/server/src/foundation-access.ts +34 -0
- package/template/apps/server/src/foundation-route.ts +55 -0
- package/template/apps/server/src/foundation.ts +85 -0
- package/template/apps/server/src/guards.test.ts +74 -0
- package/template/apps/server/src/guards.ts +214 -0
- package/template/apps/server/src/http-app.test.ts +77 -0
- package/template/apps/server/src/http-app.ts +51 -0
- package/template/apps/server/src/index.ts +374 -0
- package/template/apps/server/src/jobs/artifact-service.test.ts +78 -0
- package/template/apps/server/src/jobs/artifact-service.ts +94 -0
- package/template/apps/server/src/jobs/drizzle-artifact.ts +63 -0
- package/template/apps/server/src/jobs/drizzle-claim.ts +111 -0
- package/template/apps/server/src/jobs/drizzle-execution-repository.ts +299 -0
- package/template/apps/server/src/jobs/drizzle-execution.integration.test.ts +232 -0
- package/template/apps/server/src/jobs/drizzle-lease.ts +21 -0
- package/template/apps/server/src/jobs/drizzle-mappers.ts +121 -0
- package/template/apps/server/src/jobs/drizzle-recovery-repository.ts +214 -0
- package/template/apps/server/src/jobs/drizzle-repository.integration.test.ts +135 -0
- package/template/apps/server/src/jobs/drizzle-repository.ts +268 -0
- package/template/apps/server/src/jobs/execution-repository.ts +72 -0
- package/template/apps/server/src/jobs/execution.test.ts +303 -0
- package/template/apps/server/src/jobs/handler-registry.ts +81 -0
- package/template/apps/server/src/jobs/in-memory-claim.ts +96 -0
- package/template/apps/server/src/jobs/in-memory-execution.ts +336 -0
- package/template/apps/server/src/jobs/in-memory-lease.ts +66 -0
- package/template/apps/server/src/jobs/legacy-adapter.integration.test.ts +177 -0
- package/template/apps/server/src/jobs/legacy-adapter.test.ts +199 -0
- package/template/apps/server/src/jobs/legacy-adapter.ts +109 -0
- package/template/apps/server/src/jobs/legacy-service-runtime.ts +95 -0
- package/template/apps/server/src/jobs/repository.ts +141 -0
- package/template/apps/server/src/jobs/service.test.ts +64 -0
- package/template/apps/server/src/jobs/service.ts +44 -0
- package/template/apps/server/src/jobs/types.ts +180 -0
- package/template/apps/server/src/jobs/worker.ts +258 -0
- package/template/apps/server/src/license/legacy-license-resolver.ts +23 -0
- package/template/apps/server/src/license/license-resolver.test.ts +55 -0
- package/template/apps/server/src/license/license-resolver.ts +122 -0
- package/template/apps/server/src/license/reminder.test.ts +61 -0
- package/template/apps/server/src/license/reminder.ts +33 -0
- package/template/apps/server/src/license/restriction.test.ts +54 -0
- package/template/apps/server/src/license/restriction.ts +80 -0
- package/template/apps/server/src/license/routes-offline-code.test.ts +173 -0
- package/template/apps/server/src/license/routes.ts +99 -0
- package/template/apps/server/src/license/runtime-audit-reliability.test.ts +96 -0
- package/template/apps/server/src/license/runtime-reminder.test.ts +147 -0
- package/template/apps/server/src/license/runtime-service-test-http.ts +28 -0
- package/template/apps/server/src/license/runtime-service.test.ts +334 -0
- package/template/apps/server/src/license/runtime-service.ts +308 -0
- package/template/apps/server/src/module-composition.test.ts +70 -0
- package/template/apps/server/src/module-composition.ts +28 -0
- package/template/apps/server/src/notification/drizzle-repository.ts +233 -0
- package/template/apps/server/src/notification/repository.ts +160 -0
- package/template/apps/server/src/notification/routes.test.ts +151 -0
- package/template/apps/server/src/notification/routes.ts +185 -0
- package/template/apps/server/src/observability/bootstrap.ts +56 -0
- package/template/apps/server/src/observability/http-observability.test.ts +53 -0
- package/template/apps/server/src/observability/http-observability.ts +54 -0
- package/template/apps/server/src/observability/metrics.test.ts +36 -0
- package/template/apps/server/src/observability/metrics.ts +105 -0
- package/template/apps/server/src/observability/readiness.test.ts +36 -0
- package/template/apps/server/src/observability/readiness.ts +43 -0
- package/template/apps/server/src/observability/routes.test.ts +61 -0
- package/template/apps/server/src/observability/routes.ts +44 -0
- package/template/apps/server/src/pagination.ts +31 -0
- package/template/apps/server/src/persistence.integration.test.ts +54 -0
- package/template/apps/server/src/persistence.ts +118 -0
- package/template/apps/server/src/profile/routes.test.ts +190 -0
- package/template/apps/server/src/profile/routes.ts +173 -0
- package/template/apps/server/src/request-restriction.ts +29 -0
- package/template/apps/server/src/route-guards.test.ts +148 -0
- package/template/apps/server/src/route-guards.ts +63 -0
- package/template/apps/server/src/runtime-audit-list.test.ts +98 -0
- package/template/apps/server/src/runtime-config.ts +11 -0
- package/template/apps/server/src/runtime-development.ts +68 -0
- package/template/apps/server/src/runtime-license.ts +50 -0
- package/template/apps/server/src/runtime.test.ts +264 -0
- package/template/apps/server/src/runtime.ts +324 -0
- package/template/apps/server/src/scheduler/audit.ts +38 -0
- package/template/apps/server/src/scheduler/definitions.test.ts +35 -0
- package/template/apps/server/src/scheduler/definitions.ts +79 -0
- package/template/apps/server/src/scheduler/drizzle-durable-links.ts +52 -0
- package/template/apps/server/src/scheduler/drizzle-mappers.ts +36 -0
- package/template/apps/server/src/scheduler/drizzle-repository.integration.test.ts +174 -0
- package/template/apps/server/src/scheduler/drizzle-repository.ts +348 -0
- package/template/apps/server/src/scheduler/execution-context.ts +24 -0
- package/template/apps/server/src/scheduler/execution-recorder.ts +101 -0
- package/template/apps/server/src/scheduler/feature-preflight.ts +40 -0
- package/template/apps/server/src/scheduler/history.ts +22 -0
- package/template/apps/server/src/scheduler/overview.test.ts +89 -0
- package/template/apps/server/src/scheduler/overview.ts +125 -0
- package/template/apps/server/src/scheduler/recovery-conflict.ts +19 -0
- package/template/apps/server/src/scheduler/recovery-service.test.ts +238 -0
- package/template/apps/server/src/scheduler/recovery-service.ts +152 -0
- package/template/apps/server/src/scheduler/repository.ts +274 -0
- package/template/apps/server/src/scheduler/routes.test.ts +347 -0
- package/template/apps/server/src/scheduler/routes.ts +222 -0
- package/template/apps/server/src/scheduler/sensitive-text.ts +20 -0
- package/template/apps/server/src/scheduler/service-idle.test.ts +73 -0
- package/template/apps/server/src/scheduler/service.test.ts +330 -0
- package/template/apps/server/src/scheduler/service.ts +339 -0
- package/template/apps/server/src/scheduler/types.ts +103 -0
- package/template/apps/server/src/scheduler/worker.ts +38 -0
- package/template/apps/server/src/search/config.test.ts +43 -0
- package/template/apps/server/src/search/config.ts +62 -0
- package/template/apps/server/src/search/contracts.ts +127 -0
- package/template/apps/server/src/search/cursor.ts +39 -0
- package/template/apps/server/src/search/errors.ts +11 -0
- package/template/apps/server/src/search/host.ts +36 -0
- package/template/apps/server/src/search/masking.ts +6 -0
- package/template/apps/server/src/search/provider-execution.ts +195 -0
- package/template/apps/server/src/search/rate-limiter.ts +23 -0
- package/template/apps/server/src/search/registry.ts +105 -0
- package/template/apps/server/src/search/routes.test.ts +156 -0
- package/template/apps/server/src/search/routes.ts +95 -0
- package/template/apps/server/src/search/service.test.ts +314 -0
- package/template/apps/server/src/search/service.ts +257 -0
- package/template/apps/server/src/search/test-support.ts +122 -0
- package/template/apps/server/src/session/routes.test.ts +111 -0
- package/template/apps/server/src/session/routes.ts +56 -0
- package/template/apps/server/src/settings/drizzle-repository.ts +66 -0
- package/template/apps/server/src/settings/repository.ts +29 -0
- package/template/apps/server/src/settings/routes.test.ts +250 -0
- package/template/apps/server/src/settings/routes.ts +175 -0
- package/template/apps/server/src/settings/runtime.ts +13 -0
- package/template/apps/server/src/storage/blob-reference-registry.test.ts +25 -0
- package/template/apps/server/src/storage/blob-reference-registry.ts +15 -0
- package/template/apps/server/src/storage/drizzle-upload-repository.integration.test.ts +136 -0
- package/template/apps/server/src/storage/drizzle-upload-repository.ts +248 -0
- package/template/apps/server/src/storage/route-support.ts +84 -0
- package/template/apps/server/src/storage/routes.test.ts +288 -0
- package/template/apps/server/src/storage/routes.ts +297 -0
- package/template/apps/server/src/storage/runtime.ts +86 -0
- package/template/apps/server/src/system/audit-query.ts +17 -0
- package/template/apps/server/src/system/audit-routes.test.ts +139 -0
- package/template/apps/server/src/system/audit-routes.ts +113 -0
- package/template/apps/server/src/system/built-in-roles.ts +116 -0
- package/template/apps/server/src/system/department-routes.test.ts +80 -0
- package/template/apps/server/src/system/department-routes.ts +90 -0
- package/template/apps/server/src/system/drizzle-mapping.ts +53 -0
- package/template/apps/server/src/system/drizzle-repository.ts +298 -0
- package/template/apps/server/src/system/drizzle-scoped-repository.ts +235 -0
- package/template/apps/server/src/system/drizzle-system.ts +361 -0
- package/template/apps/server/src/system/entities.ts +78 -0
- package/template/apps/server/src/system/feature-routes.test.ts +55 -0
- package/template/apps/server/src/system/identity-route-config.ts +73 -0
- package/template/apps/server/src/system/interface-catalog.test.ts +103 -0
- package/template/apps/server/src/system/interface-catalog.ts +82 -0
- package/template/apps/server/src/system/menu-registry.test.ts +125 -0
- package/template/apps/server/src/system/menu-registry.ts +259 -0
- package/template/apps/server/src/system/menu-routes.test.ts +68 -0
- package/template/apps/server/src/system/menu-routes.ts +200 -0
- package/template/apps/server/src/system/mutation-runner.ts +33 -0
- package/template/apps/server/src/system/operation-monitoring.test.ts +78 -0
- package/template/apps/server/src/system/operation-monitoring.ts +233 -0
- package/template/apps/server/src/system/operations.test.ts +269 -0
- package/template/apps/server/src/system/operations.ts +155 -0
- package/template/apps/server/src/system/postgres-monitoring.ts +31 -0
- package/template/apps/server/src/system/redis-health.test.ts +116 -0
- package/template/apps/server/src/system/redis-health.ts +230 -0
- package/template/apps/server/src/system/repository.ts +234 -0
- package/template/apps/server/src/system/resource-access-response.ts +47 -0
- package/template/apps/server/src/system/resource-export-route.ts +64 -0
- package/template/apps/server/src/system/resource-route-support.ts +50 -0
- package/template/apps/server/src/system/response-projection.ts +24 -0
- package/template/apps/server/src/system/route-helpers.ts +104 -0
- package/template/apps/server/src/system/route-test-app.ts +27 -0
- package/template/apps/server/src/system/route-types.ts +52 -0
- package/template/apps/server/src/system/routes-validation.test.ts +61 -0
- package/template/apps/server/src/system/routes.test.ts +311 -0
- package/template/apps/server/src/system/routes.ts +354 -0
- package/template/apps/server/src/system/seed.test.ts +129 -0
- package/template/apps/server/src/system/seed.ts +237 -0
- package/template/apps/server/src/system/user-account-policy.test.ts +158 -0
- package/template/apps/server/src/system/user-account-policy.ts +103 -0
- package/template/apps/server/src/system/user-data-scope.ts +10 -0
- package/template/apps/server/src/system/user-department-validation.ts +17 -0
- package/template/apps/server/src/system/user-projection.test.ts +40 -0
- package/template/apps/server/src/system/user-projection.ts +35 -0
- package/template/apps/server/src/work-order/data-scope.integration.test.ts +171 -0
- package/template/apps/server/src/work-order/drizzle-repository.integration.test.ts +78 -0
- package/template/apps/server/src/work-order/drizzle-repository.ts +67 -0
- package/template/apps/server/src/work-order/foundation-modules.test.ts +85 -0
- package/template/apps/server/src/work-order/repository.ts +46 -0
- package/template/apps/server/src/work-order/routes.test.ts +209 -0
- package/template/apps/server/src/work-order/routes.ts +159 -0
- package/template/apps/server/src/work-order/search-api.test.ts +121 -0
- package/template/apps/server/src/work-order/search-provider.test.ts +201 -0
- package/template/apps/server/src/work-order/search-provider.ts +59 -0
- package/template/apps/server/src/work-order/service.ts +82 -0
- package/template/apps/server/src/work-order/task.test.ts +79 -0
- package/template/apps/server/src/work-order/task.ts +30 -0
- package/template/apps/server/src/workflow/assignee-directory.ts +23 -0
- package/template/apps/server/src/workflow/drizzle-repository.integration.test.ts +213 -0
- package/template/apps/server/src/workflow/drizzle-repository.ts +299 -0
- package/template/apps/server/src/workflow/effects.test.ts +64 -0
- package/template/apps/server/src/workflow/effects.ts +112 -0
- package/template/apps/server/src/workflow/repository.ts +160 -0
- package/template/apps/server/src/workflow/routes.test.ts +256 -0
- package/template/apps/server/src/workflow/routes.ts +249 -0
- package/template/apps/server/src/workflow/service.ts +196 -0
- package/template/apps/server/src/workflow/timeout-runtime.test.ts +96 -0
- package/template/apps/server/src/workflow/timeout-runtime.ts +66 -0
- package/template/apps/server/tsconfig.json +17 -0
- package/template/apps/web/Dockerfile +41 -0
- package/template/apps/web/components.json +24 -0
- package/template/apps/web/dev/dev-identity.ts +58 -0
- package/template/apps/web/dev/dev-port.test.ts +53 -0
- package/template/apps/web/dev/dev-port.ts +68 -0
- package/template/apps/web/dev/start.ts +37 -0
- package/template/apps/web/index.html +14 -0
- package/template/apps/web/package.json +44 -0
- package/template/apps/web/runtime-server.test.ts +86 -0
- package/template/apps/web/runtime-server.ts +143 -0
- package/template/apps/web/server.ts +21 -0
- package/template/apps/web/src/App.vue +22 -0
- package/template/apps/web/src/app/home/HomePage.vue +75 -0
- package/template/apps/web/src/app/home/HomeWelcome.vue +85 -0
- package/template/apps/web/src/app/home/HomeWelcome.webtest.ts +32 -0
- package/template/apps/web/src/app/layouts/AppLayout.vue +10 -0
- package/template/apps/web/src/components/auth/DevelopmentAuthWarning.vue +15 -0
- package/template/apps/web/src/components/auth/LoginForm.vue +80 -0
- package/template/apps/web/src/components/auth/LoginForm.webtest.ts +33 -0
- package/template/apps/web/src/components/auth/PasswordChangeForm.vue +90 -0
- package/template/apps/web/src/components/auth/UserSessionMenu.vue +60 -0
- package/template/apps/web/src/components/auth/UserSessionMenu.webtest.ts +45 -0
- package/template/apps/web/src/components/common/ConfirmDialog.vue +75 -0
- package/template/apps/web/src/components/common/DataPagination.vue +79 -0
- package/template/apps/web/src/components/common/DataPagination.webtest.ts +28 -0
- package/template/apps/web/src/components/common/EmptyState.vue +43 -0
- package/template/apps/web/src/components/common/FormDialog.vue +86 -0
- package/template/apps/web/src/components/common/ModalBody.vue +19 -0
- package/template/apps/web/src/components/common/ModalLayout.webtest.ts +54 -0
- package/template/apps/web/src/components/common/PageError.vue +46 -0
- package/template/apps/web/src/components/common/PageLoading.vue +41 -0
- package/template/apps/web/src/components/common/StatusSummary.vue +37 -0
- package/template/apps/web/src/components/common/UnsavedChangesDialog.vue +60 -0
- package/template/apps/web/src/components/common/UnsavedChangesDialog.webtest.ts +60 -0
- package/template/apps/web/src/components/license/LicenseActivationCodeForm.vue +80 -0
- package/template/apps/web/src/components/license/LicenseExpiryBanner.vue +54 -0
- package/template/apps/web/src/components/license/LicenseFlow.webtest.ts +170 -0
- package/template/apps/web/src/components/license/LicenseStatusCard.vue +95 -0
- package/template/apps/web/src/components/license/LicenseUploadForm.vue +79 -0
- package/template/apps/web/src/components/license/license-display.ts +12 -0
- package/template/apps/web/src/components/ui/alert/Alert.vue +21 -0
- package/template/apps/web/src/components/ui/alert/AlertAction.vue +17 -0
- package/template/apps/web/src/components/ui/alert/AlertDescription.vue +22 -0
- package/template/apps/web/src/components/ui/alert/AlertTitle.vue +22 -0
- package/template/apps/web/src/components/ui/alert/index.ts +25 -0
- package/template/apps/web/src/components/ui/badge/Badge.vue +29 -0
- package/template/apps/web/src/components/ui/badge/index.ts +28 -0
- package/template/apps/web/src/components/ui/breadcrumb/Breadcrumb.vue +18 -0
- package/template/apps/web/src/components/ui/breadcrumb/BreadcrumbEllipsis.vue +26 -0
- package/template/apps/web/src/components/ui/breadcrumb/BreadcrumbItem.vue +17 -0
- package/template/apps/web/src/components/ui/breadcrumb/BreadcrumbLink.vue +24 -0
- package/template/apps/web/src/components/ui/breadcrumb/BreadcrumbList.vue +22 -0
- package/template/apps/web/src/components/ui/breadcrumb/BreadcrumbPage.vue +20 -0
- package/template/apps/web/src/components/ui/breadcrumb/BreadcrumbSeparator.vue +23 -0
- package/template/apps/web/src/components/ui/breadcrumb/index.ts +7 -0
- package/template/apps/web/src/components/ui/button/Button.vue +31 -0
- package/template/apps/web/src/components/ui/button/index.ts +42 -0
- package/template/apps/web/src/components/ui/card/Card.vue +29 -0
- package/template/apps/web/src/components/ui/card/CardAction.vue +22 -0
- package/template/apps/web/src/components/ui/card/CardContent.vue +17 -0
- package/template/apps/web/src/components/ui/card/CardDescription.vue +17 -0
- package/template/apps/web/src/components/ui/card/CardFooter.vue +22 -0
- package/template/apps/web/src/components/ui/card/CardHeader.vue +22 -0
- package/template/apps/web/src/components/ui/card/CardTitle.vue +22 -0
- package/template/apps/web/src/components/ui/card/index.ts +7 -0
- package/template/apps/web/src/components/ui/checkbox/Checkbox.vue +41 -0
- package/template/apps/web/src/components/ui/checkbox/index.ts +1 -0
- package/template/apps/web/src/components/ui/dialog/Dialog.vue +15 -0
- package/template/apps/web/src/components/ui/dialog/DialogClose.vue +12 -0
- package/template/apps/web/src/components/ui/dialog/DialogContent.vue +62 -0
- package/template/apps/web/src/components/ui/dialog/DialogDescription.vue +30 -0
- package/template/apps/web/src/components/ui/dialog/DialogFooter.vue +33 -0
- package/template/apps/web/src/components/ui/dialog/DialogHeader.vue +17 -0
- package/template/apps/web/src/components/ui/dialog/DialogOverlay.vue +28 -0
- package/template/apps/web/src/components/ui/dialog/DialogScrollContent.vue +67 -0
- package/template/apps/web/src/components/ui/dialog/DialogTitle.vue +27 -0
- package/template/apps/web/src/components/ui/dialog/DialogTrigger.vue +12 -0
- package/template/apps/web/src/components/ui/dialog/index.ts +10 -0
- package/template/apps/web/src/components/ui/dropdown-menu/DropdownMenu.vue +19 -0
- package/template/apps/web/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +50 -0
- package/template/apps/web/src/components/ui/dropdown-menu/DropdownMenuContent.vue +48 -0
- package/template/apps/web/src/components/ui/dropdown-menu/DropdownMenuGroup.vue +12 -0
- package/template/apps/web/src/components/ui/dropdown-menu/DropdownMenuItem.vue +41 -0
- package/template/apps/web/src/components/ui/dropdown-menu/DropdownMenuLabel.vue +30 -0
- package/template/apps/web/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +21 -0
- package/template/apps/web/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +51 -0
- package/template/apps/web/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue +23 -0
- package/template/apps/web/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue +22 -0
- package/template/apps/web/src/components/ui/dropdown-menu/DropdownMenuSub.vue +19 -0
- package/template/apps/web/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue +34 -0
- package/template/apps/web/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +36 -0
- package/template/apps/web/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue +17 -0
- package/template/apps/web/src/components/ui/dropdown-menu/index.ts +16 -0
- package/template/apps/web/src/components/ui/input/Input.vue +33 -0
- package/template/apps/web/src/components/ui/input/index.ts +1 -0
- package/template/apps/web/src/components/ui/select/Select.vue +15 -0
- package/template/apps/web/src/components/ui/select/SelectContent.vue +61 -0
- package/template/apps/web/src/components/ui/select/SelectGroup.vue +23 -0
- package/template/apps/web/src/components/ui/select/SelectItem.vue +49 -0
- package/template/apps/web/src/components/ui/select/SelectItemText.vue +12 -0
- package/template/apps/web/src/components/ui/select/SelectLabel.vue +19 -0
- package/template/apps/web/src/components/ui/select/SelectScrollDownButton.vue +34 -0
- package/template/apps/web/src/components/ui/select/SelectScrollUpButton.vue +34 -0
- package/template/apps/web/src/components/ui/select/SelectSeparator.vue +21 -0
- package/template/apps/web/src/components/ui/select/SelectTrigger.vue +43 -0
- package/template/apps/web/src/components/ui/select/SelectValue.vue +12 -0
- package/template/apps/web/src/components/ui/select/index.ts +11 -0
- package/template/apps/web/src/components/ui/separator/Separator.vue +30 -0
- package/template/apps/web/src/components/ui/separator/index.ts +1 -0
- package/template/apps/web/src/components/ui/sheet/Sheet.vue +15 -0
- package/template/apps/web/src/components/ui/sheet/SheetClose.vue +12 -0
- package/template/apps/web/src/components/ui/sheet/SheetContent.vue +62 -0
- package/template/apps/web/src/components/ui/sheet/SheetDescription.vue +23 -0
- package/template/apps/web/src/components/ui/sheet/SheetFooter.vue +15 -0
- package/template/apps/web/src/components/ui/sheet/SheetHeader.vue +15 -0
- package/template/apps/web/src/components/ui/sheet/SheetOverlay.vue +28 -0
- package/template/apps/web/src/components/ui/sheet/SheetTitle.vue +25 -0
- package/template/apps/web/src/components/ui/sheet/SheetTrigger.vue +12 -0
- package/template/apps/web/src/components/ui/sheet/index.ts +8 -0
- package/template/apps/web/src/components/ui/sidebar/Sidebar.vue +114 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarContent.vue +23 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarFooter.vue +18 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarGroup.vue +18 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarGroupAction.vue +29 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarGroupContent.vue +18 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarGroupLabel.vue +29 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarHeader.vue +18 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarInput.vue +19 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarInset.vue +22 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarMenu.vue +18 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarMenuAction.vue +37 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarMenuBadge.vue +23 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarMenuButton.vue +60 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarMenuButtonChild.vue +36 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarMenuItem.vue +18 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarMenuSkeleton.vue +35 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarMenuSub.vue +23 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarMenuSubButton.vue +39 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarMenuSubItem.vue +18 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarProvider.vue +128 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarRail.vue +94 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarSeparator.vue +19 -0
- package/template/apps/web/src/components/ui/sidebar/SidebarTrigger.vue +28 -0
- package/template/apps/web/src/components/ui/sidebar/index.ts +62 -0
- package/template/apps/web/src/components/ui/sidebar/sidebar-width.ts +29 -0
- package/template/apps/web/src/components/ui/sidebar/sidebar-width.webtest.ts +28 -0
- package/template/apps/web/src/components/ui/sidebar/utils.ts +26 -0
- package/template/apps/web/src/components/ui/skeleton/Skeleton.vue +17 -0
- package/template/apps/web/src/components/ui/skeleton/index.ts +1 -0
- package/template/apps/web/src/components/ui/sonner/Sonner.vue +70 -0
- package/template/apps/web/src/components/ui/sonner/index.ts +1 -0
- package/template/apps/web/src/components/ui/switch/Switch.vue +47 -0
- package/template/apps/web/src/components/ui/switch/Switch.webtest.ts +23 -0
- package/template/apps/web/src/components/ui/switch/index.ts +1 -0
- package/template/apps/web/src/components/ui/table/Table.vue +19 -0
- package/template/apps/web/src/components/ui/table/TableBody.vue +17 -0
- package/template/apps/web/src/components/ui/table/TableCaption.vue +17 -0
- package/template/apps/web/src/components/ui/table/TableCell.vue +22 -0
- package/template/apps/web/src/components/ui/table/TableEmpty.vue +37 -0
- package/template/apps/web/src/components/ui/table/TableFooter.vue +19 -0
- package/template/apps/web/src/components/ui/table/TableHead.vue +22 -0
- package/template/apps/web/src/components/ui/table/TableHeader.vue +14 -0
- package/template/apps/web/src/components/ui/table/TableRow.vue +22 -0
- package/template/apps/web/src/components/ui/table/index.ts +9 -0
- package/template/apps/web/src/components/ui/table/utils.ts +10 -0
- package/template/apps/web/src/components/ui/tabs/Tabs.vue +27 -0
- package/template/apps/web/src/components/ui/tabs/TabsContent.vue +23 -0
- package/template/apps/web/src/components/ui/tabs/TabsList.vue +34 -0
- package/template/apps/web/src/components/ui/tabs/TabsTrigger.vue +33 -0
- package/template/apps/web/src/components/ui/tabs/index.ts +24 -0
- package/template/apps/web/src/components/ui/tooltip/Tooltip.vue +15 -0
- package/template/apps/web/src/components/ui/tooltip/TooltipContent.vue +49 -0
- package/template/apps/web/src/components/ui/tooltip/TooltipProvider.vue +14 -0
- package/template/apps/web/src/components/ui/tooltip/TooltipTrigger.vue +12 -0
- package/template/apps/web/src/components/ui/tooltip/index.ts +4 -0
- package/template/apps/web/src/composables/useAccessSnapshot.ts +55 -0
- package/template/apps/web/src/composables/useAccessSnapshot.webtest.ts +39 -0
- package/template/apps/web/src/composables/useAppToast.ts +30 -0
- package/template/apps/web/src/composables/useAuthSession.ts +127 -0
- package/template/apps/web/src/composables/useAuthSession.webtest.ts +48 -0
- package/template/apps/web/src/composables/useLicenseReminderRefresh.ts +27 -0
- package/template/apps/web/src/composables/useLicenseReminderRefresh.webtest.ts +30 -0
- package/template/apps/web/src/composables/useLicenseRuntime.ts +90 -0
- package/template/apps/web/src/composables/useLoginFlow.ts +39 -0
- package/template/apps/web/src/composables/useModuleConfigurations.ts +116 -0
- package/template/apps/web/src/composables/usePasswordChange.ts +31 -0
- package/template/apps/web/src/composables/usePlatformSettings.ts +90 -0
- package/template/apps/web/src/composables/useSessionContext.ts +56 -0
- package/template/apps/web/src/composables/useTheme.ts +123 -0
- package/template/apps/web/src/composables/useUnsavedChangesConfirmation.ts +55 -0
- package/template/apps/web/src/composables/useWatermarkSettings.ts +56 -0
- package/template/apps/web/src/composables/watermark-settings.ts +45 -0
- package/template/apps/web/src/composables/watermark-settings.webtest.ts +38 -0
- package/template/apps/web/src/env.d.ts +17 -0
- package/template/apps/web/src/layout/AppHeader.vue +107 -0
- package/template/apps/web/src/layout/AppShell.vue +55 -0
- package/template/apps/web/src/layout/AppShell.webtest.ts +75 -0
- package/template/apps/web/src/layout/AppSidebar.vue +262 -0
- package/template/apps/web/src/layout/AppSidebar.webtest.ts +167 -0
- package/template/apps/web/src/layout/GlobalWatermark.vue +38 -0
- package/template/apps/web/src/layout/NavigationSearchDialog.vue +166 -0
- package/template/apps/web/src/layout/NavigationSearchDialog.webtest.ts +84 -0
- package/template/apps/web/src/layout/NotificationMenu.vue +174 -0
- package/template/apps/web/src/layout/NotificationMenu.webtest.ts +102 -0
- package/template/apps/web/src/layout/ThemeToggle.vue +44 -0
- package/template/apps/web/src/layout/navigation.ts +103 -0
- package/template/apps/web/src/layout/navigation.webtest.ts +99 -0
- package/template/apps/web/src/lib/date-time.ts +21 -0
- package/template/apps/web/src/lib/date-time.webtest.ts +14 -0
- package/template/apps/web/src/lib/utils.ts +7 -0
- package/template/apps/web/src/main.ts +11 -0
- package/template/apps/web/src/pages/AccessDeniedPage.vue +61 -0
- package/template/apps/web/src/pages/auth/ChangePasswordPage.vue +46 -0
- package/template/apps/web/src/pages/auth/LoginPage.vue +63 -0
- package/template/apps/web/src/pages/configuration/ModuleConfigurationPage.vue +15 -0
- package/template/apps/web/src/pages/configuration/components/ModuleConfigRollbackDialog.vue +51 -0
- package/template/apps/web/src/pages/configuration/components/ModuleConfigVersionList.vue +116 -0
- package/template/apps/web/src/pages/configuration/components/ModuleConfigurationEditor.vue +126 -0
- package/template/apps/web/src/pages/configuration/components/ModuleConfigurationEditor.webtest.ts +73 -0
- package/template/apps/web/src/pages/configuration/components/ModuleConfigurationWorkbench.vue +236 -0
- package/template/apps/web/src/pages/dashboard/DashboardPage.vue +39 -0
- package/template/apps/web/src/pages/dashboard/DashboardPage.webtest.ts +37 -0
- package/template/apps/web/src/pages/dashboard/components/DashboardAttention.vue +36 -0
- package/template/apps/web/src/pages/dashboard/components/DashboardMetricCards.vue +28 -0
- package/template/apps/web/src/pages/dashboard/dashboard-presenter.ts +115 -0
- package/template/apps/web/src/pages/dashboard/dashboard-presenter.webtest.ts +92 -0
- package/template/apps/web/src/pages/license/LicensePage.vue +65 -0
- package/template/apps/web/src/pages/profile/PersonalSettingsPage.vue +177 -0
- package/template/apps/web/src/pages/profile/PersonalSettingsPage.webtest.ts +78 -0
- package/template/apps/web/src/pages/settings/BrandingSettingsSection.vue +198 -0
- package/template/apps/web/src/pages/settings/GlobalSettingsPage.vue +195 -0
- package/template/apps/web/src/pages/settings/GlobalSettingsPage.webtest.ts +314 -0
- package/template/apps/web/src/pages/settings/WatermarkSettingsSection.vue +115 -0
- package/template/apps/web/src/pages/settings/logo-file.ts +23 -0
- package/template/apps/web/src/pages/settings/logo-file.webtest.ts +14 -0
- package/template/apps/web/src/pages/system/SystemNotificationsPage.vue +262 -0
- package/template/apps/web/src/pages/system/SystemNotificationsPage.webtest.ts +88 -0
- package/template/apps/web/src/pages/system/SystemOperationsPage.vue +151 -0
- package/template/apps/web/src/pages/system/SystemOperationsPage.webtest.ts +146 -0
- package/template/apps/web/src/pages/system/SystemResourceRoutePage.vue +80 -0
- package/template/apps/web/src/pages/system/SystemResourceRoutePage.webtest.ts +100 -0
- package/template/apps/web/src/pages/system/components/AuditActionCell.vue +87 -0
- package/template/apps/web/src/pages/system/components/AuditActionCell.webtest.ts +66 -0
- package/template/apps/web/src/pages/system/components/AuditLogFilters.vue +119 -0
- package/template/apps/web/src/pages/system/components/AuditLogFilters.webtest.ts +59 -0
- package/template/apps/web/src/pages/system/components/DiskUsageChart.vue +62 -0
- package/template/apps/web/src/pages/system/components/FeatureLicensePolicyDialog.vue +136 -0
- package/template/apps/web/src/pages/system/components/FeatureLicensePolicyDialog.webtest.ts +67 -0
- package/template/apps/web/src/pages/system/components/NotificationPublishForm.vue +57 -0
- package/template/apps/web/src/pages/system/components/OperationCacheMonitor.vue +73 -0
- package/template/apps/web/src/pages/system/components/OperationOnlineUsers.vue +60 -0
- package/template/apps/web/src/pages/system/components/OperationOnlineUsers.webtest.ts +35 -0
- package/template/apps/web/src/pages/system/components/OperationServiceMonitor.vue +118 -0
- package/template/apps/web/src/pages/system/components/OperationServiceMonitor.webtest.ts +64 -0
- package/template/apps/web/src/pages/system/components/SchedulerOperationsPanel.vue +297 -0
- package/template/apps/web/src/pages/system/components/SchedulerOperationsPanel.webtest.ts +145 -0
- package/template/apps/web/src/pages/system/components/SchedulerRunTable.vue +127 -0
- package/template/apps/web/src/pages/system/components/SchedulerRunTable.webtest.ts +75 -0
- package/template/apps/web/src/pages/system/components/SchedulerStaleRecoveryForm.vue +125 -0
- package/template/apps/web/src/pages/system/components/SchedulerStaleRecoveryForm.webtest.ts +84 -0
- package/template/apps/web/src/pages/system/components/SystemResourceFilters.vue +64 -0
- package/template/apps/web/src/pages/system/components/SystemResourceForm.vue +102 -0
- package/template/apps/web/src/pages/system/components/SystemResourcePage.vue +360 -0
- package/template/apps/web/src/pages/system/components/SystemResourcePage.webtest.ts +263 -0
- package/template/apps/web/src/pages/system/components/SystemResourceTable.vue +242 -0
- package/template/apps/web/src/pages/system/components/SystemResourceTable.webtest.ts +196 -0
- package/template/apps/web/src/pages/system/components/dictionary-bulk/DictionaryBulkActions.vue +142 -0
- package/template/apps/web/src/pages/system/components/dictionary-bulk/DictionaryBulkJobDetail.vue +109 -0
- package/template/apps/web/src/pages/system/components/dictionary-bulk/DictionaryBulkJobList.vue +127 -0
- package/template/apps/web/src/pages/system/components/dictionary-bulk/DictionaryBulkPanel.vue +72 -0
- package/template/apps/web/src/pages/system/components/dictionary-bulk/DictionaryBulkPanel.webtest.ts +255 -0
- package/template/apps/web/src/pages/system/components/feature-license-policy.ts +12 -0
- package/template/apps/web/src/pages/system/components/menu-management/MenuManagementPage.vue +131 -0
- package/template/apps/web/src/pages/system/components/menu-management/MenuManagementPage.webtest.ts +228 -0
- package/template/apps/web/src/pages/system/components/menu-management/MenuStructureTable.vue +230 -0
- package/template/apps/web/src/pages/system/components/menu-management/menu-model.ts +161 -0
- package/template/apps/web/src/pages/system/components/menu-management/menu-model.webtest.ts +133 -0
- package/template/apps/web/src/pages/system/components/menu-management/useMenuManagement.ts +117 -0
- package/template/apps/web/src/pages/system/components/role-policy/RolePermissionTree.vue +144 -0
- package/template/apps/web/src/pages/system/components/role-policy/RolePermissionTree.webtest.ts +55 -0
- package/template/apps/web/src/pages/system/components/role-policy/RolePolicyForm.vue +134 -0
- package/template/apps/web/src/pages/system/components/role-policy/permission-tree.ts +58 -0
- package/template/apps/web/src/pages/system/components/role-policy/permission-tree.webtest.ts +80 -0
- package/template/apps/web/src/pages/system/components/user-account/UserAccountForm.vue +307 -0
- package/template/apps/web/src/pages/system/components/user-account/UserRoleSelector.vue +111 -0
- package/template/apps/web/src/pages/system/components/user-account/UserRoleSelector.webtest.ts +45 -0
- package/template/apps/web/src/pages/system/components/user-account/save-user-account.ts +47 -0
- package/template/apps/web/src/pages/system/composables/useDictionaryBulkJobs.ts +152 -0
- package/template/apps/web/src/pages/system/composables/useFeatureLicenseEditor.ts +38 -0
- package/template/apps/web/src/pages/system/composables/useSchedulerOperations.ts +141 -0
- package/template/apps/web/src/pages/system/composables/useSchedulerOperations.webtest.ts +224 -0
- package/template/apps/web/src/pages/system/composables/useSystemResource.ts +269 -0
- package/template/apps/web/src/pages/system/composables/useSystemResource.webtest.ts +51 -0
- package/template/apps/web/src/pages/system/dictionary-bulk-presenter.ts +126 -0
- package/template/apps/web/src/pages/system/resource-config.ts +233 -0
- package/template/apps/web/src/router/auth-navigation.ts +76 -0
- package/template/apps/web/src/router/index.ts +246 -0
- package/template/apps/web/src/router/index.webtest.ts +396 -0
- package/template/apps/web/src/router/manifest-routes.ts +59 -0
- package/template/apps/web/src/services/access-api.ts +26 -0
- package/template/apps/web/src/services/auth-api.ts +72 -0
- package/template/apps/web/src/services/bulk-data-api.ts +105 -0
- package/template/apps/web/src/services/configuration-api.ts +43 -0
- package/template/apps/web/src/services/http.ts +145 -0
- package/template/apps/web/src/services/http.webtest.ts +73 -0
- package/template/apps/web/src/services/license-api.ts +53 -0
- package/template/apps/web/src/services/notification-api.ts +51 -0
- package/template/apps/web/src/services/operations-api.ts +128 -0
- package/template/apps/web/src/services/platform-settings-api.ts +21 -0
- package/template/apps/web/src/services/profile-api.ts +17 -0
- package/template/apps/web/src/services/session-context-api.ts +20 -0
- package/template/apps/web/src/services/system-api.ts +156 -0
- package/template/apps/web/src/style.css +142 -0
- package/template/apps/web/src/style.webtest.ts +18 -0
- package/template/apps/web/tsconfig.json +23 -0
- package/template/apps/web/vite.config.ts +26 -0
- package/template/apps/web/vitest.config.ts +14 -0
- package/template/bunfig.toml +2 -0
- package/template/docker-compose.yml +74 -0
- package/template/docs/adapters/ruoyi-vue-compatibility.md +93 -0
- package/template/docs/architecture/admin-surface-boundary.md +24 -0
- package/template/docs/architecture/data-scope-query-enforcement.md +26 -0
- package/template/docs/architecture/durable-jobs.md +101 -0
- package/template/docs/architecture/minimal-approval-workflow.md +60 -0
- package/template/docs/architecture/module-manifest-composition.md +47 -0
- package/template/docs/architecture/object-storage.md +65 -0
- package/template/docs/architecture/search-provider-protocol.md +59 -0
- package/template/docs/development/crud-generator.md +57 -0
- package/template/docs/license/license-offline-activation-code.md +67 -0
- package/template/docs/operations/observability.md +50 -0
- package/template/docs/platform/agent-tools.md +37 -0
- package/template/docs/platform/audit-reliability.md +95 -0
- package/template/docs/platform/bulk-data-jobs.md +156 -0
- package/template/docs/platform/data-access-control.md +62 -0
- package/template/docs/platform/module-configuration.md +98 -0
- package/template/docs/platform/navigation-registry.md +36 -0
- package/template/docs/platform/notifications.md +33 -0
- package/template/docs/platform/operations-overview.md +35 -0
- package/template/docs/platform/organization-membership.md +31 -0
- package/template/docs/platform/platform-authentication.md +127 -0
- package/template/docs/platform/platform-shell-settings.md +88 -0
- package/template/docs/platform/scheduled-task-executor.md +89 -0
- package/template/docs/platform/system-crud-api.md +100 -0
- package/template/docs/platform/web-system-crud.md +96 -0
- package/template/docs/product/built-in-roles.md +26 -0
- package/template/drizzle.config.ts +16 -0
- package/template/examples/inventory-item.crud.json +55 -0
- package/template/package.json +55 -0
- package/template/packages/config/index.test.ts +114 -0
- package/template/packages/config/index.ts +4 -0
- package/template/packages/config/package.json +13 -0
- package/template/packages/config/src/definition.ts +109 -0
- package/template/packages/config/src/environment-loader.ts +240 -0
- package/template/packages/config/src/platform.ts +185 -0
- package/template/packages/config/src/secrets.ts +69 -0
- package/template/packages/crud-generator/index.ts +3 -0
- package/template/packages/crud-generator/package.json +12 -0
- package/template/packages/crud-generator/src/cli.ts +31 -0
- package/template/packages/crud-generator/src/definition.ts +48 -0
- package/template/packages/crud-generator/src/generator.test.ts +180 -0
- package/template/packages/crud-generator/src/generator.ts +99 -0
- package/template/packages/crud-generator/src/template-helpers.ts +72 -0
- package/template/packages/crud-generator/src/templates/domain.ts +27 -0
- package/template/packages/crud-generator/src/templates/drizzle-repository.ts +126 -0
- package/template/packages/crud-generator/src/templates/dto.ts +19 -0
- package/template/packages/crud-generator/src/templates/index.ts +8 -0
- package/template/packages/crud-generator/src/templates/manifest.ts +69 -0
- package/template/packages/crud-generator/src/templates/project.ts +161 -0
- package/template/packages/crud-generator/src/templates/repository.ts +23 -0
- package/template/packages/crud-generator/src/templates/routes.ts +158 -0
- package/template/packages/crud-generator/src/templates/schema.ts +45 -0
- package/template/packages/crud-generator/src/templates/service.ts +32 -0
- package/template/packages/crud-generator/src/validation.ts +205 -0
- package/template/packages/crud-generator/tsconfig.json +15 -0
- package/template/packages/database/drizzle/0000_organic_madame_web.sql +136 -0
- package/template/packages/database/drizzle/0001_flawless_senator_kelly.sql +80 -0
- package/template/packages/database/drizzle/0002_woozy_squadron_supreme.sql +53 -0
- package/template/packages/database/drizzle/0003_far_carnage.sql +17 -0
- package/template/packages/database/drizzle/0004_flat_bastion.sql +2 -0
- package/template/packages/database/drizzle/0005_fixed_enchantress.sql +6 -0
- package/template/packages/database/drizzle/0006_groovy_overlord.sql +146 -0
- package/template/packages/database/drizzle/0007_chubby_may_parker.sql +9 -0
- package/template/packages/database/drizzle/0008_secret_toxin.sql +21 -0
- package/template/packages/database/drizzle/0009_ambiguous_adam_warlock.sql +46 -0
- package/template/packages/database/drizzle/0010_complex_orphan.sql +42 -0
- package/template/packages/database/drizzle/0011_lowly_maria_hill.sql +42 -0
- package/template/packages/database/drizzle/0012_serious_marvex.sql +11 -0
- package/template/packages/database/drizzle/0013_mysterious_miek.sql +48 -0
- package/template/packages/database/drizzle/0014_graceful_husk.sql +1 -0
- package/template/packages/database/drizzle/0015_illegal_jazinda.sql +29 -0
- package/template/packages/database/drizzle/0016_seed_platform_roles.sql +21 -0
- package/template/packages/database/drizzle/0017_silly_thunderbolt.sql +35 -0
- package/template/packages/database/drizzle/0018_cheerful_alex_power.sql +22 -0
- package/template/packages/database/drizzle/0019_omniscient_luckman.sql +3 -0
- package/template/packages/database/drizzle/0020_handy_vertigo.sql +18 -0
- package/template/packages/database/drizzle/0021_plain_paladin.sql +51 -0
- package/template/packages/database/drizzle/0022_icy_rhodey.sql +2 -0
- package/template/packages/database/drizzle/0023_fresh_thunderbolt_ross.sql +138 -0
- package/template/packages/database/drizzle/0024_misty_lizard.sql +13 -0
- package/template/packages/database/drizzle/0025_premium_songbird.sql +6 -0
- package/template/packages/database/drizzle/0026_aberrant_doctor_octopus.sql +42 -0
- package/template/packages/database/drizzle/0027_tiny_diamondback.sql +5 -0
- package/template/packages/database/drizzle/0028_condemned_ulik.sql +27 -0
- package/template/packages/database/drizzle/0029_clean_nightshade.sql +5 -0
- package/template/packages/database/drizzle/0030_governed_export_constraints.sql +84 -0
- package/template/packages/database/drizzle/meta/0000_snapshot.json +973 -0
- package/template/packages/database/drizzle/meta/0001_snapshot.json +1559 -0
- package/template/packages/database/drizzle/meta/0002_snapshot.json +1911 -0
- package/template/packages/database/drizzle/meta/0003_snapshot.json +2047 -0
- package/template/packages/database/drizzle/meta/0004_snapshot.json +2059 -0
- package/template/packages/database/drizzle/meta/0005_snapshot.json +2084 -0
- package/template/packages/database/drizzle/meta/0006_snapshot.json +3192 -0
- package/template/packages/database/drizzle/meta/0007_snapshot.json +3208 -0
- package/template/packages/database/drizzle/meta/0008_snapshot.json +3367 -0
- package/template/packages/database/drizzle/meta/0009_snapshot.json +3629 -0
- package/template/packages/database/drizzle/meta/0010_snapshot.json +3955 -0
- package/template/packages/database/drizzle/meta/0011_snapshot.json +4299 -0
- package/template/packages/database/drizzle/meta/0012_snapshot.json +4368 -0
- package/template/packages/database/drizzle/meta/0013_snapshot.json +4483 -0
- package/template/packages/database/drizzle/meta/0014_snapshot.json +4489 -0
- package/template/packages/database/drizzle/meta/0015_snapshot.json +4771 -0
- package/template/packages/database/drizzle/meta/0016_snapshot.json +4694 -0
- package/template/packages/database/drizzle/meta/0017_snapshot.json +4731 -0
- package/template/packages/database/drizzle/meta/0018_snapshot.json +4978 -0
- package/template/packages/database/drizzle/meta/0019_snapshot.json +4996 -0
- package/template/packages/database/drizzle/meta/0020_snapshot.json +5140 -0
- package/template/packages/database/drizzle/meta/0021_snapshot.json +5535 -0
- package/template/packages/database/drizzle/meta/0022_snapshot.json +5541 -0
- package/template/packages/database/drizzle/meta/0023_snapshot.json +6667 -0
- package/template/packages/database/drizzle/meta/0024_snapshot.json +6780 -0
- package/template/packages/database/drizzle/meta/0025_snapshot.json +6849 -0
- package/template/packages/database/drizzle/meta/0026_snapshot.json +7185 -0
- package/template/packages/database/drizzle/meta/0027_snapshot.json +7225 -0
- package/template/packages/database/drizzle/meta/0028_snapshot.json +7454 -0
- package/template/packages/database/drizzle/meta/0029_snapshot.json +7460 -0
- package/template/packages/database/drizzle/meta/0030_snapshot.json +7473 -0
- package/template/packages/database/drizzle/meta/_journal.json +223 -0
- package/template/packages/database/index.ts +5 -0
- package/template/packages/database/package.json +17 -0
- package/template/packages/database/src/dialects.test.ts +33 -0
- package/template/packages/database/src/dialects.ts +139 -0
- package/template/packages/database/src/runner.test.ts +96 -0
- package/template/packages/database/src/runner.ts +175 -0
- package/template/packages/database/src/schema/bulk-data.ts +87 -0
- package/template/packages/database/src/schema/common.ts +33 -0
- package/template/packages/database/src/schema/durable-jobs.ts +266 -0
- package/template/packages/database/src/schema/file-storage.ts +94 -0
- package/template/packages/database/src/schema/governance.ts +195 -0
- package/template/packages/database/src/schema/governed-exports.ts +90 -0
- package/template/packages/database/src/schema/identity.ts +169 -0
- package/template/packages/database/src/schema/index.ts +33 -0
- package/template/packages/database/src/schema/license-legacy.ts +93 -0
- package/template/packages/database/src/schema/license-v1.ts +246 -0
- package/template/packages/database/src/schema/migration-history.ts +30 -0
- package/template/packages/database/src/schema/notifications.ts +60 -0
- package/template/packages/database/src/schema/platform-settings.ts +55 -0
- package/template/packages/database/src/schema/scheduler.ts +89 -0
- package/template/packages/database/src/schema/work-orders.ts +23 -0
- package/template/packages/database/src/schema/workflow.ts +86 -0
- package/template/packages/database/src/schema-durable-links.test.ts +27 -0
- package/template/packages/database/src/schema-governed-exports.test.ts +49 -0
- package/template/packages/database/src/schema-workflow-notification.test.ts +63 -0
- package/template/packages/database/src/schema.test.ts +343 -0
- package/template/packages/database/src/sql-store.test.ts +92 -0
- package/template/packages/database/src/sql-store.ts +101 -0
- package/template/packages/database/src/store.ts +32 -0
- package/template/packages/database/tsconfig.json +17 -0
- package/template/packages/example-work-order/index.ts +3 -0
- package/template/packages/example-work-order/package.json +13 -0
- package/template/packages/example-work-order/src/contract.ts +50 -0
- package/template/packages/example-work-order/src/manifest.test.ts +54 -0
- package/template/packages/example-work-order/src/manifest.ts +120 -0
- package/template/packages/example-work-order/src/schema.ts +27 -0
- package/template/packages/license-sdk/index.ts +13 -0
- package/template/packages/license-sdk/package.json +18 -0
- package/template/packages/license-sdk/src/bounded-json-body.test.ts +65 -0
- package/template/packages/license-sdk/src/bounded-json-body.ts +135 -0
- package/template/packages/license-sdk/src/canonical-json.test.ts +28 -0
- package/template/packages/license-sdk/src/canonical-json.ts +104 -0
- package/template/packages/license-sdk/src/client.test.ts +82 -0
- package/template/packages/license-sdk/src/client.ts +86 -0
- package/template/packages/license-sdk/src/device.ts +46 -0
- package/template/packages/license-sdk/src/file-storage.test.ts +80 -0
- package/template/packages/license-sdk/src/file-storage.ts +77 -0
- package/template/packages/license-sdk/src/installation.test.ts +241 -0
- package/template/packages/license-sdk/src/installation.ts +150 -0
- package/template/packages/license-sdk/src/license-parser.ts +56 -0
- package/template/packages/license-sdk/src/offline-code-base32.ts +57 -0
- package/template/packages/license-sdk/src/offline-code-decompression.ts +55 -0
- package/template/packages/license-sdk/src/offline-code-limits.ts +10 -0
- package/template/packages/license-sdk/src/offline-code-wire.ts +72 -0
- package/template/packages/license-sdk/src/offline-code.test.ts +172 -0
- package/template/packages/license-sdk/src/offline-code.ts +319 -0
- package/template/packages/license-sdk/src/payload.test.ts +72 -0
- package/template/packages/license-sdk/src/payload.ts +201 -0
- package/template/packages/license-sdk/src/storage.ts +64 -0
- package/template/packages/license-sdk/src/test-fixtures.ts +59 -0
- package/template/packages/license-sdk/src/v1-test-vector.ts +49 -0
- package/template/packages/license-sdk/src/validation.test.ts +62 -0
- package/template/packages/license-sdk/src/validation.ts +143 -0
- package/template/packages/license-sdk/src/verification.test.ts +97 -0
- package/template/packages/license-sdk/src/verification.ts +199 -0
- package/template/packages/license-sdk/tsconfig.json +17 -0
- package/template/packages/modules/index.ts +8 -0
- package/template/packages/modules/package.json +13 -0
- package/template/packages/modules/src/composition.test.ts +267 -0
- package/template/packages/modules/src/composition.ts +342 -0
- package/template/packages/modules/src/installed-business-modules.ts +10 -0
- package/template/packages/modules/src/manifest.ts +97 -0
- package/template/packages/modules/src/menu-composition.test.ts +64 -0
- package/template/packages/modules/src/menu-composition.ts +54 -0
- package/template/packages/modules/src/registry.ts +53 -0
- package/template/packages/modules/src/system-admin-routes.ts +134 -0
- package/template/packages/modules/src/system-agent-tools.ts +28 -0
- package/template/packages/modules/src/system-api-binding.ts +37 -0
- package/template/packages/modules/src/system-api-data-governance.ts +21 -0
- package/template/packages/modules/src/system-api-permissions.ts +344 -0
- package/template/packages/modules/src/system-audit-actions.ts +70 -0
- package/template/packages/modules/src/system-data-governance.ts +30 -0
- package/template/packages/modules/src/system-features.ts +143 -0
- package/template/packages/modules/src/system-governed-export-bindings.ts +31 -0
- package/template/packages/modules/src/system-module-catalog.test.ts +145 -0
- package/template/packages/modules/src/system-module-catalog.ts +250 -0
- package/template/packages/modules/src/system-modules.test.ts +344 -0
- package/template/packages/modules/src/system-modules.ts +335 -0
- package/template/packages/modules/src/system-permissions.ts +142 -0
- package/template/packages/modules/user/module.ts +72 -0
- package/template/packages/shared/index.ts +16 -0
- package/template/packages/shared/package.json +9 -0
- package/template/packages/shared/src/audit.test.ts +17 -0
- package/template/packages/shared/src/audit.ts +237 -0
- package/template/packages/shared/src/correlation.test.ts +10 -0
- package/template/packages/shared/src/correlation.ts +11 -0
- package/template/packages/shared/src/data-governance.test.ts +44 -0
- package/template/packages/shared/src/data-governance.ts +89 -0
- package/template/packages/shared/src/database.ts +67 -0
- package/template/packages/shared/src/feature.test.ts +54 -0
- package/template/packages/shared/src/feature.ts +104 -0
- package/template/packages/shared/src/license-legacy.ts +153 -0
- package/template/packages/shared/src/license.test.ts +63 -0
- package/template/packages/shared/src/license.ts +267 -0
- package/template/packages/shared/src/module-configuration.ts +50 -0
- package/template/packages/shared/src/notification.ts +46 -0
- package/template/packages/shared/src/platform-settings.ts +5 -0
- package/template/packages/shared/src/primitives.ts +47 -0
- package/template/packages/shared/src/profile.ts +13 -0
- package/template/packages/shared/src/rbac.ts +117 -0
- package/template/packages/shared/src/ruoyi.ts +98 -0
- package/template/packages/shared/src/scheduler.ts +108 -0
- package/template/packages/shared/src/search-provider.ts +24 -0
- package/template/packages/shared/src/workflow.test.ts +225 -0
- package/template/packages/shared/src/workflow.ts +307 -0
- package/template/packages/storage/index.ts +11 -0
- package/template/packages/storage/package.json +12 -0
- package/template/packages/storage/src/blob-store.ts +64 -0
- package/template/packages/storage/src/content-hash.ts +24 -0
- package/template/packages/storage/src/file-service.test.ts +100 -0
- package/template/packages/storage/src/file-service.ts +59 -0
- package/template/packages/storage/src/in-memory-upload-repository.ts +154 -0
- package/template/packages/storage/src/local-file-blob-store.test.ts +175 -0
- package/template/packages/storage/src/local-file-blob-store.ts +344 -0
- package/template/packages/storage/src/local-file-maintenance.ts +133 -0
- package/template/packages/storage/src/memory-blob-store.test.ts +16 -0
- package/template/packages/storage/src/memory-blob-store.ts +100 -0
- package/template/packages/storage/src/upload-repository.ts +43 -0
- package/template/packages/storage/src/upload-service.test.ts +246 -0
- package/template/packages/storage/src/upload-service.ts +334 -0
- package/template/packages/storage/src/upload-streams.ts +123 -0
- package/template/packages/storage/src/upload-types.ts +110 -0
- package/template/packages/storage/tsconfig.json +16 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# 批量导入导出后台任务
|
|
2
|
+
|
|
3
|
+
## V1 范围
|
|
4
|
+
|
|
5
|
+
DATA-01 先用 canonical `dictionaries`(字典)资源完成一个真实纵向切片,同时把任务、artifact、资源处理器和路由 Guard 做成可扩展边界。V1 支持:
|
|
6
|
+
|
|
7
|
+
- 字典 NDJSON 后台导入,`create` 与 `upsert` 两种模式;
|
|
8
|
+
- 字典 NDJSON 后台导出;
|
|
9
|
+
- PostgreSQL 持久化任务状态、进度、重试和文件内容;
|
|
10
|
+
- 逐行失败明细、导入汇总和导出结果下载;
|
|
11
|
+
- 到期 artifact 自动清理,任务元数据和审计继续保留。
|
|
12
|
+
|
|
13
|
+
原有小数据同步 JSON API 继续保留,但 Web 字典页已切换到本章的后台 NDJSON 工作流,不再展示同步 JSON 导入导出按钮。其它系统资源页面仍使用原有小数据入口。用户、角色、菜单等资源尚未注册为批量处理器,不能只改请求中的 `resource` 绕过 V1 白名单。
|
|
14
|
+
|
|
15
|
+
## NDJSON 契约与边界
|
|
16
|
+
|
|
17
|
+
导入采用 UTF-8 NDJSON,每一个非空逻辑行是一条完整字典记录。空行被忽略,失败明细中的 `line` 是非空逻辑行序号。每行至少包含稳定的 `id`、`code`、`name`:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"id": "dict_order_status",
|
|
22
|
+
"code": "order_status",
|
|
23
|
+
"name": "订单状态",
|
|
24
|
+
"status": "active",
|
|
25
|
+
"items": [
|
|
26
|
+
{ "label": "待处理", "value": "pending", "status": "active", "order": 10 }
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
约束如下:
|
|
32
|
+
|
|
33
|
+
- `id`:1-64 位字母、数字、点、横线或下划线;重试时用它定位同一实体,禁止省略或临时生成;
|
|
34
|
+
- `code`:1-80 位字母、数字、点、横线或下划线;
|
|
35
|
+
- `name`:非空字符串;
|
|
36
|
+
- `status`:`active`、`disabled` 或 `archived`,省略时为 `active`;
|
|
37
|
+
- `items`:数组;每项包含非空 `label`、`value`、合法 `status` 和非负整数 `order`。
|
|
38
|
+
|
|
39
|
+
V1 固定安全边界:单次输入最多 10 MiB、50,000 个非空逻辑行,单行最多 256 KiB。API 当前接收 JSON body 中的 `content` 字符串,不是无限流式上传;超过任一边界返回 `413`,不会创建任务。
|
|
40
|
+
|
|
41
|
+
逐行失败文件也是 NDJSON,每行结构为:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"line": 2,
|
|
46
|
+
"code": "INVALID_ROW",
|
|
47
|
+
"message": "id 仅允许 1-64 位字母、数字、点、横线或下划线",
|
|
48
|
+
"inputDigest": "<sha256>"
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
`code` 可能是 `INVALID_JSON`、`INVALID_ROW` 或 `IMPORT_FAILED`。失败文件不回显原始输入行,只保留行号、稳定错误分类、安全消息和输入行 SHA-256,避免把潜在敏感内容复制到错误报告。格式/业务行错误只影响该行;数据库不可用等系统性错误终止本次尝试并进入任务重试。
|
|
53
|
+
|
|
54
|
+
## 幂等与重试
|
|
55
|
+
|
|
56
|
+
调用方必须提供 8-160 位的 `idempotencyKey`。唯一作用域是:
|
|
57
|
+
|
|
58
|
+
```text
|
|
59
|
+
requestedBy + kind(import/export) + resource + idempotencyKey
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
同一作用域、同一输入摘要重复提交返回原任务,不会重复排队;同一作用域复用到不同输入返回 `409 IDEMPOTENCY_CONFLICT`。不同用户、导入/导出或不同资源可安全使用相同文本键。导出请求的幂等键会固定到原任务及其结果;需要导出最新数据时必须使用新键。
|
|
63
|
+
|
|
64
|
+
导入要求每行有稳定 `id`。`create` 模式在目标 ID 已存在时按现有 Repository 语义跳过;`upsert` 模式重放同一行会更新同一实体。因此进程在部分提交后发生系统错误,整份 NDJSON 重试也不会生成重复 ID。
|
|
65
|
+
|
|
66
|
+
任务最多尝试 3 次,系统性失败默认 30 秒后重试。每次领取在 PostgreSQL 中递增 `attempt`,状态为:
|
|
67
|
+
|
|
68
|
+
- `queued`:等待执行;
|
|
69
|
+
- `running`:已原子领取;
|
|
70
|
+
- `retry-pending`:系统性失败,等待下次尝试;
|
|
71
|
+
- `succeeded`:全部成功;
|
|
72
|
+
- `completed-with-errors`:任务完成但存在行级失败;
|
|
73
|
+
- `failed`:达到最大尝试次数。
|
|
74
|
+
|
|
75
|
+
每处理 100 行持久化一次中间进度;任务完成时保存最终 `processedRows`、`succeededRows`、`failedRows`。PostgreSQL 使用 `FOR UPDATE SKIP LOCKED` 领取任务,多个 Server 实例不会领取同一 job。
|
|
76
|
+
|
|
77
|
+
## 复用 OPS-02
|
|
78
|
+
|
|
79
|
+
DATA-01 没有新增 timer 或通用调度核心,而是向 OPS-02 注册两个代码任务:
|
|
80
|
+
|
|
81
|
+
- `system.bulk-data.dispatch`:每 5 秒领取并执行一个排队或到期重试的 job;
|
|
82
|
+
- `system.bulk-data.cleanup`:每小时清理到期 artifact。
|
|
83
|
+
|
|
84
|
+
因此 Worker 防 tick 重入、定时任务单 `running`、执行历史、手动触发、动态 Feature、Entitlement、RBAC 和审计都复用 OPS-02。DATA-01 的 job 状态用于描述一份业务数据文件,OPS-02 的 run 状态用于描述一次派发/清理 handler 执行,两个层次不互相冒充。
|
|
85
|
+
|
|
86
|
+
进程在 scheduler handler 内直接崩溃时,OPS-04 允许运维确认后把 stale 调度 run 终结为 `blocked`,但该动作只释放 OPS-02 的调度占用,不会修改、重跑或补偿 DATA-01 的批量 job。批量 job 自身若已被置为 `running`,仍不会被另一个派发自动抢占;操作员必须先检查已处理行和外部副作用,再按独立的业务处置流程处理。在没有 lease/heartbeat 之前,这是防止重复写入的 fail-closed 取舍。
|
|
87
|
+
|
|
88
|
+
## Guard 与审计
|
|
89
|
+
|
|
90
|
+
`system.bulk-data` 是代码注册 Feature,要求 `capability.scheduler` Entitlement。Guard 顺序固定为:
|
|
91
|
+
|
|
92
|
+
1. License 限制模式;
|
|
93
|
+
2. Entitlement;
|
|
94
|
+
3. 数据库动态 `system.bulk-data` Feature;
|
|
95
|
+
4. RBAC;
|
|
96
|
+
5. 成功动作审计。
|
|
97
|
+
|
|
98
|
+
到期限制不会被管理员、调度身份或下载接口绕过。导入创建要求 `system.dict.manage`,导出创建、本人任务查询和 artifact 下载要求 `system.dict.read`;调度执行身份要求 `system.bulk-data.manage`。申请人只能读取和下载自己的任务,不能猜测 job ID 读取他人的结果。
|
|
99
|
+
|
|
100
|
+
审计动作包括 `data.bulk-import.create`、`data.bulk-export.create` 和 `data.bulk-artifact.download`;OPS-02 对人工触发、真实执行、失败和拒绝记录 `task.trigger` / `task.execute`。定时派发没有领取到任务时属于 idle,不写执行历史或审计,避免 5 秒轮询淹没业务事件。审计只保存任务 ID、数量、artifact 类型和摘要,不保存 NDJSON 内容。
|
|
101
|
+
|
|
102
|
+
## API
|
|
103
|
+
|
|
104
|
+
- `POST /api/system/bulk-data/dictionaries/import`
|
|
105
|
+
- body:`{"idempotencyKey":"...","mode":"create|upsert","content":"<NDJSON>"}`;
|
|
106
|
+
- 新建返回 `202`,幂等命中返回 `200`。
|
|
107
|
+
- `POST /api/system/bulk-data/dictionaries/export`
|
|
108
|
+
- body:`{"idempotencyKey":"..."}`;
|
|
109
|
+
- 新建返回 `202`,幂等命中返回 `200`。
|
|
110
|
+
- `GET /api/system/bulk-data/jobs?limit=50`:查询本人最近任务;
|
|
111
|
+
- `GET /api/system/bulk-data/jobs/:id`:查询本人任务及进度;
|
|
112
|
+
- `GET /api/system/bulk-data/jobs/:id/artifacts/result`:下载导出结果或导入汇总;
|
|
113
|
+
- `GET /api/system/bulk-data/jobs/:id/artifacts/failures`:下载行级失败 NDJSON。
|
|
114
|
+
|
|
115
|
+
## Web 字典页闭环
|
|
116
|
+
|
|
117
|
+
`/system/dictionaries` 继续复用 `SystemResourcePage` 完成字典 CRUD,批量数据部分由独立组件和 composable 组合:
|
|
118
|
+
|
|
119
|
+
- `DictionaryBulkActions` 只负责用户可理解的导入/导出输入;幂等键是浏览器自动生成的 opaque retry token,不作为普通业务字段要求用户手填;
|
|
120
|
+
- `DictionaryBulkJobList` 只展示 Server 返回的当前登录用户任务,包含状态、进度、尝试次数和下次重试时间;页面没有任意 job ID 输入框;
|
|
121
|
+
- `DictionaryBulkJobDetail` 只展示所选本人任务的安全元数据,并在终态提供 `result` / `failures` 下载;失败明细内容不在页面回显;
|
|
122
|
+
- `useDictionaryBulkJobs` 统一处理加载、提交、选中、下载和错误状态;存在非终态任务时每 5 秒刷新一次,也可手动刷新;
|
|
123
|
+
- `services/bulk-data-api.ts` 复用统一认证 HTTP 客户端;artifact 下载保留 Server 返回的原始 `Response`、文件名和内容类型,不另建绕过会话或 Guard 的下载通道。
|
|
124
|
+
|
|
125
|
+
浏览器在提交前先检查 10 MiB、50,000 个非空逻辑行和 256 KiB 单行限制;Server 仍是最终校验权威。客户端为一次操作生成幂等键:请求失败或响应丢失时重试复用原键,Server 返回成功后才为下一次操作生成新键。任务详情把该键收纳在“技术信息”中只读展示,便于排障但不让普通用户承担协议字段。
|
|
126
|
+
|
|
127
|
+
错误提示按 API 语义区分:
|
|
128
|
+
|
|
129
|
+
- `401`:会话失效,统一认证客户端同时触发登录导航;
|
|
130
|
+
- `missing-permission` / `role-not-allowed`:RBAC 权限不足;
|
|
131
|
+
- `license-restricted` / `entitlement-not-granted`:License 受限或未授权后台任务;
|
|
132
|
+
- `feature-disabled`:`system.bulk-data` Feature Flag 已关闭;
|
|
133
|
+
- 输入上限、幂等冲突或其它请求错误:保留 Server 的安全错误说明。
|
|
134
|
+
|
|
135
|
+
Web 不增加其它资源的伪入口,也不改变 DATA-01 的 PostgreSQL 模型、`0011` migration、本人任务隔离、License → Entitlement → Feature → RBAC Guard 顺序或审计策略。
|
|
136
|
+
|
|
137
|
+
## 留存和存储取舍
|
|
138
|
+
|
|
139
|
+
source、result、failures artifact 默认从各自创建时间保留 7 天,可用 `BULK_DATA_RETENTION_DAYS` 调整为正整数天。清理任务只删除 `succeeded`、`completed-with-errors` 或 `failed` 终态 job 的到期 artifact,不会删除仍在排队、运行或等待重试的 source。任务元数据不随 artifact 清理,下载到期文件返回 404。
|
|
140
|
+
|
|
141
|
+
V1 把 artifact 文本和 SHA-256 一起保存在 PostgreSQL `text` 列。这保证生产状态只有一个权威来源,并避免多副本共享本地目录,但只适用于上述 10 MiB / 50,000 行明确上限,不代表 PostgreSQL 适合无限大文件。后续若提升容量,应实现保持 `BulkDataRepository` 契约的对象存储 Adapter,并把 PostgreSQL 继续作为任务、权限和 artifact 元数据权威;不能直接扩大限制而把数据库当通用对象存储。
|
|
142
|
+
|
|
143
|
+
无 PostgreSQL 时只使用进程内 Repository,限开发和测试,重启即丢失。生产必须配置 PostgreSQL 并执行到包含 `bulk_data_jobs`、`bulk_data_artifacts` 的最新 migration。本功能不访问国产数据库,也不向 RuoYi 旧库或旧 Redis 写入。
|
|
144
|
+
|
|
145
|
+
## 运维验证
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
bun run db:migrate
|
|
149
|
+
bun run test:db:migrations
|
|
150
|
+
bun run typecheck
|
|
151
|
+
bun test
|
|
152
|
+
bun run lint
|
|
153
|
+
bun run build
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
真实 PostgreSQL Repository 测试需要提供 `BULK_DATA_TEST_DATABASE_URL`,覆盖并发幂等创建、`SKIP LOCKED` 单领取、进度/终态、进程重建后的到期重试和 artifact 清理。
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# 数据访问范围
|
|
2
|
+
|
|
3
|
+
## 目标与边界
|
|
4
|
+
|
|
5
|
+
Windy V1 是单组织、单租户、私有部署优先的 Starter。RBAC Permission 决定 Actor 能否调用一种能力;数据访问范围进一步决定该 Actor 能读取或修改哪些记录。页面隐藏不构成授权,Server 必须在分页、导出和按 ID 写入之前执行同一套范围规则。
|
|
6
|
+
|
|
7
|
+
当前验收资源是系统用户。后续业务模块可复用同一服务,但必须显式声明资源归属;没有 `ownerId` 或 `departmentId` 的资源不得假装自动支持部门范围。
|
|
8
|
+
|
|
9
|
+
## 类型化上下文
|
|
10
|
+
|
|
11
|
+
Actor Resolver 从用户主部门和全部启用角色构造 `DataAccessContext`:
|
|
12
|
+
|
|
13
|
+
- `tenantId`:V1 固定为 `single-tenant`,不代表已经具备多租户隔离;
|
|
14
|
+
- `actorId`:当前用户 ID,用于 `self`;
|
|
15
|
+
- `departmentId`:当前用户唯一主部门;
|
|
16
|
+
- `roleIds`:参与本次判定的启用角色;
|
|
17
|
+
- `grants`:由角色策略转换后的类型化范围集合。
|
|
18
|
+
|
|
19
|
+
支持的范围如下:
|
|
20
|
+
|
|
21
|
+
| 范围 | 用户资源含义 |
|
|
22
|
+
| ------------------------- | ---------------------------------------------------------------- |
|
|
23
|
+
| `all` | 当前平台全部用户 |
|
|
24
|
+
| `tenant` | V1 单租户内全部用户,当前与 `all` 的结果相同,但保留不同业务语义 |
|
|
25
|
+
| `department` | 当前 Actor 主部门用户 |
|
|
26
|
+
| `department-and-children` | 当前主部门及全部下级部门用户 |
|
|
27
|
+
| `self` | 当前 Actor 自己的用户记录 |
|
|
28
|
+
| `custom` | 角色配置的指定部门用户 |
|
|
29
|
+
|
|
30
|
+
多个角色按可访问记录并集合并。停用角色不参与上下文;不能用字符串拼接或页面配置临时推导范围。
|
|
31
|
+
|
|
32
|
+
## Server 强制点
|
|
33
|
+
|
|
34
|
+
`DataScopedResourceService` 组合资源 Repository、归属映射和部门后代解析器。用户资源映射为 `{ ownerId: user.id, departmentId: user.departmentId }`,并统一约束:
|
|
35
|
+
|
|
36
|
+
- `list`、`count`、搜索和分页;
|
|
37
|
+
- `all` 与同步导出;
|
|
38
|
+
- `get-by-id`;
|
|
39
|
+
- `create`;
|
|
40
|
+
- `update`,同时校验原记录和更新后的归属,禁止把可管理记录移动到无权部门;
|
|
41
|
+
- `softDelete`;
|
|
42
|
+
- 模块选择开放时的受控导入。
|
|
43
|
+
|
|
44
|
+
越权直接 ID 不伪装成成功,也不依赖前端列表是否曾展示该记录;Server 返回 403 和稳定原因 `data-scope-denied`。开发管理员的 `super-admin` 回退仅存在于显式非生产开发通道,真实数据库 Actor 使用角色生成的上下文。
|
|
45
|
+
|
|
46
|
+
## 业务模块接入
|
|
47
|
+
|
|
48
|
+
业务模块接入数据范围时至少完成以下步骤:
|
|
49
|
+
|
|
50
|
+
1. 在领域模型中明确 `ownerId`、`departmentId` 或该模块自己的可解释归属;
|
|
51
|
+
2. 使用 `DataScopedResourceService`,或实现相同 `ScopedResourceAccess` 契约;
|
|
52
|
+
3. 菜单、页面、按钮和 API 仍注册同一 Module Manifest Feature / Permission Key;数据范围不能替代 RBAC Guard;
|
|
53
|
+
4. list、count、export、Agent Tool、直接 ID 读取和所有写入复用同一范围规范;需要继承申请人范围的后台任务必须保存不可篡改的 context snapshot,平台全量任务则必须显式使用 Server 构造的 nominal `all` context;
|
|
54
|
+
5. 测试至少覆盖全部范围、多角色并集、搜索分页、导出、跨部门直接 ID、归属移动、停用角色与组织结构变化。
|
|
55
|
+
|
|
56
|
+
工单等业务模块可把 `{ ownerId: ticket.createdBy, departmentId: ticket.departmentId }` 作为映射复用当前服务,不需要复制用户模块的条件判断。
|
|
57
|
+
|
|
58
|
+
## 性能与部署取舍
|
|
59
|
+
|
|
60
|
+
用户和 Work Order 已把类型化范围规范编译为 Drizzle Query Specification,在 PostgreSQL 中完成谓词、count 和分页下推。`DataScopedResourceService` 不在内存中裁剪生产候选集;它只接受 scoped Repository,并把 Server context 编译后传入 Repository。
|
|
61
|
+
|
|
62
|
+
同步导出与 Agent Tool 使用相同 scoped access。通用资源必须显式声明 `request` 或 `platform` 访问模式,不能因配置缺失静默走裸 Repository。V1 bulk handler 只允许平台资源;如果未来增加请求级异步导出,必须先持久化并验证不可篡改的 context snapshot,不能把客户端范围参数或 scope-less Actor 放进队列。
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# 类型化模块配置与 Secret 边界
|
|
2
|
+
|
|
3
|
+
更新时间:2026-07-16。
|
|
4
|
+
|
|
5
|
+
## 目标与边界
|
|
6
|
+
|
|
7
|
+
平台配置不是任意 Key-Value 存储。每个可配置模块必须先注册 `ModuleConfigDefinition<T>`,声明稳定模块 Key、严格 Zod schema、允许的环境变量、逻辑字段路径、默认值和 Secret 属性。未注册字段不能通过环境变量、API 或数据库临时增加。
|
|
8
|
+
|
|
9
|
+
当前首批定义只有:
|
|
10
|
+
|
|
11
|
+
- `platform.runtime`:平台名称、数据库方言、平台 Redis、Session、License 公钥元数据、审计和 RuoYi 只读兼容开关;
|
|
12
|
+
- `license.signing-service`:loopback 地址、端口、Vault 地址与 mount、速率限制、签名 key 白名单,以及签名服务 Bearer Token/Vault Token 的受保护文件引用。
|
|
13
|
+
|
|
14
|
+
配置版本治理只允许消费同一 Registry,不能新增一张绕过 Definition 的通用 KV 表。
|
|
15
|
+
|
|
16
|
+
## 启动加载契约
|
|
17
|
+
|
|
18
|
+
`ModuleConfigDefinition` 同时定义字段类型和它负责的环境变量命名空间。严格 Loader 在业务服务开始监听前执行:
|
|
19
|
+
|
|
20
|
+
1. Definition 所属命名空间出现未知环境变量时,返回 `CONFIG_UNKNOWN_ENV`;
|
|
21
|
+
2. 布尔值只接受 `true/false/1/0`,整数必须是安全整数,Zod schema 继续检查枚举、范围、URL 和严格对象结构;
|
|
22
|
+
3. 必填 Secret 没有引用时返回 `CONFIG_SECRET_REQUIRED`;
|
|
23
|
+
4. Resolver 无法读取 Secret 时返回 `CONFIG_SECRET_UNAVAILABLE`;
|
|
24
|
+
5. 错误只包含模块 Key 与逻辑字段路径,不回显输入值、Secret、环境变量内容或文件路径。
|
|
25
|
+
|
|
26
|
+
unknown 检查只作用于 Definition 明确拥有的 prefix 或 exact key,避免把操作系统、Bun、测试工具或其它服务环境变量误判为平台配置。
|
|
27
|
+
|
|
28
|
+
## SecretRef 与 SecretResolver
|
|
29
|
+
|
|
30
|
+
Secret 配置分成引用和运行时值两层:
|
|
31
|
+
|
|
32
|
+
- env Secret 的 `SecretRef` 只指向环境变量名,Registry 不保存数据库/Redis URL;
|
|
33
|
+
- file Secret 的 `SecretRef` 只指向受保护文件,签名服务通过 `ProtectedFileSecretResolver` 检查普通文件、Unix `0600` 权限和非空内容;
|
|
34
|
+
- `SecretRef` 的 locator 使用私有字段,不可枚举,`JSON.stringify` 会省略该对象,普通 `String()` 只得到 `[SecretRef]`;
|
|
35
|
+
- Registry 的公开描述只返回逻辑字段路径、是否 Secret、是否必填,不返回 env key、文件路径、引用 locator 或有效值;
|
|
36
|
+
- 解析后的 Secret 只能进入进程内的 typed runtime config,禁止交给普通 API、结构化日志、审计 metadata 或配置 diff。
|
|
37
|
+
|
|
38
|
+
平台 Server 在创建数据库连接、初始化审计恢复和监听端口前加载 `platform.runtime`。数据库、平台 Redis、RuoYi 连接和机器码通过 env Resolver 解析;Server 的 foundation 快照只投影名称、Feature 等非敏感字段。独立签名服务在连接 Vault 和监听端口前加载 `license.signing-service`,Bearer/Vault Token 只经受保护文件 Resolver 进入对应客户端。
|
|
39
|
+
|
|
40
|
+
## 新模块接入规则
|
|
41
|
+
|
|
42
|
+
新增配置模块时必须:
|
|
43
|
+
|
|
44
|
+
1. 使用 `defineModuleConfig` 和 `z.strictObject` 定义类型;
|
|
45
|
+
2. 为每个 env source 指定唯一逻辑路径,声明自己拥有的 prefix/exact key;
|
|
46
|
+
3. Secret 字段只能声明 Provider 和是否必填,不能把默认 Secret 或明文值写入 Definition;
|
|
47
|
+
4. 注册重复、未知 env、错误类型、缺失/不可读 Secret、JSON/日志无泄露必须有单元测试;
|
|
48
|
+
5. 若需要动态修改,必须接入 C2 的版本、apply、rollback、RBAC、Feature 和审计链路,不能自行写数据库或创建旁路 API。
|
|
49
|
+
|
|
50
|
+
## 版本治理与运行时应用
|
|
51
|
+
|
|
52
|
+
`module_config_versions` 保存不可变的模块配置版本,而不是平台通用 KV。每行包含模块 Key、连续版本号、已注册非敏感字段值、字段级 diff、应用状态、稳定错误、变更原因、操作者和可选回滚来源。状态固定为:
|
|
53
|
+
|
|
54
|
+
- `applying`:版本已入库,正在调用模块 Apply Adapter;
|
|
55
|
+
- `effective`:当前生效版本,同模块同时只能有一个;
|
|
56
|
+
- `failed`:schema 已通过但运行时应用失败,稳定错误不包含底层异常正文;
|
|
57
|
+
- `superseded`:曾经生效,已被后续版本替代。
|
|
58
|
+
|
|
59
|
+
版本号由 PostgreSQL transaction 内的 module-key advisory lock 分配,唯一索引继续提供最终并发保护。应用成功后,Repository 在事务内把旧 `effective` 标为 `superseded` 并把新版本标为 `effective`;应用失败只标记新版本为 `failed`,原生效版本不变。Server 启动时先读取每个已注册模块的生效版本并通过同一 schema 与 Apply Adapter 恢复,再建立 foundation 和探活运行时。
|
|
60
|
+
|
|
61
|
+
当前首批允许动态管理的 `platform.runtime` 字段只有:
|
|
62
|
+
|
|
63
|
+
- `enableAI`:更新 foundation 平台能力投影;
|
|
64
|
+
- `cache.healthTimeoutMs`:后续 Redis 探活按最新值创建 probe。
|
|
65
|
+
|
|
66
|
+
数据库、Redis URL、Session、License 机器码、签名 Token 和 Vault Token 等 Secret 或引用均不进入版本表、diff、普通 API、管理界面或审计 metadata。
|
|
67
|
+
|
|
68
|
+
## 回滚、权限与审计
|
|
69
|
+
|
|
70
|
+
回滚从不改写历史行。`POST /api/system/configurations/:moduleKey/versions/:version/rollback` 复制目标版本的已注册值,要求 8 至 500 字原因,并按正常 apply 流程创建一个带 `rollbackOfVersion` 的新版本。
|
|
71
|
+
|
|
72
|
+
配置读取要求 `system.config.read`,创建版本和回滚要求 `system.config.manage`;菜单、Web Router 和所有四个 API 绑定统一引用 `system.config` Feature 与 System Module Manifest。mutation 在改配置前先写 `critical` intent 审计,审计不可持久化或进入恢复队列时返回 `503 AUDIT_UNAVAILABLE` 且不创建版本。结果审计只记录 module Key、版本、状态、回滚来源和 changed paths,不记录 before/after 值、请求值、Secret 或 `SecretRef`。
|
|
73
|
+
|
|
74
|
+
管理端 `/system/configurations` 只根据服务端字段描述生成编辑表单,显示环境/版本来源、生效版本、diff、失败状态和历史;回滚必须经过带原因的显式确认。编辑值或原因未保存时,路由离开和刷新分别使用应用 Dialog 与原生 `beforeunload` 保护,保存失败会保留当前输入。
|
|
75
|
+
|
|
76
|
+
## 运维与验证
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
bun run test:db:migrations
|
|
80
|
+
bun run test:db:config
|
|
81
|
+
bun test apps/server/src/configuration packages/modules/src/system-modules.test.ts
|
|
82
|
+
bun run --cwd apps/web test -- ModuleConfigurationEditor.webtest.ts router/index.webtest.ts
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
`test:db:migrations` 在 fresh PostgreSQL 17 上执行全部正式 migration 并二次执行验证 tracker 指纹不变;`test:db:config` 使用真实 PostgreSQL 验证并发版本分配、生效替代、失败状态、Repository 重建后的恢复、回滚新版本和 Secret marker 不落库。
|
|
86
|
+
|
|
87
|
+
## 验证
|
|
88
|
+
|
|
89
|
+
定向验证:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
bun test packages/config/index.test.ts apps/signing-service/src/config.test.ts
|
|
93
|
+
bun test apps/server/src/configuration
|
|
94
|
+
bun run --cwd apps/server typecheck
|
|
95
|
+
bun run --cwd apps/signing-service typecheck
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
测试使用明显 marker 证明错误、Registry 描述和 JSON 序列化不包含 Secret 值或文件引用。签名测试使用临时 `0600` 文件并在结束后清理,不写入仓库。
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Manifest 菜单注册与导航结构
|
|
2
|
+
|
|
3
|
+
## 权威边界
|
|
4
|
+
|
|
5
|
+
Module Manifest 是菜单身份、标题、类型、路由、图标、Feature Key 和 Permission Key 的唯一权威。数据库 `menus` 表不允许创建未注册页面,也不允许改写路由;它只保存管理员可调整的结构状态:
|
|
6
|
+
|
|
7
|
+
- `parent_key`:上级目录;
|
|
8
|
+
- `order`:同级顺序,以 10 为步长归一化;
|
|
9
|
+
- `visible`:Sidebar 显隐。
|
|
10
|
+
|
|
11
|
+
服务启动时 `ManifestMenuRegistry` 执行兼容同步:新增 Manifest 菜单,刷新受代码管理的元数据,保留合法的父级、顺序和显隐,并软删除已取消注册、旧水印入口或 `type=button` 的历史行。个人设置仍通过右上角头像进入,不会作为 Sidebar 菜单;全局设置的真实路由固定为 `/settings`,Sidebar 将它放在底部。
|
|
12
|
+
|
|
13
|
+
## 管理行为
|
|
14
|
+
|
|
15
|
+
`/system/menus` 是专用导航结构页,不再暴露通用新增、导入、任意编辑和删除操作。具备 `system.menu.manage` 的用户可以:
|
|
16
|
+
|
|
17
|
+
- 将菜单移到根级或另一个目录;
|
|
18
|
+
- 在当前同级上移、下移;
|
|
19
|
+
- 控制是否显示在 Sidebar。
|
|
20
|
+
|
|
21
|
+
服务端拒绝不存在的父级、非目录父级、自引用,以及把目录放入自身后代形成的循环。成功调整写入 `menu.structure.update` 审计事件。`GET /api/foundation` 每次从注册表构建菜单树,因此调整后刷新授权快照即可影响真实 Sidebar。
|
|
22
|
+
|
|
23
|
+
## API
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
GET /api/system/menus
|
|
27
|
+
GET /api/system/menus/:id
|
|
28
|
+
GET /api/system/menus/export
|
|
29
|
+
PUT /api/system/menus/:id/placement
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`placement` 请求体支持 `parentKey`(`null` 表示根级)、`direction`(`up` 或 `down`)和 `visible`。所有入口继续经过 `system.rbac` Feature 与 `system.menu.read/manage` RBAC Guard。
|
|
33
|
+
|
|
34
|
+
## 扩展约束
|
|
35
|
+
|
|
36
|
+
新增页面时先在所属 Module Manifest 用同一能力 Key 注册 Feature、权限、菜单和 API 绑定,再新增 Router 页面。Router 契约测试会比较所有 `type=menu` 的 Manifest 路径与 Web 路由,避免出现“菜单有入口但页面不存在”或“页面绕过注册表”的漂移。
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# 站内通知设计
|
|
2
|
+
|
|
3
|
+
## 产品行为
|
|
4
|
+
|
|
5
|
+
通知管理页 `/system/notifications` 提供广播发布与历史管理。当前一条通知发布后,会进入所有同时具备 `system.notification.read` 权限且 `system.notification` Feature 可用的用户收件箱。Header 点击通知后打开完整正文,并为当前用户写入跨设备共享的已读回执。
|
|
6
|
+
|
|
7
|
+
管理页通过页头的“发布新通知”按钮打开发布对话框,避免让常驻表单挤占历史列表。发布过程必须显式提交、点击取消或关闭按钮;点击遮罩层不会误关对话框和丢失已填写内容。对话框遵循全局布局约束:设置适合表单的最小高度且不超过当前屏幕,只有 Body 区域滚动,标题与底部操作始终可见。发布成功后对话框自动关闭并清空表单。
|
|
8
|
+
|
|
9
|
+
管理列表与用户收件箱共享平台分页契约:默认每页 10 条,服务端上限 100;管理页允许输入范围内任意正整数页大小,并按跨页连续序号展示通知。已发布通知的刷新操作固定在列表右上角,仅显示刷新图标,通过立即出现的组件库 Tooltip 和 `aria-label` 提供名称;加载期间图标旋转且按钮不可重复提交。
|
|
10
|
+
|
|
11
|
+
通知管理页的人工发布范围仍是全体授权用户,不能通过普通发布 API 伪造定向受众。平台业务端口可以创建受控的用户或角色通知,并携带通用 `TargetRef` 业务目标;当前仅最小审批工作流接入。业务通知使用稳定 `sourceKey` 去重,收件箱查询和已读写入都按当前 Actor 的用户 ID 与角色集合执行最终可见性校验。
|
|
12
|
+
|
|
13
|
+
组织范围、管理端定向/定时发布、用户偏好、策略化合并,以及邮件、短信、企业微信等渠道 Adapter 仍属于 P1,不在现有广播管理页或审批接入中伪装支持。
|
|
14
|
+
|
|
15
|
+
## 生命周期与数据
|
|
16
|
+
|
|
17
|
+
- `platform_notifications` 保存标题、摘要、正文、分类、发布时间和审计字段;业务端口还可写入可选 TargetRef、用户/角色受众和唯一 source key。
|
|
18
|
+
- `notification_reads` 以“通知 ID + 用户 ID”为复合主键保存已读时间,重复点击幂等。
|
|
19
|
+
- 管理操作使用归档而不是物理删除。归档后通知立即退出用户收件箱,但通知历史、操作者信息和既有已读回执继续保留。
|
|
20
|
+
- 无数据库时仅允许开发态内存 Repository;生产部署必须配置 `DATABASE_URL` 并执行迁移。
|
|
21
|
+
|
|
22
|
+
## Feature、RBAC 与审计
|
|
23
|
+
|
|
24
|
+
能力基础 Key 为 `system.notification`:
|
|
25
|
+
|
|
26
|
+
- 用户收件箱和已读接口要求 `system.notification.read`;
|
|
27
|
+
- 后台列表、发布和归档要求 `system.notification.manage`;
|
|
28
|
+
- 菜单、Router、Header、Server API 都引用 Manifest 中的同一 Feature / Permission Key;
|
|
29
|
+
- Feature 或权限不可用时 Header 隐藏且不发请求,Server 仍执行最终 Guard;
|
|
30
|
+
- 普通管理发布只接受广播字段;受众和 TargetRef 只由经过组合根注入的业务端口生成,猜测通知 ID 不能绕过已读可见性检查;
|
|
31
|
+
- 发布记录 `notification.publish`,首次阅读记录 `notification.read`,归档记录 `notification.archive`;重复已读不重复制造审计事件。
|
|
32
|
+
|
|
33
|
+
发布和归档使用关键审计写入策略。普通已读使用常规审计,避免审计存储短暂降级时阻止用户阅读正文。
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# 运维总览设计
|
|
2
|
+
|
|
3
|
+
## 产品边界
|
|
4
|
+
|
|
5
|
+
运维总览面向平台运维人员,纵向展示服务资源、在线会话、缓存和调度状态。页面不再展示“代码生成”和“系统接口”:CRUD 代码生成是开发期 CLI(`bun run generate:crud`),接口目录属于 Manifest、OpenAPI 与安全校验基础设施,两者都不是生产运行监控指标。
|
|
6
|
+
|
|
7
|
+
页面每 5 秒刷新一次基础监控快照,手动刷新会同时刷新已获授权的调度状态。`system.scheduler` Feature 未启用或当前用户没有 `system.scheduler.read` 时,前端不会请求调度接口,避免把符合预期的 Guard 拒绝渲染成加载故障。
|
|
8
|
+
|
|
9
|
+
## 在线会话与 IP
|
|
10
|
+
|
|
11
|
+
“在线”定义为满足以下全部条件的登录会话:
|
|
12
|
+
|
|
13
|
+
- 会话状态为 `active`、未撤销且未过期;
|
|
14
|
+
- 用户仍处于启用状态;
|
|
15
|
+
- `lastSeenAt`(首次请求前使用 `issuedAt`)处于最近 15 分钟窗口内。
|
|
16
|
+
|
|
17
|
+
数据来自认证会话 Repository,而不是当前运维请求的 Actor。IP 在登录时持久化,来源是 Bun Server 读取的直接网络对端地址。服务端不直接信任客户端传入的 `X-Forwarded-For`;部署在反向代理后若要展示原始客户端 IP,应在可信代理边界增加受控的地址解析适配器。
|
|
18
|
+
|
|
19
|
+
## 数据库和磁盘监控
|
|
20
|
+
|
|
21
|
+
运维 DTO 只包含方言无关字段:数据库引擎、版本、库名和逻辑数据量。当前启动入口注入 PostgreSQL Probe,通过 `server_version`、`current_database()` 和 `pg_database_size()` 读取信息。MySQL、达梦、人大金仓等数据库应各自实现相同 `DatabaseMonitorProbe`,业务页面不感知 SQL 方言。
|
|
22
|
+
|
|
23
|
+
磁盘监控按独立数据源展示,不再用“文件系统已用量减数据库逻辑量”推算:
|
|
24
|
+
|
|
25
|
+
- 宿主机总容量:非容器部署读取 `/`;容器部署只有显式配置只读宿主机挂载 `WINDY_HOST_DISK_PATH` 时才展示,否则返回“未知”,避免把容器 overlay 当成电脑总容量;
|
|
26
|
+
- 系统占用:递归汇总 `WINDY_SYSTEM_USAGE_PATHS` 指定的一组应用自有目录的实际文件字节;
|
|
27
|
+
- 数据占用:数据库 Probe 返回的逻辑数据量,加上 `WINDY_IMPORT_DATA_PATHS` 指定的数据库外独立导入目录。
|
|
28
|
+
|
|
29
|
+
路径列表使用英文逗号分隔。嵌套系统路径会自动去重;与导入目录完全相同的路径会从系统路径中排除,部署时仍应避免把数据库物理目录或导入目录的父目录配置为系统路径。目录统计缓存 60 秒,页面的 5 秒刷新不会触发无界重复遍历。数据库内的导入内容已经包含在数据库逻辑量中,不得再配置为独立导入目录。
|
|
30
|
+
|
|
31
|
+
Docker 或 Kubernetes 无法可靠读取物理宿主机容量时,保留“未知”比展示 overlay 容量更准确。若数据库位于独立主机或卷,数据库逻辑量也不应和应用宿主机总容量解释为同一物理磁盘的占用比例。
|
|
32
|
+
|
|
33
|
+
## 时间与刷新
|
|
34
|
+
|
|
35
|
+
服务端返回 ISO 时间,Web 端统一按 `Asia/Shanghai` 格式化为 `yyyy-mm-dd hh:mm:ss`。服务卡展示进程启动时间,内存条展示 Bun Server 进程 RSS 相对主机总内存的实时占比。
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# 部门组织与用户归属
|
|
2
|
+
|
|
3
|
+
## 设计依据
|
|
4
|
+
|
|
5
|
+
Windy V1 采用单组织、单租户的企业私有化模型。canonical schema 保留 RuoYi-Vue 兼容导入所需的部门树、用户主部门和角色自定义部门范围,但新模块不得直接依赖旧 `sys_dept` 或其它 `sys_*` 表。
|
|
6
|
+
|
|
7
|
+
- `departments.parent_id` 表示上级部门,空值为根部门;
|
|
8
|
+
- `users.department_id` 表示用户唯一主部门;
|
|
9
|
+
- `roles.data_scope` 和 `roles.department_ids` 表示角色数据范围策略;
|
|
10
|
+
- 岗位、兼职部门和多组织成员关系属于后续独立模型,不复用 `department_id` 暗中表达。
|
|
11
|
+
|
|
12
|
+
这些边界延续 [RuoYi-Vue 兼容与迁移设计](../adapters/ruoyi-vue-compatibility.md) 的 Adapter 原则,也与 [Starter 产品缺口分析](../product/starter-product-gap-analysis.md) 中“单组织 V1”和“数据权限必须进入查询约束”的结论一致。
|
|
13
|
+
|
|
14
|
+
## 用户表单闭环
|
|
15
|
+
|
|
16
|
+
用户新增和编辑表单从 `GET /api/system/departments` 加载启用部门,并以受控下拉框写入 `users.department_id`;角色区域从 `GET /api/system/roles` 加载启用角色,显示中文名称、稳定编码和数据范围。创建用户必须选择一个启用部门和至少一个启用角色,服务端会再次验证,不能通过直接调用 API 写入悬空部门、空角色或停用角色。
|
|
17
|
+
|
|
18
|
+
具备以下任一管理能力时,用户表单显示“新建部门”快捷入口:
|
|
19
|
+
|
|
20
|
+
- `system.department.create`:调用受限的 `POST /api/system/departments/quick`;
|
|
21
|
+
- `system.department.manage`:兼容既有管理员,调用通用部门创建接口。
|
|
22
|
+
|
|
23
|
+
快捷创建只接收名称、编码、可选上级和排序,成功后刷新部门列表并自动选中新部门。`system.department.create` 与既有 `system.department.read/manage` 使用同一能力基础 Key `system.department`,接口继续经过 `system.rbac` Feature Guard,并写入 `crud.create` 审计事件。没有创建或管理权限时,表单只显示部门选择,不渲染快捷入口。
|
|
24
|
+
|
|
25
|
+
## 权限边界
|
|
26
|
+
|
|
27
|
+
用户页面的新增、编辑和删除入口要求 `system.user.manage`;只有 `system.user.read` 时保持只读。部门下拉还需要 `system.department.read`,快捷创建需要上述 create 或 manage 权限,Server 是最终授权边界。
|
|
28
|
+
|
|
29
|
+
当前用户资源已接入类型化数据访问上下文。Actor Resolver 从全部启用角色生成 `all`、`tenant`、`department`、`department-and-children`、`self` 或 `custom` grant;多个角色按可见集合并集计算。用户列表、总数、搜索、分页、导出、按 ID 读取、更新、删除和组织移动使用同一约束,跨部门猜测 ID 返回稳定的 `data-scope-denied`,不会只依赖 Web 隐藏。
|
|
30
|
+
|
|
31
|
+
详细接入契约见 [数据访问范围](./data-access-control.md)。V1 当前只承诺用户资源已经闭环;没有明确 `ownerId` / `departmentId` 归属的资源不会自动套用部门范围。部门树循环、唯一根节点、含下级或用户节点的停用/删除/迁移策略仍属于 `ORG-02`,不能从当前后代解析能力推导为已经完成。
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# 客户业务平台认证与会话
|
|
2
|
+
|
|
3
|
+
## 运行模型
|
|
4
|
+
|
|
5
|
+
客户业务平台账号保存在 canonical PostgreSQL `users` 表,和 License 签发中心操作员账号完全隔离。认证链路为:
|
|
6
|
+
|
|
7
|
+
1. Admin Web 通过 `POST /api/auth/login` 校验用户名和密码并只接收 `HttpOnly` Cookie;明确需要 Bearer 的非浏览器客户端使用独立的 `POST /api/auth/api/login`。
|
|
8
|
+
2. 密码只以 Argon2id hash 保存;策略为 12-128 个字符,服务端不会记录或返回明文密码。
|
|
9
|
+
3. 登录成功后签发 256-bit 随机会话 Token;数据库 `server_sessions` 只保存 Token 的 SHA-256 hash。
|
|
10
|
+
4. 浏览器通过 `windy.sid` Cookie 使用会话,登录 JSON 不返回 Token;API 客户端只能从独立 Bearer 签发入口取得 Token,再使用 `Authorization: Bearer <token>`。
|
|
11
|
+
5. Web 启动时通过 `GET /api/auth/session` 恢复当前 Actor,再按 License 状态读取权限快照;Actor Resolver 校验会话状态、吊销时间、过期时间和用户状态,然后从活跃角色聚合角色代码与权限,交给 Role / Permission Guard。
|
|
12
|
+
|
|
13
|
+
默认会话时长为 8 小时,可通过 `SESSION_TTL_SECONDS` 调整。Cookie 使用 `HttpOnly`、`SameSite=Strict` 和 `Path=/`;`NODE_ENV=production` 时还会启用 `Secure`。
|
|
14
|
+
|
|
15
|
+
## API
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
POST /api/auth/login
|
|
19
|
+
POST /api/auth/api/login
|
|
20
|
+
GET /api/auth/session
|
|
21
|
+
POST /api/auth/logout
|
|
22
|
+
POST /api/auth/password/change
|
|
23
|
+
GET /api/auth/sessions
|
|
24
|
+
POST /api/auth/sessions/:id/revoke
|
|
25
|
+
POST /api/auth/sessions/revoke-all
|
|
26
|
+
GET /api/auth/login-events
|
|
27
|
+
POST /api/auth/users/:id/password
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- `POST /auth/login` 是 Admin Web 的 Cookie-only 登录:返回 Session ID、到期时间和非敏感用户信息,设置 `HttpOnly` Cookie,但 JSON 明确不包含 `token` 或 `tokenType`。
|
|
31
|
+
- `POST /auth/api/login` 是非浏览器集成的显式 Bearer 签发缝:返回 Token、`Bearer` 类型、Session ID、到期时间和非敏感用户信息,但不设置 Cookie。它不是 OAuth/OIDC Token Endpoint,也不应被 Admin Web 调用;正式对外开放前仍需在部署层明确客户端、网络、限流和凭据管理边界。
|
|
32
|
+
- `session` 只返回当前 Actor,不返回 Token,并设置 `Cache-Control: no-store`;匿名请求返回 401。
|
|
33
|
+
- `logout` 吊销当前 Bearer/Cookie 会话并清除 Cookie。
|
|
34
|
+
- `GET /auth/sessions` 只按服务端解析出的当前 Session Actor 查询有效会话,不接受客户端 `userId`,并返回 `current`、IP、User-Agent、签发/最近活动/到期时间;不会返回用户 ID、原始 Token 或 Token hash。
|
|
35
|
+
- 用户可以通过 `POST /auth/sessions/:id/revoke` 吊销自己的单个会话;具备 `system.user.manage` 权限的用户仍可吊销其他用户会话。响应显式返回 `currentSessionRevoked`;若吊销的是当前会话,会同时清除 Cookie,后续请求立即变为未认证。
|
|
36
|
+
- `POST /auth/sessions/revoke-all` 默认只吊销本人其它会话并保留当前会话,响应返回吊销数量以及当前会话是否保留。只有显式提交 `{ "includeCurrent": true }` 才会吊销包括当前会话在内的全部本人会话并清除 Cookie;客户端不能提交目标用户 ID。
|
|
37
|
+
- `GET /auth/login-events` 返回当前 Session Actor 最近 20 条登录成功/失败事件。查询条件固定为服务端 Actor,客户端即使提交 `actorId` 也不能读取他人的事件;响应只保留结果、时间、IP、User-Agent 和稳定失败原因,不暴露审计 Actor 或目标账号字段。未知账号登录失败继续归属匿名 Actor,不能借该接口探测账号是否存在。
|
|
38
|
+
- 只有具备 `system.user.manage` 权限的用户可以重置密码。接口接收 `password`,服务端生成 Argon2id hash;通用用户 CRUD 不读写或返回 `password_hash`。重置后账号进入 `must-change-password`,`password_changed_at` 保持空值,并立即吊销该用户全部活跃会话。
|
|
39
|
+
- 已认证用户通过 `POST /api/auth/password/change` 提交当前密码和新密码。服务端固定使用 Session Actor 作为目标用户,不接受客户端 `userId`;校验当前密码、拒绝复用当前密码,并在成功后把状态恢复为 `active`、记录 `password_changed_at`。成功改密会吊销包括当前会话在内的全部会话、清除 Cookie,用户必须用新密码重新登录。
|
|
40
|
+
|
|
41
|
+
登录成功、登录失败、退出、会话吊销、密码更新和越权拒绝都会写入审计。审计只记录用户、Session ID、结果和稳定原因,不记录明文密码、Bearer Token 或 Cookie。
|
|
42
|
+
|
|
43
|
+
## Authentication Provider 边界
|
|
44
|
+
|
|
45
|
+
`AuthService` 不再直接查询密码 hash 或调用 Argon2,而是只调用 `AuthenticationProviderRegistry` 选中的默认 `AuthenticationProvider`。当前默认注册 `LocalArgon2AuthenticationAdapter`:它通过 `AuthRepository` 读取 canonical 用户、使用既有 `PasswordHasher` 验证 Argon2id,并只把启用用户映射回平台 Session。密码修改与管理员重置仍由独立凭据服务负责,不混入 Provider 登录职责。
|
|
46
|
+
|
|
47
|
+
Provider 契约显式区分 `local`、`oidc`、`ldap` 三类 Provider,以及 `password`、`authorization-code`、`mfa` 能力;认证输入为密码、OIDC 授权码或 MFA challenge 的判别联合,结果为已认证、拒绝或需要 MFA challenge。Registry 会拒绝空 Key、重复 Key 和未注册的默认 Provider,并提供稳定的类型化描述。该端口只是组合与替换边界:当前没有 OIDC callback、LDAP 配置、MFA challenge 存储或企业微信/钉钉实现,不能把契约存在解释为已经支持这些客户集成。真实 Provider 必须在客户场景明确后作为 Adapter 接入并补充配置校验、失败/超时、账号映射、审计和集成回归。
|
|
48
|
+
|
|
49
|
+
## 管理端账号生命周期
|
|
50
|
+
|
|
51
|
+
用户创建和编辑继续使用受 Guard 保护的系统资源入口,但身份配置附加领域策略,不能等同于任意 JSON CRUD:
|
|
52
|
+
|
|
53
|
+
- 创建必须选择启用部门和至少一个启用角色;用户与角色资源不支持通用 JSON 导入,避免绕过这些不变量。
|
|
54
|
+
- Web 创建账号时必须填写一次性初始密码。账号资料保存后调用专用密码接口;密码字段不会进入用户资料、列表响应或通用 CRUD 审计。
|
|
55
|
+
- 管理员可在同一表单执行密码重置。停用、软删除或密码更新都会吊销该用户全部活跃会话;Actor Resolver 同时要求用户仍为启用状态,因此停用后的既有 Token 不能继续访问。
|
|
56
|
+
- 系统必须至少保留一个启用且持有启用 `super-admin` 角色的账号。用户停用、删除、移除角色,以及内置超级管理员角色停用、改码、缩小数据范围、移除用户管理权限或删除,都会被领域策略拒绝。
|
|
57
|
+
- 用户与角色关键变更共享串行 mutation runner,最后管理员检查和写入在当前单 Server 进程内保持原子顺序,并有并发停用回归。多副本部署前仍需把该互斥升级为 PostgreSQL 事务锁或分布式单写者。
|
|
58
|
+
|
|
59
|
+
自助修改密码、首次登录强制改密、本人设备会话 API、最近登录事件 API、类型化企业身份 Provider 边界与浏览器 Token 返回收口已经闭环。OIDC、LDAP、MFA、企业微信或钉钉的真实接入继续等待客户场景,不是当前完成度的隐含声明。
|
|
60
|
+
|
|
61
|
+
## Web 登录与权限刷新
|
|
62
|
+
|
|
63
|
+
Web 路由进入顺序固定为:当前会话 → 强制改密状态 → License 运行状态 → `/api/foundation` 权限快照。会话、License 和权限读取都使用同一轮 single-flight,避免并发组件重复请求;正常路由切换会刷新 License 和权限快照,因此角色、权限、Feature Flag 或新 License 在下一次导航时生效,无需重新构建前端。
|
|
64
|
+
|
|
65
|
+
会话 Actor 除角色和权限外,只携带当前用户自己的 `username`、`displayName`、`phone`、`email` 可选字段,供账号菜单和页面水印等当前会话体验使用;不会借此返回其他用户资料。
|
|
66
|
+
|
|
67
|
+
- 未登录访问受保护路径会跳转 `/login?returnTo=...`。`returnTo` 只接受本站绝对路径,拒绝协议相对地址、反斜线、控制字符和登录页自身,防止开放重定向与循环。
|
|
68
|
+
- 登录成功后重新读取 `/auth/session`,清空旧 License/权限缓存并返回安全的原路径。
|
|
69
|
+
- Session Actor 为 `must-change-password` 时,Web 只进入 `/change-password`;服务端同时只放行会话探测、本人改密和退出,避免绕过前端直接访问业务 API。该入口在 License 受限状态下也保持可用。
|
|
70
|
+
- 任意业务请求返回 401 时全局清除会话、License 和权限状态并跳转登录;403 仍按 License、Feature 或权限拒绝处理,不会误判为退出。
|
|
71
|
+
- 退出成功后吊销服务端会话并返回登录页;网络错误不会在客户端伪造“已退出”。
|
|
72
|
+
- License 到期、缺失或无效时,已认证用户仍可读取会话、退出以及进入 License 查看/上传页,不会先请求受限的权限快照。
|
|
73
|
+
- 会话到期后不做客户端静默续期,用户需要重新登录。
|
|
74
|
+
|
|
75
|
+
## 浏览器凭据与同源边界
|
|
76
|
+
|
|
77
|
+
Web 只使用服务端设置的 `HttpOnly` Cookie;浏览器登录响应已经不再携带 Bearer Token,因此前端类型也不存在 Token 字段,更不会把 Token 保存到 localStorage、sessionStorage、Pinia 或其它 JavaScript 持久化位置。生产前端所有请求默认使用 `credentials: same-origin` 和相对 `/api` 地址;Bun Web 服务通过 `API_UPSTREAM` 把 `/api` 转发给内部 Server,浏览器始终看到同一 Origin。当前不支持跨 Origin 的带凭据 Web 部署,也没有开启 credentialed CORS。
|
|
78
|
+
|
|
79
|
+
当前 Cookie 请求的 CSRF 边界由 `SameSite=Strict`、同源 `/api` 和不开放跨域凭据共同组成。它不能防御同源 XSS、被攻陷的同站点应用或错误的反向代理边界;生产仍应只托管可信同源内容并配置合适的 CSP。未来若必须把 Web 与 API 部署到不同 Origin,必须先增加严格 Origin 白名单和独立 CSRF Token/请求头校验,不能只把 `credentials` 改成 `include`。
|
|
80
|
+
|
|
81
|
+
## 首次初始化
|
|
82
|
+
|
|
83
|
+
新数据库可在第一次启动 Server 时临时设置:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
WINDY_BOOTSTRAP_ADMIN_PASSWORD=<至少 12 个字符的初始密码>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Server 会幂等创建默认开发管理员和 `developer` 角色;仅当默认管理员尚无密码 hash 时写入初始密码,并把凭据状态设为 `must-change-password`。初始化成功后应从运行环境删除该变量,首次登录完成自助改密,后续通过受权限保护的密码重置 API 管理密码。Feature Flag 修改除 `system.feature.manage` 权限外,还要求活跃角色代码为 `super-admin` 或 `developer`;普通管理员不能通过单独获配该权限绕过角色边界。已有数据库不会自动把既有普通管理员提升为开发角色,需要显式分配 `developer` 角色。
|
|
90
|
+
|
|
91
|
+
## 开发直通与生产约束
|
|
92
|
+
|
|
93
|
+
真实会话是默认认证路径。开发直通只在非生产环境可用:
|
|
94
|
+
|
|
95
|
+
- 配置 `WINDY_DEV_ADMIN_TOKEN` 会显式启用该开发 Token。
|
|
96
|
+
- 配置 `WINDY_DEV_AUTH_BYPASS=1` 会启用默认 `dev-admin-token`,并允许 `user:<userIdOrUsername>` 直通。
|
|
97
|
+
- `WINDY_DB_USER_TOKEN_PREFIX` 只能修改开发直通前缀。
|
|
98
|
+
- `NODE_ENV=production` 时,上述 Token 与 `user:` 直通无条件关闭,即使环境变量误配置也不会生效。
|
|
99
|
+
|
|
100
|
+
Web 不提供默认开发 Token。只有 Vite 开发模式同时设置 `VITE_DEV_AUTH_BYPASS=1` 和非空 `VITE_DEV_ADMIN_TOKEN` 时,前端才会携带显式 Bearer Token,并在登录页和应用壳持续显示警告;生产构建无条件忽略这两个变量。完成一次真实密码登录后,当前页面生命周期内会停用开发 Token,后续请求只使用 Cookie。Docker Compose 不再注入默认 `dev-admin-token`。
|
|
101
|
+
|
|
102
|
+
未配置 `DATABASE_URL` 时不会注册真实登录 API;只允许显式的非生产开发直通,不存在内存生产账号或默认生产密码。
|
|
103
|
+
|
|
104
|
+
## PostgreSQL 交付回归
|
|
105
|
+
|
|
106
|
+
在安装了 Docker 的交付机或 CI 上运行:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
bun run test:db:auth
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
该命令会临时启动 `postgres:17-alpine`、执行正式 migration、写入使用真实 Argon2id 密码的 fixture,并启动两次正式 Server 进程完成以下验证:
|
|
113
|
+
|
|
114
|
+
- Admin Web 的 `POST /api/auth/login` 响应不返回 Token、只签发 `HttpOnly` Cookie;独立 `POST /api/auth/api/login` 返回 Bearer Token 且不设置 Cookie,数据库在两条路径都只保存密码 hash 和 Session Token 的 SHA-256 hash;
|
|
115
|
+
- Bearer Token 经 Actor Resolver 解析授权快照:`users.role_ids` 只要是数组(包括 `[]`)就是用户角色的 canonical 真相,只有字段为 `NULL` 或非数组旧值时才回退 `user_roles`;对选中的每个启用角色,`roles.permission_keys` 同样只要是数组(包括 `[]`)就覆盖该角色的兼容关系,只有字段缺失时才回退 `role_permissions`;
|
|
116
|
+
- `roleCodes`、`permissionKeys` 和 data access 只从同一组启用角色生成,并对角色 ID、权限 Key 和自定义部门 ID 稳定去重;停用角色及其 JSON/关系权限都不会进入快照;
|
|
117
|
+
- Server 进程退出并重启后,已有 PostgreSQL Session 仍能鉴权;
|
|
118
|
+
- 过期、主动吊销和退出的 Session 均立即失效;
|
|
119
|
+
- 管理员重置后 PostgreSQL 凭据状态为 `must-change-password`、业务 API 返回 `PASSWORD_CHANGE_REQUIRED`,会话探测和本人改密仍可用;本人改密写入 `password_changed_at` 并吊销包括当前会话在内的全部会话,新密码重登后恢复业务访问;
|
|
120
|
+
- 本人会话列表不能被客户端 `userId` 扩大范围,且只标识一个当前会话;单个吊销、默认保留当前会话的批量吊销、显式包含当前会话的全退都会按响应语义立即生效;
|
|
121
|
+
- 本人登录事件同时包含已知账号的登录成功与失败,读取条件固定为服务端 Session Actor,客户端 `actorId` 不能改写查询范围;
|
|
122
|
+
- 即使误配 `WINDY_DEV_AUTH_BYPASS` 和 `WINDY_DEV_ADMIN_TOKEN`,生产环境也拒绝开发 Token 与 `user:` 直通;
|
|
123
|
+
- 认证关键动作落入 PostgreSQL 审计表。
|
|
124
|
+
|
|
125
|
+
脚本使用随机容器名、随机宿主端口和临时审计恢复文件,并等待 PostgreSQL 连续两次真实 SQL 探活后再迁移,避免镜像初始化阶段的临时 Server 被误判为就绪。成功或失败都会先停止当前 Server,再强制删除 PostgreSQL 容器和临时文件。它验证的是 Server、PostgreSQL 与认证链路,不覆盖反向代理 TLS、浏览器 Cookie 策略或多实例负载均衡;这些属于部署环境验收。
|
|
126
|
+
|
|
127
|
+
迁移期契约是“canonical 存在即覆盖、缺失才兼容回退”,不是无条件并集。权限策略页面的勾选和取消直接更新 `roles.permission_keys`;空数组表示明确撤销全部权限,不能被残留 `role_permissions` 重新授予。`user_roles` 与 `role_permissions` 仅服务尚未回填 JSON 列的旧记录,导入完成后必须归并到 `users.role_ids` / `roles.permission_keys`。在关系表被前向迁移移除前,不得把 canonical 列重新写成 `NULL`,否则会重新启用兼容回退。
|