@h-ai/cli 0.1.0-alpha9 → 1.0.0-beta.2
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.en.md +229 -0
- package/README.ja.md +229 -0
- package/README.md +175 -113
- package/dist/chunk-AKV2CQZV.js +1497 -0
- package/dist/chunk-AKV2CQZV.js.map +1 -0
- package/dist/chunk-EF7WOFWZ.js +7557 -0
- package/dist/chunk-EF7WOFWZ.js.map +1 -0
- package/dist/chunk-MUHRBJSW.js +29272 -0
- package/dist/chunk-MUHRBJSW.js.map +1 -0
- package/dist/chunk-ZSDEVXZ7.js +38 -0
- package/dist/{chunk-2H7UOFLK.js.map → chunk-ZSDEVXZ7.js.map} +1 -1
- package/dist/cli-config-templates-HHFHNXBN.js +5 -0
- package/dist/cli-config-templates-HHFHNXBN.js.map +1 -0
- package/dist/cli-skill-templates-PN4FLGBC.js +5 -0
- package/dist/cli-skill-templates-PN4FLGBC.js.map +1 -0
- package/dist/index.js +4444 -554
- package/dist/index.js.map +1 -1
- package/dist/metafile-esm.json +1 -0
- package/dist/src-TEBHR5I5.js +5 -0
- package/dist/src-TEBHR5I5.js.map +1 -0
- package/package.json +35 -15
- package/templates/README.md +56 -114
- package/templates/apps/admin/messages/en-US.json +7 -0
- package/templates/apps/admin/messages/ja-JP.json +40 -0
- package/templates/apps/admin/messages/zh-CN.json +7 -0
- package/templates/apps/admin/src/routes/+layout.svelte.hbs +65 -8
- package/templates/apps/admin/src/routes/+page.svelte.hbs +35 -14
- package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +54 -22
- package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +33 -24
- package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +16 -13
- package/templates/apps/api/.dockerignore.hbs +25 -0
- package/templates/apps/api/.gitignore.hbs +22 -0
- package/templates/apps/api/.npmrc.hbs +1 -0
- package/templates/apps/api/apps/{{projectName}}-contract/README.md.hbs +39 -0
- package/templates/apps/api/apps/{{projectName}}-contract/package.json.hbs +41 -0
- package/templates/apps/api/apps/{{projectName}}-contract/src/app-contract.ts.hbs +27 -0
- package/templates/apps/api/apps/{{projectName}}-contract/src/app-schemas.ts.hbs +28 -0
- package/templates/apps/api/apps/{{projectName}}-contract/src/index.ts.hbs +5 -0
- package/templates/apps/api/apps/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +16 -0
- package/templates/apps/api/apps/{{projectName}}-contract/tests/contract.test.ts.hbs +18 -0
- package/templates/apps/api/apps/{{projectName}}-contract/tsconfig.json.hbs +12 -0
- package/templates/apps/api/apps/{{projectName}}-contract/tsup.config.ts.hbs +11 -0
- package/templates/apps/api/apps/{{projectName}}-contract/vitest.config.ts.hbs +9 -0
- package/templates/apps/api/apps/{{projectName}}-serv/README.md.hbs +60 -0
- package/templates/apps/api/apps/{{projectName}}-serv/config/_core.yml.hbs +17 -0
- package/templates/apps/api/apps/{{projectName}}-serv/config/_serv.yml.hbs +54 -0
- package/templates/apps/api/apps/{{projectName}}-serv/data/.gitkeep.hbs +1 -0
- package/templates/apps/api/apps/{{projectName}}-serv/package.json.hbs +66 -0
- package/templates/apps/api/apps/{{projectName}}-serv/src/app.ts.hbs +119 -0
- package/templates/apps/api/apps/{{projectName}}-serv/src/build-metadata.ts.hbs +7 -0
- package/templates/apps/api/apps/{{projectName}}-serv/src/index.ts.hbs +41 -0
- package/templates/apps/api/apps/{{projectName}}-serv/src/lib/server/init.ts.hbs +165 -0
- package/templates/apps/api/apps/{{projectName}}-serv/src/server/procedures/app-procedures.ts.hbs +57 -0
- package/templates/apps/api/apps/{{projectName}}-serv/src/server/procedures/index.ts.hbs +41 -0
- package/templates/apps/api/apps/{{projectName}}-serv/tests/service.test.ts.hbs +176 -0
- package/templates/apps/api/apps/{{projectName}}-serv/tsconfig.json.hbs +16 -0
- package/templates/apps/api/apps/{{projectName}}-serv/tsup.config.ts.hbs +20 -0
- package/templates/apps/api/apps/{{projectName}}-serv/vitest.config.ts.hbs +12 -0
- package/templates/apps/api/e2e/api-serv.spec.ts.hbs +113 -0
- package/templates/apps/api/e2e/capture-evidence.ts.hbs +23 -0
- package/templates/apps/api/eslint.config.js.hbs +30 -0
- package/templates/apps/api/hai.json.hbs +4 -0
- package/templates/apps/api/images/serv.Dockerfile.hbs +37 -0
- package/templates/apps/api/package.json.hbs +53 -0
- package/templates/apps/api/playwright.config.ts.hbs +67 -0
- package/templates/apps/api/pnpm-workspace.yaml.hbs +40 -0
- package/templates/apps/api/tsconfig.base.json +14 -0
- package/templates/apps/fullstack/.dockerignore.hbs +25 -0
- package/templates/apps/fullstack/.gitignore.hbs +38 -0
- package/templates/apps/fullstack/.npmrc.hbs +1 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/.env.example.hbs +10 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +67 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/capacitor.config.ts.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/eslint.config.js.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/index.html.hbs +22 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/messages/en-US.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/messages/ja-JP.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/messages/zh-CN.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +86 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/project.inlang/settings.json.hbs +17 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/public/runtime-config.js.hbs +4 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/App.svelte.hbs +59 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.css.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.d.ts.hbs +8 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/build-metadata.ts.hbs +9 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/lib/capacitor.ts.hbs +19 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/main.ts.hbs +21 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/svelte.config.js.hbs +16 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/tsconfig.json.hbs +23 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +74 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/.env.example.hbs +6 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +64 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/eslint.config.js.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/index.html.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/en-US.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/ja-JP.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/zh-CN.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +66 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/project.inlang/settings.json.hbs +17 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/App.svelte.hbs +25 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/app.css.hbs +18 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/app.d.ts.hbs +8 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/build-metadata.ts.hbs +9 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/main.ts.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/Cargo.toml.hbs +33 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/build.rs.hbs +6 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/capabilities/default.json.hbs +16 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/128x128.png +0 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/128x128@2x.png +0 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/32x32.png +0 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/icon.icns +0 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/icon.ico +0 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/lib.rs.hbs +91 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/main.rs.hbs +8 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +46 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/svelte.config.js.hbs +14 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/tsconfig.json.hbs +22 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +89 -0
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/README.md.hbs +25 -0
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/messages/en-US.json.hbs +12 -0
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/messages/ja-JP.json.hbs +12 -0
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/messages/zh-CN.json.hbs +12 -0
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/project.inlang/settings.json.hbs +17 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +54 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/eslint.config.js.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/index.html.hbs +21 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/messages/en-US.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/messages/ja-JP.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/messages/zh-CN.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +53 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/project.inlang/settings.json.hbs +17 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/public/runtime-config.js.hbs +1 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/App.svelte.hbs +18 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.css.hbs +18 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.d.ts.hbs +8 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/build-metadata.ts.hbs +9 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/main.ts.hbs +14 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/svelte.config.js.hbs +16 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/tsconfig.json.hbs +23 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +76 -0
- package/templates/apps/fullstack/docs/security-configuration.md.hbs +349 -0
- package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +988 -0
- package/templates/apps/fullstack/e2e/session-close.spec.ts.hbs +119 -0
- package/templates/apps/fullstack/eslint.config.js.hbs +41 -0
- package/templates/apps/fullstack/hai.json.hbs +11 -0
- package/templates/apps/fullstack/images/serv.Dockerfile.hbs +38 -0
- package/templates/apps/fullstack/images/web/19-runtime-config.envsh.hbs +5 -0
- package/templates/apps/fullstack/images/web/nginx.conf.hbs +24 -0
- package/templates/apps/fullstack/images/web/runtime-config.js.template.hbs +3 -0
- package/templates/apps/fullstack/images/web.Dockerfile.hbs +37 -0
- package/templates/apps/fullstack/package.json.hbs +61 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/README.md.hbs +40 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/package.json.hbs +30 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-contract.ts.hbs +78 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-schemas.ts.hbs +134 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/app-contract.ts.hbs +20 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/app-schemas.ts.hbs +35 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/index.ts.hbs +7 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +23 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/tests/contract.test.ts.hbs +31 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/tsconfig.json.hbs +9 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/tsup.config.ts.hbs +9 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +84 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_ai.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_audit.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_cache.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_core.yml.hbs +22 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_db.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_feedback.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_iam.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_payment.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_reach.yml.hbs +60 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_scheduler.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +64 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_storage.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_vecdb.yml.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/data/.gitkeep.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +62 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/app-server.ts.hbs +115 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/build-metadata.ts.hbs +7 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +40 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/admin-service.ts.hbs +294 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/audit-jobs.ts.hbs +28 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/business-settings.ts.hbs +50 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/messages.ts.hbs +50 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/admin-procedures.ts.hbs +106 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/app-procedures.ts.hbs +49 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/index.ts.hbs +34 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/runtime.ts.hbs +159 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/security-roles.ts.hbs +73 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/app-server.test.ts.hbs +505 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/runtime.test.ts.hbs +72 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/security.test.ts.hbs +183 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tsconfig.json.hbs +10 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tsup.config.ts.hbs +18 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/vitest.config.ts.hbs +12 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/.gitignore.hbs +10 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +97 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/en-US.json.hbs +164 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/ja-JP.json.hbs +164 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/zh-CN.json.hbs +164 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/package.json.hbs +55 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/project.inlang/settings.json.hbs +11 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/index.ts.hbs +7 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/api-client.ts.hbs +94 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/feedback-client.ts.hbs +36 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/sensitive-actions.svelte.ts.hbs +16 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/session-recovery.svelte.ts.hbs +4 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AdminWorkspace.svelte.hbs +122 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +90 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/FeedbackEntry.svelte.hbs +86 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/audit.svelte.hbs +94 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/configuration.svelte.hbs +25 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/feedback.svelte.hbs +157 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/roles.svelte.hbs +77 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/settings.svelte.hbs +44 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/users.svelte.hbs +216 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/security/role-label.ts.hbs +12 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/guide-store.ts.hbs +55 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/management-store.svelte.ts.hbs +614 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/theme-store.svelte.ts.hbs +23 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/svelte.config.js.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/api-client.test.ts.hbs +150 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/management-store.test.ts.hbs +253 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/tsconfig.json.hbs +17 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/vitest.config.ts.hbs +7 -0
- package/templates/apps/fullstack/playwright.config.ts.hbs +114 -0
- package/templates/apps/fullstack/playwright.session-close.config.ts.hbs +18 -0
- package/templates/apps/fullstack/pnpm-workspace.yaml.hbs +38 -0
- package/templates/apps/fullstack/tsconfig.base.json +14 -0
- package/templates/apps/h5/messages/en-US.json +3 -0
- package/templates/apps/h5/messages/ja-JP.json +40 -0
- package/templates/apps/h5/messages/zh-CN.json +3 -0
- package/templates/apps/h5/src/routes/+layout.svelte.hbs +85 -30
- package/templates/apps/h5/src/routes/+page.svelte.hbs +20 -8
- package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +17 -6
- package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +17 -6
- package/templates/apps/mobile-app/.env.hbs +3 -0
- package/templates/apps/{android-app → mobile-app}/capacitor.config.ts.hbs +2 -2
- package/templates/apps/mobile-app/index.html.hbs +14 -0
- package/templates/apps/mobile-app/messages/en-US.json +36 -0
- package/templates/apps/mobile-app/messages/ja-JP.json +36 -0
- package/templates/apps/mobile-app/messages/zh-CN.json +36 -0
- package/templates/apps/mobile-app/public/runtime-config.js +1 -0
- package/templates/apps/mobile-app/src/App.svelte.hbs +153 -0
- package/templates/apps/mobile-app/src/lib/api.ts.hbs +213 -0
- package/templates/apps/mobile-app/src/lib/app-config.ts.hbs +14 -0
- package/templates/apps/{android-app → mobile-app}/src/lib/capacitor.ts +6 -7
- package/templates/apps/mobile-app/src/lib/pages/home.svelte.hbs +58 -0
- package/templates/apps/mobile-app/src/lib/pages/profile.svelte.hbs +13 -0
- package/templates/apps/mobile-app/src/lib/pages/tasks.svelte.hbs +16 -0
- package/templates/apps/mobile-app/src/main.ts.hbs +11 -0
- package/templates/apps/website/messages/en-US.json +4 -2
- package/templates/apps/website/messages/ja-JP.json +34 -0
- package/templates/apps/website/messages/zh-CN.json +4 -2
- package/templates/apps/website/scripts/static-website.mjs.hbs +67 -0
- package/templates/apps/website/src/routes/+layout.svelte.hbs +77 -26
- package/templates/apps/website/src/routes/+layout.ts +3 -0
- package/templates/apps/website/src/routes/+page.svelte.hbs +31 -12
- package/templates/apps/website/src/routes/about/+page.svelte.hbs +11 -6
- package/templates/apps/website/src/routes/api/health/+server.ts +3 -0
- package/templates/apps/website/src/routes/contact/+page.svelte.hbs +44 -34
- package/templates/apps/website/src/routes/services/+page.svelte.hbs +27 -40
- package/templates/base/.dockerignore.hbs +27 -0
- package/templates/base/.gitignore.hbs +41 -0
- package/templates/base/.npmrc.hbs +1 -0
- package/templates/base/e2e/app.spec.ts.hbs +213 -0
- package/templates/base/e2e/helpers.ts +1 -1
- package/templates/base/eslint-rules.js +45 -0
- package/templates/base/eslint.config.js.hbs +34 -0
- package/templates/base/hai.json.hbs +4 -0
- package/templates/base/images/web/nginx.conf.hbs +24 -0
- package/templates/base/images/web.Dockerfile.hbs +72 -0
- package/templates/base/package.json.hbs +125 -49
- package/templates/base/playwright.config.ts +44 -6
- package/templates/base/pnpm-workspace.yaml.hbs +40 -0
- package/templates/base/src/app.css.hbs +40 -0
- package/templates/base/src/app.d.ts.hbs +14 -1
- package/templates/base/src/app.html.hbs +13 -0
- package/templates/base/src/hooks.server.ts.hbs +115 -43
- package/templates/base/src/lib/build-metadata.ts.hbs +7 -0
- package/templates/base/src/lib/server/init.ts.hbs +125 -152
- package/templates/base/src/lib/server/kit-config.ts.hbs +40 -0
- package/templates/base/src/routes/+layout.server.ts.hbs +35 -0
- package/templates/base/static/favicon.png +0 -0
- package/templates/base/svelte.config.js.hbs +84 -5
- package/templates/base/tests/scaffold.test.ts.hbs +102 -0
- package/templates/base/tsconfig.json.hbs +50 -0
- package/templates/base/vite.config.ts.hbs +117 -12
- package/templates/base/vitest.config.ts.hbs +19 -0
- package/templates/features/ai/routes/api/chat/+server.ts +6 -7
- package/templates/features/iam/routes-admin/(auth)/+layout.svelte.hbs +3 -17
- package/templates/features/iam/routes-admin/(auth)/auth/forgot-password/+page.svelte.hbs +10 -0
- package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +9 -96
- package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +9 -122
- package/templates/features/iam/routes-admin/(auth)/auth/reset-password/+page.svelte.hbs +10 -0
- package/templates/features/iam/routes-h5/auth/forgot-password/+page.svelte.hbs +10 -0
- package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +9 -96
- package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +9 -112
- package/templates/features/iam/routes-h5/auth/reset-password/+page.svelte.hbs +10 -0
- package/templates/features/iam/routes-shared/api/auth/captcha/+server.ts.hbs +4 -0
- package/templates/features/iam/routes-shared/api/auth/config/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/login/+server.ts +1 -29
- package/templates/features/iam/routes-shared/api/auth/login/ldap/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/login/otp/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/logout/+server.ts +13 -6
- package/templates/features/iam/routes-shared/api/auth/otp/send/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/password/renew/+server.ts +5 -0
- package/templates/features/iam/routes-shared/api/auth/password-reset/confirm/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/password-reset/request/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/reauthenticate/+server.ts +5 -0
- package/templates/features/iam/routes-shared/api/auth/register/+server.ts +1 -23
- package/templates/features/iam/routes-shared/api/auth/session/close/+server.ts.hbs +4 -0
- package/templates/features/iam/routes-website/auth/forgot-password/+page.svelte.hbs +10 -0
- package/templates/features/iam/routes-website/auth/login/+page.svelte.hbs +11 -0
- package/templates/features/iam/routes-website/auth/register/+page.svelte.hbs +11 -0
- package/templates/features/iam/routes-website/auth/reset-password/+page.svelte.hbs +10 -0
- package/templates/features/payment/routes/api/v1/payment/create/+server.ts +25 -23
- package/templates/features/payment/routes/api/v1/payment/notify/[provider]/+server.ts +5 -2
- package/templates/features/storage/routes/api/upload/+server.ts +10 -8
- package/templates/i18n/project.inlang/settings.json +2 -2
- package/templates/shared/.gitattributes +11 -0
- package/templates/shared/build-metadata.ts +42 -0
- package/templates/shared/container-runtime-config.sh +30 -0
- package/templates/shared/e2e-env.ts +98 -0
- package/templates/shared/hash-router.svelte.ts +83 -0
- package/templates/shared/public-base-path.mjs +19 -0
- package/templates/shared/run-e2e.mjs +104 -0
- package/templates/shared/vite-runtime-config.ts +56 -0
- package/templates/skills/AGENTS.md +75 -16
- package/templates/skills/CLAUDE.md +0 -11
- package/templates/skills/bridges/admin/AGENTS.md +89 -0
- package/templates/skills/bridges/api/AGENTS.md +83 -0
- package/templates/skills/bridges/fullstack/AGENTS.md.hbs +102 -0
- package/templates/skills/bridges/h5/AGENTS.md +88 -0
- package/templates/skills/bridges/mobile-app/AGENTS.md +100 -0
- package/templates/skills/bridges/website/AGENTS.md +88 -0
- package/templates/skills/copilot-instructions.md +3 -59
- package/templates/skills/hai-ai/SKILL.md +44 -715
- package/templates/skills/hai-ai/guide.md +457 -0
- package/templates/skills/hai-ai/reference.md +292 -0
- package/templates/skills/hai-api-client/SKILL.md +26 -339
- package/templates/skills/hai-api-client/reference.md +180 -0
- package/templates/skills/hai-api-contract/SKILL.md +36 -0
- package/templates/skills/hai-api-contract/reference.md +280 -0
- package/templates/skills/hai-app-create/SKILL.md +38 -351
- package/templates/skills/hai-app-create/collaboration.md +52 -0
- package/templates/skills/hai-app-create/development.md +243 -0
- package/templates/skills/hai-app-create/reference.md +376 -0
- package/templates/skills/hai-app-review/SKILL.md +57 -126
- package/templates/skills/hai-app-review/differential.md +34 -0
- package/templates/skills/hai-app-tests/SKILL.md +34 -454
- package/templates/skills/hai-app-tests/reference.md +462 -0
- package/templates/skills/hai-app-tests/validation.md +42 -0
- package/templates/skills/hai-audit/SKILL.md +37 -122
- package/templates/skills/hai-audit/reference.md +184 -0
- package/templates/skills/hai-build/SKILL.md +62 -315
- package/templates/skills/hai-build/paths.md +30 -0
- package/templates/skills/hai-build/reference.md +353 -0
- package/templates/skills/hai-cache/SKILL.md +26 -175
- package/templates/skills/hai-cache/reference.md +229 -0
- package/templates/skills/hai-capacitor/SKILL.md +24 -364
- package/templates/skills/hai-capacitor/reference.md +358 -0
- package/templates/skills/hai-change-plan/SKILL.md +46 -0
- package/templates/skills/hai-ci/SKILL.md +114 -0
- package/templates/skills/hai-core/SKILL.md +31 -469
- package/templates/skills/hai-core/reference.md +557 -0
- package/templates/skills/hai-core/request-access.md +65 -0
- package/templates/skills/hai-crypto/SKILL.md +29 -180
- package/templates/skills/hai-crypto/reference.md +317 -0
- package/templates/skills/hai-datapipe/SKILL.md +24 -207
- package/templates/skills/hai-datapipe/reference.md +204 -0
- package/templates/skills/hai-deploy/SKILL.md +53 -178
- package/templates/skills/hai-deploy/credentials.md +19 -0
- package/templates/skills/hai-deploy/middleware.md +129 -0
- package/templates/skills/hai-feedback/SKILL.md +85 -0
- package/templates/skills/hai-framework-sync/SKILL.md +105 -0
- package/templates/skills/hai-framework-sync/sync.md +49 -0
- package/templates/skills/hai-iam/SKILL.md +53 -325
- package/templates/skills/hai-iam/reference.md +535 -0
- package/templates/skills/hai-kit/SKILL.md +33 -329
- package/templates/skills/hai-kit/reference.md +202 -0
- package/templates/skills/hai-payment/SKILL.md +28 -262
- package/templates/skills/hai-payment/reference.md +295 -0
- package/templates/skills/hai-pr-review/SKILL.md +41 -0
- package/templates/skills/hai-reach/SKILL.md +28 -300
- package/templates/skills/hai-reach/reference.md +363 -0
- package/templates/skills/hai-reldb/SKILL.md +28 -449
- package/templates/skills/hai-reldb/reference.md +500 -0
- package/templates/skills/hai-scheduler/SKILL.md +26 -174
- package/templates/skills/hai-scheduler/reference.md +216 -0
- package/templates/skills/hai-serv/SKILL.md +60 -0
- package/templates/skills/hai-serv/reference.md +792 -0
- package/templates/skills/hai-spec-implement/SKILL.md +50 -0
- package/templates/skills/hai-spec-implement/changes.md +67 -0
- package/templates/skills/hai-spec-implement/evaluation.md +18 -0
- package/templates/skills/hai-spec-implement/handoff.md +47 -0
- package/templates/skills/hai-spec-implement/templates.md +117 -0
- package/templates/skills/hai-spec-implement/workflow.md +56 -0
- package/templates/skills/hai-spec-review/SKILL.md +57 -0
- package/templates/skills/hai-spec-review/checklist.md +71 -0
- package/templates/skills/hai-storage/SKILL.md +31 -262
- package/templates/skills/hai-storage/reference.md +284 -0
- package/templates/skills/hai-ui/SKILL.md +62 -238
- package/templates/skills/hai-ui/guide.md +81 -0
- package/templates/skills/hai-ui/reference.md +705 -0
- package/templates/skills/hai-ui-design/SKILL.md +31 -0
- package/templates/skills/hai-ui-design/patterns.md +31 -0
- package/templates/skills/hai-ui-review/SKILL.md +32 -0
- package/templates/skills/hai-ui-review/checklist.md +29 -0
- package/templates/skills/hai-vecdb/SKILL.md +25 -267
- package/templates/skills/hai-vecdb/reference.md +325 -0
- package/templates/skills/opencode.json +0 -5
- package/dist/chunk-2H7UOFLK.js +0 -10
- package/dist/chunk-LANIDJC7.js +0 -659
- package/dist/chunk-LANIDJC7.js.map +0 -1
- package/dist/chunk-YV7WPUI6.js +0 -206
- package/dist/chunk-YV7WPUI6.js.map +0 -1
- package/dist/config-templates-S5RI2MC6.js +0 -5
- package/dist/config-templates-S5RI2MC6.js.map +0 -1
- package/dist/skill-templates-N5DU5FNX.js +0 -5
- package/dist/skill-templates-N5DU5FNX.js.map +0 -1
- package/dist/src-XJ6YXNAF.js +0 -15030
- package/dist/src-XJ6YXNAF.js.map +0 -1
- package/templates/apps/android-app/.env.hbs +0 -3
- package/templates/apps/android-app/messages/en-US.json +0 -24
- package/templates/apps/android-app/messages/zh-CN.json +0 -24
- package/templates/apps/android-app/src/lib/api.ts.hbs +0 -30
- package/templates/apps/android-app/src/routes/+layout.svelte.hbs +0 -42
- package/templates/apps/android-app/src/routes/+layout.ts +0 -7
- package/templates/apps/android-app/src/routes/+page.svelte.hbs +0 -27
- package/templates/apps/api/src/routes/+layout.svelte +0 -14
- package/templates/apps/api/src/routes/+page.svelte +0 -11
- package/templates/apps/api/src/routes/api/v1/health/+server.ts +0 -14
- package/templates/apps/api/src/routes/api/v1/items/+server.ts +0 -37
- package/templates/apps/api/src/routes/api/v1/items/[id]/+server.ts +0 -30
- package/templates/base/src/app.css +0 -2
- package/templates/base/tsconfig.json +0 -8
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/** 真实 HTTP、IAM 与持久化验证示例职责及可选再鉴别,不替代浏览器加密验收。 */
|
|
2
|
+
import { once } from 'node:events'
|
|
3
|
+
import { mkdtemp, rm } from 'node:fs/promises'
|
|
4
|
+
import { tmpdir } from 'node:os'
|
|
5
|
+
import path from 'node:path'
|
|
6
|
+
import { apiContract } from '@h-ai/api-contract'
|
|
7
|
+
import { audit } from '@h-ai/audit'
|
|
8
|
+
import { cache } from '@h-ai/cache'
|
|
9
|
+
import { iam } from '@h-ai/iam'
|
|
10
|
+
import { reldb } from '@h-ai/reldb'
|
|
11
|
+
import { serv } from '@h-ai/serv'
|
|
12
|
+
import { storage } from '@h-ai/storage'
|
|
13
|
+
import { AdminUserSchema, {{fullstack.contractExportName}} } from '{{fullstack.contractPackageName}}'
|
|
14
|
+
import { afterAll, beforeAll, expect, it } from 'vitest'
|
|
15
|
+
import { initBusinessSettings } from '../src/server/business-settings.js'
|
|
16
|
+
import { createServerProcedures } from '../src/server/procedures/index.js'
|
|
17
|
+
import { APP_DUTIES, seedAppDuties } from '../src/server/security-roles.js'
|
|
18
|
+
|
|
19
|
+
type Duty = keyof typeof APP_DUTIES
|
|
20
|
+
const actors = new Map<Duty, { token: string, password: string }>()
|
|
21
|
+
const invitations = new Map<string, string>()
|
|
22
|
+
let deliveryUnknown = false
|
|
23
|
+
let directory = ''
|
|
24
|
+
let server: ReturnType<typeof serv.listen> | undefined
|
|
25
|
+
let base = ''
|
|
26
|
+
|
|
27
|
+
beforeAll(async () => {
|
|
28
|
+
directory = await mkdtemp(path.join(tmpdir(), 'hai-app-security-'))
|
|
29
|
+
expect((await reldb.init({ type: 'sqlite', database: ':memory:' })).success).toBe(true)
|
|
30
|
+
expect((await cache.init({ type: 'memory' })).success).toBe(true)
|
|
31
|
+
expect((await storage.init({ type: 'local', root: directory })).success).toBe(true)
|
|
32
|
+
expect((await audit.init({ storage, backup: { enabled: true } })).success).toBe(true)
|
|
33
|
+
expect((await iam.init({
|
|
34
|
+
initialCredentials: { enabled: true },
|
|
35
|
+
passwordReset: { enabled: true, mode: 'email' },
|
|
36
|
+
reauthentication: { enabled: true, operations: ['iam.users.create', 'iam.users.invite', 'iam.users.resetPassword', 'audit.backup', 'business.settings.update'] },
|
|
37
|
+
onPasswordResetRequest: async (user, token) => {
|
|
38
|
+
invitations.set(user.username, token)
|
|
39
|
+
if (deliveryUnknown)
|
|
40
|
+
throw new Error('Notification delivery outcome is unknown')
|
|
41
|
+
},
|
|
42
|
+
})).success).toBe(true)
|
|
43
|
+
expect((await seedAppDuties()).success).toBe(true)
|
|
44
|
+
expect((await initBusinessSettings()).success).toBe(true)
|
|
45
|
+
for (const code of Object.keys(APP_DUTIES) as Duty[]) {
|
|
46
|
+
const password = `Example-${code}-123!`
|
|
47
|
+
const user = await iam.user.createUser({ username: code, password })
|
|
48
|
+
const role = await iam.authz.getRoleByCode(code)
|
|
49
|
+
if (!user.success || !role.success || !role.data)
|
|
50
|
+
throw new Error('Missing security actor fixture')
|
|
51
|
+
expect((await iam.authz.syncRoles(user.data.user.id, [role.data.id])).success).toBe(true)
|
|
52
|
+
const signedIn = await iam.auth.login({ identifier: code, password })
|
|
53
|
+
if (!signedIn.success)
|
|
54
|
+
throw new Error(signedIn.error.message)
|
|
55
|
+
actors.set(code, { token: signedIn.data.tokens.accessToken, password })
|
|
56
|
+
}
|
|
57
|
+
const app = serv.createApp({
|
|
58
|
+
contract: {{fullstack.contractExportName}},
|
|
59
|
+
procedures: createServerProcedures({ app: { name: 'Security fixture', version: 'test', env: 'test', defaultLocale: 'en-US', supportedLocales: ['en-US'], startedAt: new Date().toISOString(), frontends: ['web'] } }),
|
|
60
|
+
iam,
|
|
61
|
+
http: { openapi: false, docs: false, rpc: false },
|
|
62
|
+
})
|
|
63
|
+
server = serv.listen(app, { host: '127.0.0.1', port: 0 })
|
|
64
|
+
if (!server.server.listening)
|
|
65
|
+
await once(server.server, 'listening')
|
|
66
|
+
const address = server.server.address()
|
|
67
|
+
if (!address || typeof address === 'string')
|
|
68
|
+
throw new Error('Missing security server address')
|
|
69
|
+
base = `http://127.0.0.1:${address.port}/api/v1`
|
|
70
|
+
}, 30000)
|
|
71
|
+
|
|
72
|
+
afterAll(async () => {
|
|
73
|
+
try {
|
|
74
|
+
await server?.close()
|
|
75
|
+
await iam.close()
|
|
76
|
+
await audit.close()
|
|
77
|
+
await storage.close()
|
|
78
|
+
await cache.close()
|
|
79
|
+
await reldb.close()
|
|
80
|
+
}
|
|
81
|
+
finally {
|
|
82
|
+
if (directory)
|
|
83
|
+
await rm(directory, { recursive: true, force: true })
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
function actor(code: Duty) {
|
|
88
|
+
const value = actors.get(code)
|
|
89
|
+
if (!value)
|
|
90
|
+
throw new Error('Missing security actor')
|
|
91
|
+
return value
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function proof(code: Duty, operation: string) {
|
|
95
|
+
const value = actor(code)
|
|
96
|
+
const result = await iam.auth.reauthenticate(value.token, value.password, operation)
|
|
97
|
+
if (!result.success)
|
|
98
|
+
throw new Error(result.error.message)
|
|
99
|
+
return result.data.ticket
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function post(code: Duty, route: string, input: object = {}, ticket?: string) {
|
|
103
|
+
return fetch(`${base}${route}`, { method: 'POST', headers: { 'content-type': 'application/json', 'authorization': `Bearer ${actor(code).token}`, ...(ticket ? { 'x-hai-reauthentication': ticket } : {}) }, body: JSON.stringify(input) })
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
it('系统、审计、配置与业务职责的直接 HTTP 请求各有边界', async () => {
|
|
107
|
+
expect(await (await post('audit_admin', '/admin/users/list')).json()).toMatchObject({ success: false, error: { httpStatus: 403 } })
|
|
108
|
+
expect(await (await post('admin', '/admin/audit/list')).json()).toMatchObject({ success: false, error: { httpStatus: 403 } })
|
|
109
|
+
expect(await (await post('admin', '/admin/configuration/update', { notice: 'Rejected' })).json()).toMatchObject({ success: false, error: { httpStatus: 403 } })
|
|
110
|
+
expect(await (await post('business_operator', '/admin/users/list')).json()).toMatchObject({ success: false, error: { httpStatus: 403 } })
|
|
111
|
+
const ticket = await proof('config_admin', 'business.settings.update')
|
|
112
|
+
expect(await (await post('config_admin', '/admin/configuration/update', { notice: 'Authorized public notice' }, ticket)).json()).toMatchObject({ success: true })
|
|
113
|
+
const info = await fetch(`${base}/app/info`, { method: 'POST' })
|
|
114
|
+
expect(await info.json()).toMatchObject({ success: true, data: { notice: 'Authorized public notice' } })
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('再鉴别按用途单次使用,临时账号状态变化立即阻止旧会话', async () => {
|
|
118
|
+
const input = { username: 'temporary-member', password: 'Temporary-example-123!', role: 'user', accountType: 'temporary', accountExpiresAt: new Date(Date.now() + 3600000).toISOString() }
|
|
119
|
+
expect(await (await post('admin', '/admin/users/create', input)).json()).toMatchObject({ success: false, error: { code: 'hai:iam:027' } })
|
|
120
|
+
const ticket = await proof('admin', 'iam.users.create')
|
|
121
|
+
const response = await post('admin', '/admin/users/create', input, ticket)
|
|
122
|
+
const created = apiContract.haiResultSchema(AdminUserSchema).parse(await response.json())
|
|
123
|
+
expect(created.success).toBe(true)
|
|
124
|
+
if (!created.success)
|
|
125
|
+
return
|
|
126
|
+
expect(created.data.accountType).toBe('temporary')
|
|
127
|
+
expect(await (await post('admin', '/admin/users/create', { ...input, username: 'replayed-member' }, ticket)).json()).toMatchObject({ success: false })
|
|
128
|
+
const login = await iam.auth.login({ identifier: input.username, password: input.password })
|
|
129
|
+
if (!login.success)
|
|
130
|
+
throw new Error(login.error.message)
|
|
131
|
+
expect(await (await post('admin', '/admin/users/update', { id: created.data.id, accountStatus: 'dormant' })).json()).toMatchObject({ success: true })
|
|
132
|
+
expect((await iam.auth.verifyToken(login.data.tokens.accessToken)).success).toBe(false)
|
|
133
|
+
expect((await iam.session.refresh(login.data.tokens.refreshToken)).success).toBe(false)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('设密邀请可完成,投递未知时保留账号;系统管理员可创建其他职责账号', async () => {
|
|
137
|
+
const createdDuty = await post('admin', '/admin/users/create', { username: 'managed-auditor', password: 'Example-123!', role: 'audit_admin' }, await proof('admin', 'iam.users.create'))
|
|
138
|
+
expect(await createdDuty.json()).toMatchObject({ success: true, data: { roles: ['audit_admin'] } })
|
|
139
|
+
const invite = await post('admin', '/admin/users/invite', { username: 'invited-member', email: 'member@example.test' }, await proof('admin', 'iam.users.invite'))
|
|
140
|
+
expect(await invite.json()).toMatchObject({ success: true })
|
|
141
|
+
const token = invitations.get('invited-member')
|
|
142
|
+
expect(token).toBeTruthy()
|
|
143
|
+
expect((await iam.user.confirmPasswordReset(token!, 'Invited-example-123!')).success).toBe(true)
|
|
144
|
+
expect((await iam.auth.login({ identifier: 'invited-member', password: 'Invited-example-123!' })).success).toBe(true)
|
|
145
|
+
deliveryUnknown = true
|
|
146
|
+
try {
|
|
147
|
+
const unknown = await post('admin', '/admin/users/invite', { username: 'delivery-unknown-member', email: 'unknown@example.test' }, await proof('admin', 'iam.users.invite'))
|
|
148
|
+
expect(await unknown.json()).toMatchObject({ success: false, error: { code: 'hai:iam:028' } })
|
|
149
|
+
const found = await iam.user.listUsers({ search: 'delivery-unknown-member' })
|
|
150
|
+
expect(found).toMatchObject({ success: true, data: { total: 1 } })
|
|
151
|
+
}
|
|
152
|
+
finally { deliveryUnknown = false }
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('只有审计职责可手动备份且私有归档可验证', async () => {
|
|
156
|
+
const id = crypto.randomUUID()
|
|
157
|
+
expect(await (await post('admin', '/admin/audit/backup', { id })).json()).toMatchObject({ success: false, error: { httpStatus: 403 } })
|
|
158
|
+
const result = await post('audit_admin', '/admin/audit/backup', { id }, await proof('audit_admin', 'audit.backup'))
|
|
159
|
+
const body: unknown = await result.json()
|
|
160
|
+
expect(body).toMatchObject({ success: true, data: { id, key: expect.stringContaining('hai-private/audit-backups/'), sha256: expect.stringMatching(/^[a-f\d]{64}$/) } })
|
|
161
|
+
const verified = await audit.backup.verify(`hai-private/audit-backups/${id}.jsonl`)
|
|
162
|
+
expect(verified.success).toBe(true)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it.each(['admin', 'audit_admin', 'config_admin', 'business_operator', 'user'] as const)('系统管理员统一管理 %s 的资料、生命周期、角色和密码', async (role) => {
|
|
166
|
+
const username = `managed-${role}`
|
|
167
|
+
const created = apiContract.haiResultSchema(AdminUserSchema).parse(await (await post('admin', '/admin/users/create', { username, password: 'Managed-example-123!', role }, await proof('admin', 'iam.users.create'))).json())
|
|
168
|
+
expect(created).toMatchObject({ success: true, data: { roles: [role], accountStatus: 'active' } })
|
|
169
|
+
if (!created.success)
|
|
170
|
+
throw new Error('Managed account fixture failed')
|
|
171
|
+
const input = { id: created.data.id, displayName: 'Managed profile', accountStatus: 'dormant', role: 'user' }
|
|
172
|
+
expect(await (await post('admin', '/admin/users/update', input)).json()).toMatchObject({ success: true, data: { displayName: 'Managed profile', roles: ['user'], accountStatus: 'dormant' } })
|
|
173
|
+
const reset = { id: created.data.id, newPassword: 'Reset-example-456!' }
|
|
174
|
+
expect(await (await post('admin', '/admin/users/reset-password', reset)).json()).toMatchObject({ success: false, error: { code: 'hai:iam:027' } })
|
|
175
|
+
const ticket = await proof('admin', 'iam.users.resetPassword')
|
|
176
|
+
expect(await (await post('admin', '/admin/users/reset-password', reset, ticket)).json()).toMatchObject({ success: true, data: { reset: true } })
|
|
177
|
+
expect(await (await post('admin', '/admin/users/reset-password', reset, ticket)).json()).toMatchObject({ success: false })
|
|
178
|
+
expect(await iam.user.getUser(created.data.id)).toMatchObject({ success: true, data: { accountStatus: 'dormant' } })
|
|
179
|
+
expect(await iam.auth.login({ identifier: username, password: reset.newPassword })).toMatchObject({ success: false, error: { code: 'hai:iam:002' } })
|
|
180
|
+
expect(await (await post('admin', '/admin/users/update', { id: created.data.id, accountStatus: 'active' })).json()).toMatchObject({ success: true })
|
|
181
|
+
expect((await iam.auth.login({ identifier: username, password: reset.newPassword })).success).toBe(true)
|
|
182
|
+
expect(await (await post('audit_admin', '/admin/users/reset-password', reset)).json()).toMatchObject({ success: false, error: { httpStatus: 403 } })
|
|
183
|
+
})
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { writeFile } from 'node:fs/promises'
|
|
2
|
+
import { fileURLToPath } from 'node:url'
|
|
3
|
+
import { defineConfig } from 'tsup'
|
|
4
|
+
import { resolveBuildMetadata } from '../../scripts/build-metadata.js'
|
|
5
|
+
|
|
6
|
+
const buildMetadata = resolveBuildMetadata(fileURLToPath(new URL('.', import.meta.url)))
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
define: { __HAI_BUILD_METADATA__: JSON.stringify(buildMetadata) },
|
|
10
|
+
async onSuccess() {
|
|
11
|
+
await writeFile(new URL('./dist/build-metadata.json', import.meta.url), JSON.stringify(buildMetadata))
|
|
12
|
+
},
|
|
13
|
+
entry: ['src/index.ts'],
|
|
14
|
+
format: ['esm'],
|
|
15
|
+
dts: { compilerOptions: { ignoreDeprecations: '6.0' } },
|
|
16
|
+
sourcemap: true,
|
|
17
|
+
clean: true,
|
|
18
|
+
})
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url'
|
|
2
|
+
import { defineConfig } from 'vitest/config'
|
|
3
|
+
import { resolveBuildMetadata } from '../../scripts/build-metadata.js'
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
define: { __HAI_BUILD_METADATA__: JSON.stringify(resolveBuildMetadata(fileURLToPath(new URL('.', import.meta.url)))) },
|
|
7
|
+
test: {
|
|
8
|
+
globals: true,
|
|
9
|
+
environment: 'node',
|
|
10
|
+
include: ['tests/**/*.test.ts'],
|
|
11
|
+
},
|
|
12
|
+
})
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# {{fullstack.sharedPackageName}}
|
|
2
|
+
|
|
3
|
+
## Introduction
|
|
4
|
+
|
|
5
|
+
Shared mini administration workspace for **{{projectName}}**. Web, Capacitor App and Tauri desktop use the same `AdminWorkspace`, responsive `AppShell`, typed API client and management store.
|
|
6
|
+
|
|
7
|
+
## Core features
|
|
8
|
+
|
|
9
|
+
- Shared management pages, forms, navigation and application state.
|
|
10
|
+
- Typed encrypted API client and platform-specific token storage.
|
|
11
|
+
- Themes, language preferences, onboarding and help.
|
|
12
|
+
|
|
13
|
+
## Getting started
|
|
14
|
+
|
|
15
|
+
### Behavior and configuration
|
|
16
|
+
|
|
17
|
+
The behavior below describes the initial example. Roles, permissions, workflows, limits, preferences and audit policies can change with the user's requirements. Update conflicting implementation, tests and guidance together; preserve the applicable public API contracts and server security checks.
|
|
18
|
+
|
|
19
|
+
- Administrators manage users, upload user avatars, assign the built-in administrator/user roles, edit role descriptions and query audit logs.
|
|
20
|
+
- By default, ordinary users update their own profile, avatar, language, appearance and password. The server enforces the actual business permissions on every request.
|
|
21
|
+
- The workspace uses the available window width. Tables scroll within their own area; settings panels form two columns on large screens and stack on phones.
|
|
22
|
+
- `ManagementStore` owns API calls and business state; components render the state and forward user interactions.
|
|
23
|
+
- Application name, version, environment and default locale come from the backend `app.info` contract, which reads `core` configuration. Do not duplicate these values in translations or frontend constants.
|
|
24
|
+
- Requests, token refresh and JSON responses use the same `@h-ai/api-client` + `@h-ai/crypto` transport. Avatar uploads use encrypted JSON and validate PNG/JPEG/WebP content, with a 512 KiB limit.
|
|
25
|
+
- Read metadata through the same initialized `managementApi.app.info()` client; inspect `success` before using `data`.
|
|
26
|
+
|
|
27
|
+
Vite development and preview servers read the workspace root environment files and proxy /api to the backend. Builds do not load deployment environment files. Web containers receive their public API address at startup; native apps follow the platform configuration below.
|
|
28
|
+
|
|
29
|
+
An origin-only API base uses `/api/v1`. For a custom service `http.apiPrefix`, include that path in `PUBLIC_API_BASE` or the runtime API base; the client preserves the configured path and restricts avatar URLs to its matching resource prefix.
|
|
30
|
+
|
|
31
|
+
### Configurable security and duties
|
|
32
|
+
|
|
33
|
+
System administrators manage accounts and roles, auditors query/export private audit archives, configuration staff maintain the public notice, and business operators process feedback. Basic members retain self-serv access. Navigation and server permissions follow the same application-owned duties. Management forms support temporary account expiry and active/dormant/closed states; optional invitations use one-time password setup notifications. `ReauthenticationDialog` collects confirmation for configured operations through the service layer, and proofs are passed only to the corresponding API call. Audit pages expose category/outcome/severity filters, sorting, seven-day statistics and private backup receipts. Page-exit revocation is optional and best effort; combine it with server idle/absolute deadlines.
|
|
34
|
+
|
|
35
|
+
### Authentication and preferences
|
|
36
|
+
|
|
37
|
+
Web and browser previews keep access tokens in memory and refresh tokens in the server's httpOnly Cookie. Requests include credentials; reload restores the session through the encrypted refresh flow. Never store authentication tokens in localStorage.
|
|
38
|
+
|
|
39
|
+
Capacitor native uses `createCapacitorTokenStorage()` and the trusted native token channel. Set its public API address in the App's `public/runtime-config.js` before compiling and syncing native assets. Tauri uses memory token storage and requires a new login after restart; set process `PUBLIC_API_BASE` before launching the installed application, and its Rust host injects the address. Both send `clientName` and `X-HAI-Token-Transport: body`; the service verifies the trusted native origin before returning a refresh token in JSON. Capacitor requires explicit API configuration. The Tauri host defaults to http://localhost:3000/api/v1 when PUBLIC_API_BASE is absent; configure the actual service address for installed applications. A configured address does not prove connectivity.
|
|
40
|
+
|
|
41
|
+
Language and theme preferences are saved in IAM user metadata, restored after login and synchronized with the shared/host Paraglide runtimes and `core.i18n`. The small reactive theme store delegates DOM updates and safe appearance caching to `@h-ai/ui/theme` (`applyTheme` / `getSavedTheme`); the framework uses the `theme` localStorage key. Appearance selectors live in personal settings and save through the authenticated profile contract.
|
|
42
|
+
|
|
43
|
+
### Onboarding and help
|
|
44
|
+
|
|
45
|
+
AdminWorkspace mounts the shared `@h-ai/ui/guide` controller and GuideHost after authentication. AppShell includes a help button; first-use invitations offer start, later and dismiss. Web stores preferences in Cookies, while App/Desktop use localStorage, scoped by the current user and tour version. Help articles link to the overview and profile tours.
|
|
46
|
+
|
|
47
|
+
Extend `src/lib/stores/guide-store.ts` and the shared Chinese/English/Japanese messages, then add stable data-guide attributes to existing components. Navigation uses the same ManagementStore. Keep business text as i18n callbacks and preserve the host's locale/scope binding. Browser tests cover completion, reload, replay, settings navigation and mobile help.
|
|
48
|
+
|
|
49
|
+
### i18n and themes
|
|
50
|
+
|
|
51
|
+
Shared page copy belongs in `messages/{zh-CN,en-US,ja-JP}.json`. Frontend-specific copy belongs in each app's own messages directory. Keep `baseLocale` and `locales` aligned across all enabled projects, then run root `pnpm i18n:compile`; do not edit generated Paraglide files.
|
|
52
|
+
|
|
53
|
+
All frontend and shared projects load the installed message-format plugin from the workspace root `node_modules`, matching the scaffold's hoisted dependency layout. Compilation uses the workspace dependency version and does not fetch a plugin from a CDN.
|
|
54
|
+
|
|
55
|
+
The scaffold theme configuration determines the themes compiled into frontend CSS. Personal settings offer only those available themes. Customize the common layout in `src/lib/components/AppShell.svelte`, the management pages in adjacent components, and business behavior in `src/lib/stores/management-store.svelte.ts`.
|
|
56
|
+
|
|
57
|
+
### Validation
|
|
58
|
+
|
|
59
|
+
Run root `pnpm typecheck`, `pnpm lint`, `pnpm build`, `pnpm test` and `pnpm test:e2e`. Shared API tests exercise real transport key exchange, encrypted request/response handling, configured core metadata and credential forwarding. Root browser tests cover administrator and ordinary-user workflows, avatar rendering, persisted preferences, password/session invalidation and narrow-screen layout. All selected Web/App/Desktop previews also exercise login, tours, help and profile navigation. Clean screenshots, reports, temporary projects, containers and helper processes in finally/teardown, including failure paths. These browser checks do not replace native-shell or miniapp device acceptance.
|
|
60
|
+
|
|
61
|
+
### IAM configuration
|
|
62
|
+
|
|
63
|
+
The service's `config/_iam.yml` controls login methods, registration, password reset, agreements and `ui` branding. Email and SMS use providers/templates in `_reach.yml` or custom callbacks. `AuthPanel` uses the public configuration and framework auth actions to manage tokens, resend countdowns and errors. Memory cache is for local development and explicit tests. Production requires supported shared database/cache backends even with one instance, write routing and a shared managed transport key ring and registry as described in the project README.
|
|
64
|
+
|
|
65
|
+
Authentication defaults to a split layout. Set `ui.variant`, `title`, `subtitle`, `brandTitle`, `brandText`, `logoUrl` and `illustrationUrl` to customize login and registration. Without a `brandTitle`, the displayed application name comes from `app.info` and follows `core` configuration.
|
|
66
|
+
|
|
67
|
+
LDAP and Reach are optional. Install ldapts in the IAM service workspace only when using its default LDAP client, then enable login.ldap and set connection settings. Custom onOtpSendEmail/onOtpSendSms/onPasswordResetRequest callbacks work without Reach and must reject on delivery failure. Their third context argument supplies expiresAt/idempotencyKey; senders durably deduplicate that key, and errors/timeouts mean unknown delivery with no automatic resend. Agreements open in a Modal. LoginForm/RegisterForm support header/extraFields/footer snippets; AuthPanel forwards loginHeader/loginFields/loginFooter and registerHeader/registerFields/registerFooter. See the generated hai-iam/hai-ui skills for configuration and examples.
|
|
68
|
+
|
|
69
|
+
Agreements accept Markdown text or a URL. Markdown takes precedence and opens in a safely rendered dialog.
|
|
70
|
+
|
|
71
|
+
See `.agents/skills/hai-iam/reference.md` in the generated application for the complete contract.
|
|
72
|
+
|
|
73
|
+
### Operation feedback
|
|
74
|
+
|
|
75
|
+
Operation results use the shared `toast` queue from the lightweight `@h-ai/ui/toast` entry. `AdminWorkspace` mounts one `ToastContainer` for Web, App and Desktop: notifications float at the bottom right by default, use UI-owned semantic colors for information, success, warning and error, with a soft tinted background, a narrow color border and a distinct icon, close automatically or manually, and appear one at a time in FIFO order. Waiting notifications do not expire before being shown. Set `position` in `toast.add` for any of the six supported positions. Field validation and persistent business state stay inline.
|
|
76
|
+
|
|
77
|
+
### Form layouts
|
|
78
|
+
|
|
79
|
+
The user editor uses `FormLayout columns={2} labelPosition="left"`. Personal settings fill the available width and use two columns on wide screens, with stacked labels and a single avatar editor. Narrow containers automatically stack cards, fields and labels. UI controls and CRUD forms show client validation on blur, update errors while correcting input and validate untouched fields on submit. Field errors follow the current UI language. The management store syncs locale through the lightweight `@h-ai/ui/i18n` entry, without loading components or tour CSS. Configure `colSpan` on FormField to override automatic spans for textareas, uploads and multiple choices.
|
|
80
|
+
|
|
81
|
+
## 界面设计与验收
|
|
82
|
+
|
|
83
|
+
共享管理界面的 Web/App/Desktop 使用同一套 UI 组件和状态。设计、实现、审查分别参考根目录 `.agents/skills/hai-ui-design/`、`hai-ui/`、`hai-ui-review/`;正常、加载、空态、错误恢复、键盘、语言/主题和窄容器均按实际场景验收。组件的筛选、排序和分页仍由业务数据回调接入。
|
|
84
|
+
|
|
85
|
+
## 反馈现场与交付检查
|
|
86
|
+
|
|
87
|
+
feedback.init(config, { collectEvidence }) 支持等待业务 text/data 与文本/ZIP/GZIP 附件;_feedback.yml 提供业务采集超时和 Webhook URL/签名密钥/请求超时。密钥仅放服务端私有环境。Webhook 持久重试,详情展示状态并允许管理员重试。
|
|
88
|
+
|
|
89
|
+
反馈的 console/disabled/reach 独立选择;SDK getView/ratio/saveDraft 与 createFeedbackReview 统一预览、标注、保存及轮询。退出身份清理草稿和观察器。宿主生命周期由 core.module.createRuntime 处理,框架表升级前备份停旧写入并运行各模块 dryRun 预检。
|
|
90
|
+
|
|
91
|
+
## Development and testing
|
|
92
|
+
|
|
93
|
+
Run root `pnpm typecheck`, `pnpm lint`, `pnpm build`, `pnpm test` and `pnpm test:e2e`. Browser checks cover shared workflows; test native shells on their target platforms separately.
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
Apache-2.0
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
{{! @skipIfEmpty }}
|
|
2
|
+
{
|
|
3
|
+
"$schema": "https://inlang.com/schema/inlang-message-format",
|
|
4
|
+
"settings_title": "Personal settings",
|
|
5
|
+
"settings_language": "Language",
|
|
6
|
+
"settings_theme": "Theme",
|
|
7
|
+
"theme_high_contrast": "High contrast",
|
|
8
|
+
"theme_formal": "Formal",
|
|
9
|
+
"home_refresh": "Refresh",
|
|
10
|
+
"home_loading": "Loading…",
|
|
11
|
+
"home_error": "Unable to reach the API service",
|
|
12
|
+
"business_settings_title": "Business configuration",
|
|
13
|
+
"business_notice_label": "Public business notice",
|
|
14
|
+
"business_notice_hint": "All users can read this notice. Do not include sensitive information.",
|
|
15
|
+
"security_sensitive_operations": "Sensitive operations",
|
|
16
|
+
"security_action_cancelled": "Sensitive action cancelled.",
|
|
17
|
+
"account_type": "Account type",
|
|
18
|
+
"account_permanent": "Permanent",
|
|
19
|
+
"account_temporary": "Temporary",
|
|
20
|
+
"account_state": "Account state",
|
|
21
|
+
"account_active": "Active",
|
|
22
|
+
"account_dormant": "Dormant",
|
|
23
|
+
"account_closed": "Closed",
|
|
24
|
+
"account_expires": "Expires at",
|
|
25
|
+
"account_last_login": "Last login",
|
|
26
|
+
"invitation_title": "Invite user to set password",
|
|
27
|
+
"invitation_hint": "Send a one-time password setup link without displaying or sharing an initial password.",
|
|
28
|
+
"invitation_send": "Send invitation",
|
|
29
|
+
"invitation_check_existing": "Check the user list and delivery records before retrying; the account may already exist.",
|
|
30
|
+
"invitation_default_role": "Default business operator",
|
|
31
|
+
"invitation_phone": "Phone number",
|
|
32
|
+
"audit_category": "Category",
|
|
33
|
+
"audit_outcome": "Outcome",
|
|
34
|
+
"audit_severity": "Severity",
|
|
35
|
+
"audit_category_system": "System events",
|
|
36
|
+
"audit_category_business": "Business events",
|
|
37
|
+
"audit_success": "Success",
|
|
38
|
+
"audit_failure": "Failure",
|
|
39
|
+
"audit_denied": "Denied",
|
|
40
|
+
"audit_info": "Info",
|
|
41
|
+
"audit_warning": "Warning",
|
|
42
|
+
"audit_error": "Error",
|
|
43
|
+
"audit_critical": "Critical",
|
|
44
|
+
"audit_all": "All",
|
|
45
|
+
"audit_backup_run": "Back up audit records",
|
|
46
|
+
"audit_backup_private_hint": "Archive saved to private server storage. Retrieve and verify it using the archive key.",
|
|
47
|
+
"audit_backup_retry_hint": "Retry verifies the same archive ID. Avoid starting duplicate jobs with different IDs.",
|
|
48
|
+
"audit_stats_hint": "Last 7 days grouped by action, filtered by category, outcome, severity and resource.",
|
|
49
|
+
"audit_advanced_filters": "Classification, sorting and statistics",
|
|
50
|
+
"audit_sort_direction": "Sort direction",
|
|
51
|
+
"audit_request_id": "Request ID",
|
|
52
|
+
"audit_trace_id": "Trace ID",
|
|
53
|
+
"audit_scope": "Business scope",
|
|
54
|
+
"audit_actor_snapshot": "Event identity snapshot",
|
|
55
|
+
"audit_asc": "Ascending",
|
|
56
|
+
"audit_desc": "Descending",
|
|
57
|
+
"audit_sort": "Sort by",
|
|
58
|
+
"nav_users": "Users",
|
|
59
|
+
"nav_roles": "Roles",
|
|
60
|
+
"nav_audit": "Audit logs",
|
|
61
|
+
"nav_feedback": "Feedback",
|
|
62
|
+
"feedback_logs": "Logs and requests",
|
|
63
|
+
"feedback_export_pending": "The feedback bundle is still being generated. Please retry shortly.",
|
|
64
|
+
"navigation": "Main navigation",
|
|
65
|
+
"open_menu": "Open navigation",
|
|
66
|
+
"close_menu": "Close navigation",
|
|
67
|
+
"logout": "Sign out",
|
|
68
|
+
"login_title": "Sign in",
|
|
69
|
+
"login_description": "Sign in to manage your account and workspace",
|
|
70
|
+
"login_invalid": "The account or password is incorrect. Please try again.",
|
|
71
|
+
"session_expired": "Your session has expired. Please sign in again.",
|
|
72
|
+
"saved": "Changes saved",
|
|
73
|
+
"save": "Save",
|
|
74
|
+
"edit": "Edit",
|
|
75
|
+
"delete": "Delete",
|
|
76
|
+
"cancel": "Cancel",
|
|
77
|
+
"search": "Search",
|
|
78
|
+
"details": "Details",
|
|
79
|
+
"created_at": "Created at",
|
|
80
|
+
"all_statuses": "All statuses",
|
|
81
|
+
"operation_failed": "The operation could not be completed. Please try again.",
|
|
82
|
+
"network_error": "Connection failed. Check your network and try again.",
|
|
83
|
+
"forbidden": "You do not have permission to perform this operation.",
|
|
84
|
+
"conflict": "This account already exists or the change conflicts with the current data.",
|
|
85
|
+
"validation_failed": "Check the information entered and try again.",
|
|
86
|
+
"settings_description": "Manage your profile, preferences and account security",
|
|
87
|
+
"profile_title": "Profile",
|
|
88
|
+
"preferences_title": "Preferences",
|
|
89
|
+
"preferences_description": "Your language and appearance preferences follow your account across devices.",
|
|
90
|
+
"password_title": "Change password",
|
|
91
|
+
"password_rules": "Choose a different password.",
|
|
92
|
+
"password_changed": "Password updated. Please sign in with your new password.",
|
|
93
|
+
"password_current_required": "Enter your current password before changing it.",
|
|
94
|
+
"password_confirmation_mismatch": "The new passwords do not match. Enter the same password in both fields.",
|
|
95
|
+
"avatar_hint": "Upload a PNG, JPEG or WebP image, up to 512 KB.",
|
|
96
|
+
"avatar_invalid": "Choose a PNG, JPEG or WebP image no larger than 512 KB.",
|
|
97
|
+
"avatar_saved": "Avatar updated",
|
|
98
|
+
"avatar_upload": "Upload avatar",
|
|
99
|
+
"users_description": "Create accounts, assign roles and manage access",
|
|
100
|
+
"users_search": "Search username, name or email",
|
|
101
|
+
"user_account": "Account",
|
|
102
|
+
"user_username": "Username",
|
|
103
|
+
"user_display_name": "Display name",
|
|
104
|
+
"user_email": "Email",
|
|
105
|
+
"user_password": "Initial password",
|
|
106
|
+
"user_role": "Role",
|
|
107
|
+
"user_create": "Add user",
|
|
108
|
+
"initial_password_rules": "Use at least {min} characters.",
|
|
109
|
+
"users_empty": "No matching accounts. Try another search or create a user.",
|
|
110
|
+
"user_edit": "Edit user",
|
|
111
|
+
"user_deleted": "User deleted",
|
|
112
|
+
"user_delete_title": "Delete user",
|
|
113
|
+
"user_delete_confirm": "Delete {name}? This permanently removes the account and its access.",
|
|
114
|
+
"roles_description": "Separate permissions by responsibility. Assign roles from user management.",
|
|
115
|
+
"role_admin": "System administrator",
|
|
116
|
+
"role_audit": "Audit administrator",
|
|
117
|
+
"role_config": "Configuration administrator",
|
|
118
|
+
"role_audit_capabilities": "Read, aggregate and back up audit records without account or business configuration management.",
|
|
119
|
+
"role_config_capabilities": "Manage business configuration without account or audit administration.",
|
|
120
|
+
"role_operator": "Business operator",
|
|
121
|
+
"role_operator_capabilities": "Use business workflows without account, audit or configuration administration.",
|
|
122
|
+
"role_user": "User",
|
|
123
|
+
"role_admin_capabilities": "Manage system accounts and roles without audit or business configuration access.",
|
|
124
|
+
"role_user_capabilities": "Update personal profile, avatar, language, appearance and password.",
|
|
125
|
+
"role_members": "{count} members",
|
|
126
|
+
"role_edit": "Edit description",
|
|
127
|
+
"role_description": "Description",
|
|
128
|
+
"audit_description": "Review account and administration activity",
|
|
129
|
+
"audit_actor": "Actor",
|
|
130
|
+
"audit_action": "Action",
|
|
131
|
+
"audit_resource": "Resource",
|
|
132
|
+
"audit_resource_id": "Resource ID",
|
|
133
|
+
"audit_ip": "IP address",
|
|
134
|
+
"audit_start": "From",
|
|
135
|
+
"audit_end": "To",
|
|
136
|
+
"audit_action_placeholder": "All actions",
|
|
137
|
+
"audit_resource_placeholder": "All resources",
|
|
138
|
+
"audit_system": "System",
|
|
139
|
+
"audit_details": "Audit log details",
|
|
140
|
+
"audit_date_invalid": "The end date must be on or after the start date.",
|
|
141
|
+
"api_not_configured": "The service connection is not configured. Please contact your administrator.",
|
|
142
|
+
"guide_overview_title": "Explore your admin workspace",
|
|
143
|
+
"guide_overview_description": "A few short steps introduce the workspace, personal settings and help. Leave at any time and replay tours from the help center.",
|
|
144
|
+
"guide_content_title": "Workspace",
|
|
145
|
+
"guide_content_description": "The current page appears here. Use navigation to switch features. Available actions depend on your permissions.",
|
|
146
|
+
"guide_theme_title": "Appearance",
|
|
147
|
+
"guide_theme_description": "Switch between light and dark appearances here. More themes are available in settings.",
|
|
148
|
+
"guide_profile_title": "Your profile",
|
|
149
|
+
"guide_profile_description": "Use your avatar to access your profile and settings, including personal information and passwords.",
|
|
150
|
+
"guide_help_title": "Help center",
|
|
151
|
+
"guide_help_description": "Search instructions here whenever you need help, or replay a product tour.",
|
|
152
|
+
"guide_profile_tour_title": "Set up your profile",
|
|
153
|
+
"guide_profile_tour_description": "Find your personal information, preferences and password settings. This tour explains actions without submitting changes.",
|
|
154
|
+
"guide_profile_form_description": "View or edit your profile, choose an avatar and save your changes. Uploaded files must meet the format and size requirements shown on the page.",
|
|
155
|
+
"guide_preferences_description": "Save your preferred language and theme. The interface and help content follow your selection.",
|
|
156
|
+
"guide_password_title": "Change password",
|
|
157
|
+
"guide_password_description": "Enter your current password, new password and confirmation. Check the password rules before submitting.",
|
|
158
|
+
"guide_overview_article": "## Getting started\n\n- Open features through navigation. Menus and actions depend on your current permissions.\n- The workspace contains lists, details or settings. Follow the page instructions and check information before submitting.\n- Use your avatar to access your profile and settings.\n- Search instructions or replay tours through the help button.\n\n## First-use tour\n\n“Remind me later” pauses reminders for one day. “Do not remind me” saves your preference. Completed tours no longer prompt automatically and remain available for manual replay.",
|
|
159
|
+
"guide_profile_article": "## Profile and preferences\n\nOpen your profile to view or update personal information and your avatar. Check the file requirements, save changes and read the result message. Appearance and language can be adjusted in settings.\n\n## Password\n\nChanging a password requires the current password, new password and confirmation. Follow the displayed password rules and check the result after submitting.\n\n“Start tour” opens the relevant page. Tours never save forms or change your account automatically.",
|
|
160
|
+
"user_password_reset": "Reset password",
|
|
161
|
+
"user_password_reset_hint": "Set a new password for {name}. Existing sessions will end and account status stays the same. Deliver the new password through a secure channel.",
|
|
162
|
+
"user_password_reset_done": "Password reset and existing sessions ended. Deliver the new password securely.",
|
|
163
|
+
"user_password_reset_initial_hint": "Initial password change is required: the user must choose their own password at the next sign-in."
|
|
164
|
+
}
|