@nakedev/go-scaffold 0.1.2 → 0.1.4
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 +93 -14
- package/dist/commands/auth.js +129 -0
- package/dist/commands/create.js +3 -2
- package/dist/commands/generate.js +61 -2
- package/dist/commands/method.js +66 -15
- package/dist/commands/migration.js +34 -0
- package/dist/commands/rbac.js +103 -0
- package/dist/commands/remove.js +36 -20
- package/dist/commands/worker.js +75 -0
- package/dist/index.js +71 -7
- package/dist/prompts/create-wizard.js +6 -1
- package/dist/prompts/generate-wizard.js +8 -0
- package/dist/templates/auth-manifest.js +19 -0
- package/dist/templates/create-manifest.js +25 -0
- package/dist/templates/module-manifest.js +2 -0
- package/dist/templates/rbac-manifest.js +17 -0
- package/dist/templates/worker-manifest.js +12 -0
- package/dist/utils/auth-patcher.js +96 -0
- package/dist/utils/gocheck.js +65 -0
- package/dist/utils/main-patcher.js +8 -1
- package/dist/utils/method-patcher.js +80 -16
- package/dist/utils/migrations.js +30 -8
- package/dist/utils/module-location.js +22 -0
- package/dist/utils/naming.js +75 -12
- package/dist/utils/openapi-patcher.js +35 -1
- package/dist/utils/platform-patcher.js +59 -0
- package/dist/utils/rbac-patcher.js +277 -0
- package/dist/utils/smoke-run.js +31 -0
- package/dist/utils/version.js +24 -0
- package/package.json +15 -6
- package/scripts/smoke-test.mjs +2058 -0
- package/templates/add/auth/cmd/seed/main.go.hbs +76 -0
- package/templates/add/auth/docs/forgot-password.yaml.hbs +19 -0
- package/templates/add/auth/docs/google-callback.yaml.hbs +22 -0
- package/templates/add/auth/docs/google-login.yaml.hbs +7 -0
- package/templates/add/auth/docs/login.yaml.hbs +19 -0
- package/templates/add/auth/docs/logout.yaml.hbs +8 -0
- package/templates/add/auth/docs/refresh.yaml.hbs +15 -0
- package/templates/add/auth/docs/register.yaml.hbs +19 -0
- package/templates/add/auth/docs/reset-password.yaml.hbs +16 -0
- package/templates/add/auth/docs/schemas.yaml.hbs +58 -0
- package/templates/add/auth/docs/users-me-logout-all.yaml.hbs +9 -0
- package/templates/add/auth/docs/users-me-resend-verification.yaml.hbs +10 -0
- package/templates/add/auth/docs/users-me.yaml.hbs +12 -0
- package/templates/add/auth/docs/verify-email.yaml.hbs +16 -0
- package/templates/add/auth/internal/app/user/dto.go.hbs +77 -0
- package/templates/add/auth/internal/app/user/errors.go.hbs +36 -0
- package/templates/add/auth/internal/app/user/handler.go.hbs +235 -0
- package/templates/add/auth/internal/app/user/jwt.go.hbs +84 -0
- package/templates/add/auth/internal/app/user/model/identity.go.hbs +28 -0
- package/templates/add/auth/internal/app/user/model/user.go.hbs +22 -0
- package/templates/add/auth/internal/app/user/repository.go.hbs +84 -0
- package/templates/add/auth/internal/app/user/service.go.hbs +447 -0
- package/templates/add/auth/internal/app/user/service_test.go.hbs +237 -0
- package/templates/add/auth/internal/app/user/tokenstore.go.hbs +159 -0
- package/templates/add/auth/internal/shared/middleware/auth.go.hbs +64 -0
- package/templates/add/auth/internal/shared/middleware/ratelimit.go.hbs +44 -0
- package/templates/add/auth/migrations/create_identities.down.sql.hbs +1 -0
- package/templates/add/auth/migrations/create_identities.up.sql.hbs +11 -0
- package/templates/add/auth/migrations/create_users.down.sql.hbs +1 -0
- package/templates/add/auth/migrations/create_users.up.sql.hbs +9 -0
- package/templates/add/rbac/docs/permissions.yaml.hbs +24 -0
- package/templates/add/rbac/docs/role-permissions.yaml.hbs +31 -0
- package/templates/add/rbac/docs/role.yaml.hbs +17 -0
- package/templates/add/rbac/docs/roles.yaml.hbs +43 -0
- package/templates/add/rbac/docs/schemas.yaml.hbs +37 -0
- package/templates/add/rbac/docs/user-set-role.yaml.hbs +23 -0
- package/templates/add/rbac/docs/user.yaml.hbs +16 -0
- package/templates/add/rbac/docs/users.yaml.hbs +23 -0
- package/templates/add/rbac/internal/app/role/dto.go.hbs +40 -0
- package/templates/add/rbac/internal/app/role/errors.go.hbs +39 -0
- package/templates/add/rbac/internal/app/role/handler.go.hbs +101 -0
- package/templates/add/rbac/internal/app/role/model/permission.go.hbs +9 -0
- package/templates/add/rbac/internal/app/role/model/role.go.hbs +18 -0
- package/templates/add/rbac/internal/app/role/model/role_permission.go.hbs +8 -0
- package/templates/add/rbac/internal/app/role/repository.go.hbs +96 -0
- package/templates/add/rbac/internal/app/role/service.go.hbs +210 -0
- package/templates/add/rbac/internal/app/role/service_test.go.hbs +119 -0
- package/templates/add/rbac/internal/shared/middleware/authz.go.hbs +88 -0
- package/templates/add/rbac/internal/shared/middleware/authz_test.go.hbs +88 -0
- package/templates/add/rbac/migrations/add_roles.down.sql.hbs +15 -0
- package/templates/add/rbac/migrations/add_roles.up.sql.hbs +35 -0
- package/templates/add/worker/cmd/worker/main.go.hbs +77 -0
- package/templates/add/worker/internal/platform/cache/redis.go.hbs +18 -0
- package/templates/add/worker/internal/platform/mail/mail.go.hbs +48 -0
- package/templates/add/worker/internal/platform/mail/task.go.hbs +52 -0
- package/templates/add/worker/internal/platform/queue/client.go.hbs +31 -0
- package/templates/add/worker/internal/platform/queue/server.go.hbs +68 -0
- package/templates/create/base/.env.example.hbs +20 -0
- package/templates/create/base/.github/workflows/ci.yml.hbs +19 -4
- package/templates/create/base/.gitignore.hbs +2 -0
- package/templates/create/base/AGENTS.md.hbs +10 -12
- package/templates/create/base/Makefile.hbs +39 -8
- package/templates/create/base/README.md.hbs +52 -12
- package/templates/create/base/cmd/api/main.go.hbs +26 -1
- package/templates/create/base/internal/platform/database/database.go.hbs +53 -0
- package/templates/create/base/internal/shared/config/config.go.hbs +43 -1
- package/templates/create/base/internal/shared/middleware/cors.go.hbs +29 -0
- package/templates/create/base/internal/shared/middleware/error.go.hbs +13 -1
- package/templates/create/base/migrations/embed.go.hbs +15 -0
- package/templates/create/features/docs/architecture.md.hbs +22 -0
- package/templates/create/features/docs/common/responses.yaml.hbs +15 -0
- package/templates/create/features/docs/observability/metrics.yaml.hbs +12 -0
- package/templates/create/features/docs/openapi.yaml.hbs +17 -5
- package/templates/create/features/docs/patterns.md.hbs +9 -6
- package/templates/create/features/docs/techstack.md.hbs +3 -0
- package/templates/create/features/observability/middleware/metrics.go.hbs +41 -0
- package/templates/create/features/observability/middleware/tracing.go.hbs +46 -0
- package/templates/create/features/observability/platform/telemetry/tracing.go.hbs +130 -0
- package/templates/generate/module/docs/item.yaml.hbs +3 -3
- package/templates/generate/module/handler.go.hbs +37 -6
- package/templates/generate/module/handler_test.go.hbs +113 -51
- package/templates/generate/module/migration.down.sql.hbs +1 -1
- package/templates/generate/module/migration.up.sql.hbs +1 -1
- package/templates/generate/module/minimal/handler.go.hbs +28 -4
- package/templates/generate/module/minimal/handler_test.go.hbs +5 -65
- package/templates/generate/module/minimal/service_test.go.hbs +39 -16
- package/templates/generate/module/model/model.go.hbs +7 -0
- package/templates/generate/module/permission.down.sql.hbs +5 -0
- package/templates/generate/module/permission.up.sql.hbs +4 -0
- package/templates/generate/module/repository_test.go.hbs +79 -0
- package/templates/generate/module/service.go.hbs +6 -4
- package/templates/generate/module/service_test.go.hbs +68 -17
- package/tests/integration/default-module.test.mjs +46 -0
- package/tests/integration/generator-naming.test.mjs +81 -0
- package/tests/integration/generator-unit-test-seams.test.mjs +91 -0
- package/tests/integration/legacy-method-compat.test.mjs +222 -0
- package/tests/integration/remove-module.test.mjs +58 -0
- package/tests/unit/naming.test.mjs +94 -0
- package/tests/unit/smoke-isolation.test.mjs +35 -0
- package/dist/utils/module-paths.js +0 -33
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.addRbac = addRbac;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
10
|
+
const config_1 = require("../utils/config");
|
|
11
|
+
const template_renderer_1 = require("../utils/template-renderer");
|
|
12
|
+
const rbac_manifest_1 = require("../templates/rbac-manifest");
|
|
13
|
+
const migrations_1 = require("../utils/migrations");
|
|
14
|
+
const rbac_patcher_1 = require("../utils/rbac-patcher");
|
|
15
|
+
const openapi_patcher_1 = require("../utils/openapi-patcher");
|
|
16
|
+
// URL (relative to the api prefix) -> docs file (relative to docs/) for every
|
|
17
|
+
// route `add rbac` registers or adds onto the user handler.
|
|
18
|
+
const RBAC_OPENAPI_PATHS = [
|
|
19
|
+
{ urlPath: "/roles", file: "./rbac/roles.yaml" },
|
|
20
|
+
{ urlPath: "/roles/{code}/permissions", file: "./rbac/role-permissions.yaml" },
|
|
21
|
+
{ urlPath: "/roles/{code}", file: "./rbac/role.yaml" },
|
|
22
|
+
{ urlPath: "/permissions", file: "./rbac/permissions.yaml" },
|
|
23
|
+
{ urlPath: "/users", file: "./rbac/users.yaml" },
|
|
24
|
+
{ urlPath: "/users/{id}", file: "./rbac/user.yaml" },
|
|
25
|
+
{ urlPath: "/users/{id}/set-role", file: "./rbac/user-set-role.yaml" },
|
|
26
|
+
];
|
|
27
|
+
// addRbac layers role-based access control on top of `add auth`: a role
|
|
28
|
+
// domain (roles/permissions/role_permissions, admin-manageable), an Authz
|
|
29
|
+
// middleware with a cached role->permission lookup, a Role claim threaded
|
|
30
|
+
// through the JWT, and the admin endpoints that actually need it: listing/
|
|
31
|
+
// viewing other users (GET /users, GET /users/:id) and changing a user's
|
|
32
|
+
// role (PATCH /users/:id/set-role). Opt-in on top of an opt-in — most
|
|
33
|
+
// projects need "is this caller logged in" long before they need "can this
|
|
34
|
+
// caller do X".
|
|
35
|
+
async function addRbac(projectDir = process.cwd()) {
|
|
36
|
+
const config = (0, config_1.readConfig)(projectDir);
|
|
37
|
+
if (!config.features.auth) {
|
|
38
|
+
throw new Error("`go-scaffold add rbac` requires `go-scaffold add auth` first — there's no Role claim to check permissions against otherwise");
|
|
39
|
+
}
|
|
40
|
+
const roleDir = path_1.default.join(projectDir, "internal", "app", "role");
|
|
41
|
+
if (fs_extra_1.default.existsSync(roleDir)) {
|
|
42
|
+
throw new Error(`${roleDir} already exists — RBAC looks like it's already been added`);
|
|
43
|
+
}
|
|
44
|
+
await (0, template_renderer_1.applyTemplateEntries)(projectDir, rbac_manifest_1.RBAC_FILES, { goModule: config.goModule });
|
|
45
|
+
const migrationsDir = path_1.default.join(projectDir, "migrations");
|
|
46
|
+
fs_extra_1.default.ensureDirSync(migrationsDir);
|
|
47
|
+
const version = (0, migrations_1.newMigrationVersion)(migrationsDir);
|
|
48
|
+
await (0, template_renderer_1.applyTemplateEntries)(projectDir, [
|
|
49
|
+
{ template: "add/rbac/migrations/add_roles.up.sql.hbs", output: path_1.default.join("migrations", `${version}_add_roles.up.sql`) },
|
|
50
|
+
{ template: "add/rbac/migrations/add_roles.down.sql.hbs", output: path_1.default.join("migrations", `${version}_add_roles.down.sql`) },
|
|
51
|
+
], {});
|
|
52
|
+
(0, rbac_patcher_1.patchConfigForRbac)(path_1.default.join(projectDir, "internal", "shared", "config", "config.go"));
|
|
53
|
+
(0, rbac_patcher_1.patchUserModelForRbac)(path_1.default.join(projectDir, "internal", "app", "user", "model", "user.go"));
|
|
54
|
+
(0, rbac_patcher_1.patchMiddlewareAuthForRbac)(path_1.default.join(projectDir, "internal", "shared", "middleware", "auth.go"));
|
|
55
|
+
(0, rbac_patcher_1.patchUserJWTForRbac)(path_1.default.join(projectDir, "internal", "app", "user", "jwt.go"));
|
|
56
|
+
(0, rbac_patcher_1.patchUserServiceForRbac)(path_1.default.join(projectDir, "internal", "app", "user", "service.go"));
|
|
57
|
+
(0, rbac_patcher_1.patchUserServiceTestForRbac)(path_1.default.join(projectDir, "internal", "app", "user", "service_test.go"));
|
|
58
|
+
(0, rbac_patcher_1.patchUserDTOForRbac)(path_1.default.join(projectDir, "internal", "app", "user", "dto.go"));
|
|
59
|
+
(0, rbac_patcher_1.patchUserHandlerForRbac)(path_1.default.join(projectDir, "internal", "app", "user", "handler.go"), config.goModule);
|
|
60
|
+
(0, rbac_patcher_1.patchUserErrorsForRbac)(path_1.default.join(projectDir, "internal", "app", "user", "errors.go"));
|
|
61
|
+
(0, rbac_patcher_1.patchMainGoForRbac)(path_1.default.join(projectDir, "cmd", "api", "main.go"), config.goModule);
|
|
62
|
+
(0, rbac_patcher_1.patchCmdSeedForRbac)(path_1.default.join(projectDir, "cmd", "seed", "main.go"), config.goModule);
|
|
63
|
+
patchEnvExample(path_1.default.join(projectDir, ".env.example"));
|
|
64
|
+
let docsMessage = "";
|
|
65
|
+
const openapiPath = path_1.default.join(projectDir, "docs", "openapi.yaml");
|
|
66
|
+
if (config.features.openapiDocs && fs_extra_1.default.existsSync(openapiPath)) {
|
|
67
|
+
const docsEntries = [
|
|
68
|
+
{ template: "add/rbac/docs/schemas.yaml.hbs", output: path_1.default.join("docs", "rbac", "schemas.yaml") },
|
|
69
|
+
...RBAC_OPENAPI_PATHS.map(({ file }) => ({
|
|
70
|
+
template: `add/rbac/docs/${path_1.default.basename(file)}.hbs`,
|
|
71
|
+
output: path_1.default.join("docs", "rbac", path_1.default.basename(file)),
|
|
72
|
+
})),
|
|
73
|
+
];
|
|
74
|
+
await (0, template_renderer_1.applyTemplateEntries)(projectDir, docsEntries, {});
|
|
75
|
+
(0, openapi_patcher_1.patchOpenapiIndexRaw)(openapiPath, config.apiPrefix, RBAC_OPENAPI_PATHS);
|
|
76
|
+
(0, rbac_patcher_1.patchAuthDocsForRbac)(path_1.default.join(projectDir, "docs", "auth", "schemas.yaml"));
|
|
77
|
+
docsMessage = "\ndocs: docs/rbac/*.yaml, wired into docs/openapi.yaml";
|
|
78
|
+
}
|
|
79
|
+
(0, template_renderer_1.gofmtTree)(projectDir);
|
|
80
|
+
(0, config_1.writeConfig)(projectDir, { ...config, features: { ...config.features, rbac: true } });
|
|
81
|
+
console.log(picocolors_1.default.green("\nadded internal/app/role/ and internal/shared/middleware/authz.go"));
|
|
82
|
+
console.log("registered GET /users, GET /users/:id, PATCH /users/:id/set-role, /roles, and /permissions in cmd/api/main.go" + docsMessage);
|
|
83
|
+
console.log(picocolors_1.default.yellow("\n⚠ AUTO_MIGRATE=true does NOT seed the role/permission data — it only creates the\n" +
|
|
84
|
+
" tables from the Go structs. The \"staff\"/\"admin\" roles and their permissions live\n" +
|
|
85
|
+
" in the migration's SQL (INSERT statements), which AutoMigrate never runs. Without\n" +
|
|
86
|
+
" applying it for real, `make seed` fails with \"unknown role code\" and nobody can be\n" +
|
|
87
|
+
" granted anything. Apply it before relying on RBAC, even in dev:\n" +
|
|
88
|
+
" migrate -path migrations -database \"$DB_DSN\" up (or: make migrate-up)"));
|
|
89
|
+
console.log(picocolors_1.default.dim("\nnext: go mod tidy, then SEED_ADMIN_EMAIL=... SEED_ADMIN_PASSWORD=... make seed to get an admin"));
|
|
90
|
+
}
|
|
91
|
+
function patchEnvExample(envExamplePath) {
|
|
92
|
+
if (!fs_extra_1.default.existsSync(envExamplePath))
|
|
93
|
+
return;
|
|
94
|
+
let content = fs_extra_1.default.readFileSync(envExamplePath, "utf8");
|
|
95
|
+
if (content.includes("AUTHZ_CACHE_TTL_MIN"))
|
|
96
|
+
return; // already added
|
|
97
|
+
content =
|
|
98
|
+
content.replace(/\n?$/, "\n") +
|
|
99
|
+
"\n# how long a role's permission set is cached before Authz.Require re-checks the DB —\n" +
|
|
100
|
+
"# a permission change takes effect for already-issued tokens within this window\n" +
|
|
101
|
+
"AUTHZ_CACHE_TTL_MIN=1\n";
|
|
102
|
+
fs_extra_1.default.writeFileSync(envExamplePath, content);
|
|
103
|
+
}
|
package/dist/commands/remove.js
CHANGED
|
@@ -9,18 +9,17 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
|
9
9
|
const picocolors_1 = __importDefault(require("picocolors"));
|
|
10
10
|
const prompts_1 = require("@inquirer/prompts");
|
|
11
11
|
const config_1 = require("../utils/config");
|
|
12
|
-
const
|
|
12
|
+
const module_location_1 = require("../utils/module-location");
|
|
13
13
|
const main_patcher_1 = require("../utils/main-patcher");
|
|
14
14
|
const openapi_patcher_1 = require("../utils/openapi-patcher");
|
|
15
15
|
const template_renderer_1 = require("../utils/template-renderer");
|
|
16
16
|
const generate_wizard_1 = require("../prompts/generate-wizard");
|
|
17
|
-
// removeModule
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
// path that produced the duplicate-registration bug in the first place).
|
|
17
|
+
// removeModule deletes application code and reverses generated wiring while
|
|
18
|
+
// preserving immutable migration history and table data. Destructive schema
|
|
19
|
+
// removal must be an explicit new migration, never a deletion of an applied one.
|
|
21
20
|
async function removeModule(rawName, opts, projectDir = process.cwd()) {
|
|
22
21
|
const config = (0, config_1.readConfig)(projectDir);
|
|
23
|
-
const naming = (0,
|
|
22
|
+
const naming = (0, module_location_1.resolveProjectModuleNaming)(projectDir, rawName ?? (await (0, generate_wizard_1.promptModuleName)()));
|
|
24
23
|
const modulePath = naming.pkg;
|
|
25
24
|
const moduleDir = path_1.default.join(projectDir, "internal", "app", modulePath);
|
|
26
25
|
if (!fs_extra_1.default.existsSync(moduleDir)) {
|
|
@@ -28,12 +27,24 @@ async function removeModule(rawName, opts, projectDir = process.cwd()) {
|
|
|
28
27
|
}
|
|
29
28
|
if (!opts.yes) {
|
|
30
29
|
const ok = await (0, prompts_1.confirm)({
|
|
31
|
-
message: `Remove module "${naming.pkg}"? Deletes internal/app/${modulePath}
|
|
30
|
+
message: `Remove module "${naming.pkg}"? Deletes internal/app/${modulePath}/ and its docs, ` +
|
|
31
|
+
`then un-wires main.go/openapi.yaml. Existing migrations, table, and data are preserved.`,
|
|
32
32
|
default: false,
|
|
33
33
|
});
|
|
34
34
|
if (!ok)
|
|
35
35
|
throw new Error("removal cancelled");
|
|
36
36
|
}
|
|
37
|
+
// detect --auth/--permission from the generated handler.go itself (not
|
|
38
|
+
// stored anywhere else) — unpatchMainGo needs the exact same flags used at
|
|
39
|
+
// generate-time to reconstruct the identical line it's removing.
|
|
40
|
+
const handlerGoPath = path_1.default.join(moduleDir, "handler.go");
|
|
41
|
+
let auth;
|
|
42
|
+
let permission;
|
|
43
|
+
if (fs_extra_1.default.existsSync(handlerGoPath)) {
|
|
44
|
+
const handlerContent = fs_extra_1.default.readFileSync(handlerGoPath, "utf8");
|
|
45
|
+
auth = /jwtSecret\s+string/.test(handlerContent);
|
|
46
|
+
permission = handlerContent.match(/h\.authz\.Require\("([^"]+)"\)/)?.[1];
|
|
47
|
+
}
|
|
37
48
|
// 1. the domain package
|
|
38
49
|
fs_extra_1.default.removeSync(moduleDir);
|
|
39
50
|
// 2. main.go wiring
|
|
@@ -42,6 +53,8 @@ async function removeModule(rawName, opts, projectDir = process.cwd()) {
|
|
|
42
53
|
modulePath,
|
|
43
54
|
pkg: naming.pkg,
|
|
44
55
|
pascalName: naming.pascalName,
|
|
56
|
+
auth,
|
|
57
|
+
permission,
|
|
45
58
|
});
|
|
46
59
|
// 3. openapi index + per-module docs
|
|
47
60
|
const openapiPath = path_1.default.join(projectDir, "docs", "openapi.yaml");
|
|
@@ -49,24 +62,27 @@ async function removeModule(rawName, opts, projectDir = process.cwd()) {
|
|
|
49
62
|
(0, openapi_patcher_1.unpatchOpenapiIndex)(openapiPath, naming, config.apiPrefix);
|
|
50
63
|
fs_extra_1.default.removeSync(path_1.default.join(projectDir, "docs", naming.plural));
|
|
51
64
|
}
|
|
52
|
-
// 4. migration
|
|
65
|
+
// 4. Migration history is immutable. A migration may already be recorded in
|
|
66
|
+
// schema_migrations on production databases, so deleting its file would make
|
|
67
|
+
// existing and fresh environments disagree and can prevent the app booting.
|
|
68
|
+
// Re-generating the same module reuses this create migration.
|
|
53
69
|
const migrationsDir = path_1.default.join(projectDir, "migrations");
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
70
|
+
const preservedMigrations = fs_extra_1.default.existsSync(migrationsDir)
|
|
71
|
+
? fs_extra_1.default.readdirSync(migrationsDir).filter((f) => f.endsWith(`_create_${naming.plural}.up.sql`) ||
|
|
72
|
+
f.endsWith(`_create_${naming.plural}.down.sql`) ||
|
|
73
|
+
f.endsWith(`_add_${naming.plural}_permission.up.sql`) ||
|
|
74
|
+
f.endsWith(`_add_${naming.plural}_permission.down.sql`))
|
|
75
|
+
: [];
|
|
63
76
|
(0, template_renderer_1.gofmtTree)(projectDir);
|
|
64
77
|
console.log(picocolors_1.default.green(`\nremoved module "${naming.pkg}"`));
|
|
65
78
|
console.log(` deleted internal/app/${modulePath}/`);
|
|
66
79
|
console.log(` un-wired cmd/api/main.go`);
|
|
67
80
|
if (fs_extra_1.default.existsSync(openapiPath))
|
|
68
81
|
console.log(` un-wired docs/openapi.yaml + deleted docs/${naming.plural}/`);
|
|
69
|
-
if (
|
|
70
|
-
console.log(`
|
|
71
|
-
|
|
82
|
+
if (preservedMigrations.length) {
|
|
83
|
+
console.log(` preserved migration history: ${preservedMigrations.join(", ")}`);
|
|
84
|
+
}
|
|
85
|
+
console.log(picocolors_1.default.yellow(`\nnote: the ${naming.tableName} table and its data are untouched. ` +
|
|
86
|
+
`To remove them safely, run \`go-scaffold generate migration drop_${naming.tableName}\` ` +
|
|
87
|
+
`and write an explicit up/down migration.`));
|
|
72
88
|
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.addWorker = addWorker;
|
|
7
|
+
const path_1 = __importDefault(require("path"));
|
|
8
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
|
+
const picocolors_1 = __importDefault(require("picocolors"));
|
|
10
|
+
const config_1 = require("../utils/config");
|
|
11
|
+
const template_renderer_1 = require("../utils/template-renderer");
|
|
12
|
+
const worker_manifest_1 = require("../templates/worker-manifest");
|
|
13
|
+
const platform_patcher_1 = require("../utils/platform-patcher");
|
|
14
|
+
// addWorker scaffolds the async task processing subsystem: Redis
|
|
15
|
+
// (platform/cache), Asynq client/server (platform/queue), SMTP mail
|
|
16
|
+
// (platform/mail, with an email:send task type as the one thing the fresh
|
|
17
|
+
// worker actually handles), and cmd/worker itself. Opt-in — most projects
|
|
18
|
+
// don't need a queue on day one, and an empty worker with no task types
|
|
19
|
+
// registered is a stranger scaffold than just not having one.
|
|
20
|
+
async function addWorker(projectDir = process.cwd()) {
|
|
21
|
+
const config = (0, config_1.readConfig)(projectDir);
|
|
22
|
+
const queueDir = path_1.default.join(projectDir, "internal", "platform", "queue");
|
|
23
|
+
if (fs_extra_1.default.existsSync(queueDir)) {
|
|
24
|
+
throw new Error(`${queueDir} already exists — worker infrastructure looks like it's already been added`);
|
|
25
|
+
}
|
|
26
|
+
await (0, template_renderer_1.applyTemplateEntries)(projectDir, worker_manifest_1.WORKER_FILES, { goModule: config.goModule });
|
|
27
|
+
(0, platform_patcher_1.patchConfigForWorker)(path_1.default.join(projectDir, "internal", "shared", "config", "config.go"));
|
|
28
|
+
(0, platform_patcher_1.patchMainGoForWorker)(path_1.default.join(projectDir, "cmd", "api", "main.go"), config.goModule);
|
|
29
|
+
patchEnvExample(path_1.default.join(projectDir, ".env.example"));
|
|
30
|
+
patchMakefile(path_1.default.join(projectDir, "Makefile"));
|
|
31
|
+
(0, template_renderer_1.gofmtTree)(projectDir);
|
|
32
|
+
(0, config_1.writeConfig)(projectDir, { ...config, features: { ...config.features, worker: true } });
|
|
33
|
+
console.log(picocolors_1.default.green("\nadded internal/platform/{cache,queue,mail}/ and cmd/worker/"));
|
|
34
|
+
console.log("wired Redis into cmd/api (readyz check) — cmd/api does not enqueue anything yet");
|
|
35
|
+
console.log(picocolors_1.default.dim("\nnext: make worker (separate terminal, or `make dev` runs both), then go build ./... to confirm"));
|
|
36
|
+
}
|
|
37
|
+
function patchEnvExample(envExamplePath) {
|
|
38
|
+
if (!fs_extra_1.default.existsSync(envExamplePath))
|
|
39
|
+
return;
|
|
40
|
+
let content = fs_extra_1.default.readFileSync(envExamplePath, "utf8");
|
|
41
|
+
if (content.includes("REDIS_URL"))
|
|
42
|
+
return; // already added
|
|
43
|
+
content =
|
|
44
|
+
content.replace(/\n?$/, "\n") +
|
|
45
|
+
"\nREDIS_URL=redis://localhost:6379/0\n" +
|
|
46
|
+
"\n# leave SMTP_HOST unset to log emails instead of sending them (dev default)\n" +
|
|
47
|
+
"SMTP_HOST=\n" +
|
|
48
|
+
"SMTP_PORT=587\n" +
|
|
49
|
+
"SMTP_USERNAME=\n" +
|
|
50
|
+
"SMTP_PASSWORD=\n" +
|
|
51
|
+
"SMTP_FROM=no-reply@example.local\n";
|
|
52
|
+
fs_extra_1.default.writeFileSync(envExamplePath, content);
|
|
53
|
+
}
|
|
54
|
+
function patchMakefile(makefilePath) {
|
|
55
|
+
if (!fs_extra_1.default.existsSync(makefilePath))
|
|
56
|
+
return;
|
|
57
|
+
let content = fs_extra_1.default.readFileSync(makefilePath, "utf8");
|
|
58
|
+
if (content.includes("\nworker:\n"))
|
|
59
|
+
return; // already added
|
|
60
|
+
content = content.replace(/^\.PHONY: /m, ".PHONY: dev worker ");
|
|
61
|
+
const targets = "\n# run both API + worker in one terminal — Ctrl+C kills both\n" +
|
|
62
|
+
"dev:\n" +
|
|
63
|
+
"\t@[ -f .env ] && export $$(grep -v '^#' .env | xargs); \\\n" +
|
|
64
|
+
"\t(trap 'kill 0' SIGINT SIGTERM; \\\n" +
|
|
65
|
+
"\t go run ./cmd/api & \\\n" +
|
|
66
|
+
"\t go run ./cmd/worker & \\\n" +
|
|
67
|
+
"\t wait)\n" +
|
|
68
|
+
"\n" +
|
|
69
|
+
"# background worker for async task processing (email, ...) — requires Redis.\n" +
|
|
70
|
+
"# Use `make dev` to run both in one terminal, or run this in a separate one.\n" +
|
|
71
|
+
"worker:\n" +
|
|
72
|
+
"\t@[ -f .env ] && export $$(grep -v '^#' .env | xargs); go run ./cmd/worker\n";
|
|
73
|
+
content = content.replace(/\nbuild:/, `${targets}\nbuild:`);
|
|
74
|
+
fs_extra_1.default.writeFileSync(makefilePath, content);
|
|
75
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -10,12 +10,17 @@ const picocolors_1 = __importDefault(require("picocolors"));
|
|
|
10
10
|
const create_1 = require("./commands/create");
|
|
11
11
|
const generate_1 = require("./commands/generate");
|
|
12
12
|
const method_1 = require("./commands/method");
|
|
13
|
+
const migration_1 = require("./commands/migration");
|
|
13
14
|
const remove_1 = require("./commands/remove");
|
|
15
|
+
const version_1 = require("./utils/version");
|
|
16
|
+
const worker_1 = require("./commands/worker");
|
|
17
|
+
const auth_1 = require("./commands/auth");
|
|
18
|
+
const rbac_1 = require("./commands/rbac");
|
|
14
19
|
const program = new commander_1.Command();
|
|
15
20
|
program
|
|
16
21
|
.name("go-scaffold")
|
|
17
22
|
.description("Scaffold Gin + GORM + Postgres Go backend projects with a consistent domain-module standard")
|
|
18
|
-
.version(
|
|
23
|
+
.version((0, version_1.cliVersion)());
|
|
19
24
|
program
|
|
20
25
|
.command("create [name]")
|
|
21
26
|
.alias("c")
|
|
@@ -23,6 +28,7 @@ program
|
|
|
23
28
|
.option("--defaults", "skip the wizard, use defaults (for CI/scripting)")
|
|
24
29
|
.option("--no-docker", "skip docker-compose.yml (only applies with --defaults)")
|
|
25
30
|
.option("--no-openapi-docs", "skip docs/openapi.yaml (only applies with --defaults)")
|
|
31
|
+
.option("--observability", "add Prometheus /metrics + OpenTelemetry tracing (only applies with --defaults; off by default)")
|
|
26
32
|
.option("--api-prefix <prefix>", 'URL prefix every route is grouped under (default "v1"; pass "" for none)')
|
|
27
33
|
.action(async (name, opts) => {
|
|
28
34
|
try {
|
|
@@ -30,6 +36,7 @@ program
|
|
|
30
36
|
defaults: opts.defaults,
|
|
31
37
|
docker: opts.docker,
|
|
32
38
|
openapiDocs: opts.openapiDocs,
|
|
39
|
+
observability: opts.observability,
|
|
33
40
|
apiPrefix: opts.apiPrefix,
|
|
34
41
|
});
|
|
35
42
|
}
|
|
@@ -49,16 +56,20 @@ const generate = program
|
|
|
49
56
|
const target = await (0, prompts_1.select)({
|
|
50
57
|
message: "What do you want to generate?",
|
|
51
58
|
choices: [
|
|
52
|
-
{ name: "Module (
|
|
59
|
+
{ name: "Module (safe minimal domain; add methods explicitly)", value: "module" },
|
|
53
60
|
{ name: "Method (add one endpoint to an existing module)", value: "method" },
|
|
61
|
+
{ name: "Migration (reserve a timestamped up/down SQL file pair)", value: "migration" },
|
|
54
62
|
],
|
|
55
63
|
});
|
|
56
64
|
if (target === "module") {
|
|
57
|
-
await (0, generate_1.generateModule)(undefined, { full:
|
|
65
|
+
await (0, generate_1.generateModule)(undefined, { full: false });
|
|
58
66
|
}
|
|
59
|
-
else {
|
|
67
|
+
else if (target === "method") {
|
|
60
68
|
await (0, method_1.generateMethod)(undefined, undefined, {});
|
|
61
69
|
}
|
|
70
|
+
else {
|
|
71
|
+
await (0, migration_1.generateMigration)(undefined);
|
|
72
|
+
}
|
|
62
73
|
}
|
|
63
74
|
catch (err) {
|
|
64
75
|
console.error(picocolors_1.default.red(err.message));
|
|
@@ -68,11 +79,14 @@ const generate = program
|
|
|
68
79
|
generate
|
|
69
80
|
.command("module [name]")
|
|
70
81
|
.alias("m")
|
|
71
|
-
.description("scaffold a domain module
|
|
72
|
-
.option("--
|
|
82
|
+
.description("scaffold a safe minimal domain module; opt into a CRUD skeleton with --full")
|
|
83
|
+
.option("--full", "generate a CRUD skeleton (DTO fields/business rules remain TODO); minimal is the safe default")
|
|
84
|
+
.option("--no-full", "deprecated compatibility alias; minimal is already the default")
|
|
85
|
+
.option("--auth", "require a valid access token for this module's routes (needs `add auth`)")
|
|
86
|
+
.option("--permission <code>", "also require this permission via authz.Require (needs `add rbac`; implies --auth)")
|
|
73
87
|
.action(async (name, opts) => {
|
|
74
88
|
try {
|
|
75
|
-
await (0, generate_1.generateModule)(name, { full: opts.full });
|
|
89
|
+
await (0, generate_1.generateModule)(name, { full: opts.full, auth: opts.auth, permission: opts.permission });
|
|
76
90
|
}
|
|
77
91
|
catch (err) {
|
|
78
92
|
console.error(picocolors_1.default.red(err.message));
|
|
@@ -107,6 +121,56 @@ generate
|
|
|
107
121
|
process.exitCode = 1;
|
|
108
122
|
}
|
|
109
123
|
});
|
|
124
|
+
generate
|
|
125
|
+
.command("migration [name]")
|
|
126
|
+
.alias("mig")
|
|
127
|
+
.description("reserve a timestamped migrations/<version>_<name>.{up,down}.sql pair (stubs only — you write the SQL)")
|
|
128
|
+
.action(async (name) => {
|
|
129
|
+
try {
|
|
130
|
+
await (0, migration_1.generateMigration)(name);
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
console.error(picocolors_1.default.red(err.message));
|
|
134
|
+
process.exitCode = 1;
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
const add = program.command("add").description("add opt-in infrastructure to an existing go-scaffold project");
|
|
138
|
+
add
|
|
139
|
+
.command("worker")
|
|
140
|
+
.description("add Redis, an Asynq task queue, SMTP mail, and cmd/worker (opt-in — most projects don't need this on day one)")
|
|
141
|
+
.action(async () => {
|
|
142
|
+
try {
|
|
143
|
+
await (0, worker_1.addWorker)();
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
console.error(picocolors_1.default.red(err.message));
|
|
147
|
+
process.exitCode = 1;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
add
|
|
151
|
+
.command("auth")
|
|
152
|
+
.description("add email/password auth: JWT access tokens, Redis-backed refresh token rotation, register/login/refresh/logout/me (requires `add worker` first)")
|
|
153
|
+
.action(async () => {
|
|
154
|
+
try {
|
|
155
|
+
await (0, auth_1.addAuth)();
|
|
156
|
+
}
|
|
157
|
+
catch (err) {
|
|
158
|
+
console.error(picocolors_1.default.red(err.message));
|
|
159
|
+
process.exitCode = 1;
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
add
|
|
163
|
+
.command("rbac")
|
|
164
|
+
.description("add role-based access control: roles/permissions admin API, cached Authz middleware, PATCH /users/:id/set-role (requires `add auth` first)")
|
|
165
|
+
.action(async () => {
|
|
166
|
+
try {
|
|
167
|
+
await (0, rbac_1.addRbac)();
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
console.error(picocolors_1.default.red(err.message));
|
|
171
|
+
process.exitCode = 1;
|
|
172
|
+
}
|
|
173
|
+
});
|
|
110
174
|
const remove = program
|
|
111
175
|
.command("remove")
|
|
112
176
|
.alias("rm")
|
|
@@ -25,6 +25,10 @@ async function runCreateWizard() {
|
|
|
25
25
|
message: "Include hand-written OpenAPI docs (docs/openapi.yaml, whole docs/ tree served at /docs)?",
|
|
26
26
|
default: true,
|
|
27
27
|
});
|
|
28
|
+
const observability = await (0, prompts_1.confirm)({
|
|
29
|
+
message: "Add metrics + tracing (Prometheus /metrics, OpenTelemetry over OTLP/HTTP for Gin + GORM)?",
|
|
30
|
+
default: false,
|
|
31
|
+
});
|
|
28
32
|
const apiPrefixRaw = await (0, prompts_1.input)({
|
|
29
33
|
message: "API route prefix (e.g. v1, api/v1; leave blank for none):",
|
|
30
34
|
default: "v1",
|
|
@@ -34,10 +38,11 @@ async function runCreateWizard() {
|
|
|
34
38
|
console.log("\nSummary:");
|
|
35
39
|
console.log(` Docker + PostgreSQL: ${docker ? "yes" : "no"}`);
|
|
36
40
|
console.log(` OpenAPI docs: ${openapiDocs ? "yes" : "no"}`);
|
|
41
|
+
console.log(` Metrics + tracing: ${observability ? "yes" : "no"}`);
|
|
37
42
|
console.log(` Route prefix: ${apiPrefix ? `/${apiPrefix}` : "(none)"}`);
|
|
38
43
|
const proceed = await (0, prompts_1.confirm)({ message: "\nCreate project with these settings?", default: true });
|
|
39
44
|
if (!proceed) {
|
|
40
45
|
throw new Error("project creation cancelled");
|
|
41
46
|
}
|
|
42
|
-
return { features: { docker, openapiDocs }, apiPrefix };
|
|
47
|
+
return { features: { docker, openapiDocs, observability }, apiPrefix };
|
|
43
48
|
}
|
|
@@ -4,6 +4,7 @@ exports.promptModuleName = promptModuleName;
|
|
|
4
4
|
exports.promptMethodName = promptMethodName;
|
|
5
5
|
exports.promptMethodType = promptMethodType;
|
|
6
6
|
exports.promptGetMode = promptGetMode;
|
|
7
|
+
exports.promptMigrationName = promptMigrationName;
|
|
7
8
|
exports.promptLookupField = promptLookupField;
|
|
8
9
|
const prompts_1 = require("@inquirer/prompts");
|
|
9
10
|
const naming_1 = require("../utils/naming");
|
|
@@ -53,6 +54,13 @@ async function promptGetMode() {
|
|
|
53
54
|
],
|
|
54
55
|
});
|
|
55
56
|
}
|
|
57
|
+
async function promptMigrationName() {
|
|
58
|
+
const name = await (0, prompts_1.input)({
|
|
59
|
+
message: "Migration name (e.g. add_status_to_orders):",
|
|
60
|
+
validate: (value) => (value.trim() ? true : "migration name is required"),
|
|
61
|
+
});
|
|
62
|
+
return name.trim();
|
|
63
|
+
}
|
|
56
64
|
async function promptLookupField() {
|
|
57
65
|
const field = await (0, prompts_1.input)({
|
|
58
66
|
message: "Lookup field (e.g. email, status, slug):",
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AUTH_FILES = void 0;
|
|
4
|
+
// output paths are relative to the project root
|
|
5
|
+
exports.AUTH_FILES = [
|
|
6
|
+
{ template: "add/auth/internal/shared/middleware/auth.go.hbs", output: "internal/shared/middleware/auth.go" },
|
|
7
|
+
{ template: "add/auth/internal/shared/middleware/ratelimit.go.hbs", output: "internal/shared/middleware/ratelimit.go" },
|
|
8
|
+
{ template: "add/auth/internal/app/user/model/user.go.hbs", output: "internal/app/user/model/user.go" },
|
|
9
|
+
{ template: "add/auth/internal/app/user/model/identity.go.hbs", output: "internal/app/user/model/identity.go" },
|
|
10
|
+
{ template: "add/auth/internal/app/user/dto.go.hbs", output: "internal/app/user/dto.go" },
|
|
11
|
+
{ template: "add/auth/internal/app/user/errors.go.hbs", output: "internal/app/user/errors.go" },
|
|
12
|
+
{ template: "add/auth/internal/app/user/jwt.go.hbs", output: "internal/app/user/jwt.go" },
|
|
13
|
+
{ template: "add/auth/internal/app/user/tokenstore.go.hbs", output: "internal/app/user/tokenstore.go" },
|
|
14
|
+
{ template: "add/auth/internal/app/user/repository.go.hbs", output: "internal/app/user/repository.go" },
|
|
15
|
+
{ template: "add/auth/internal/app/user/service.go.hbs", output: "internal/app/user/service.go" },
|
|
16
|
+
{ template: "add/auth/internal/app/user/service_test.go.hbs", output: "internal/app/user/service_test.go" },
|
|
17
|
+
{ template: "add/auth/internal/app/user/handler.go.hbs", output: "internal/app/user/handler.go" },
|
|
18
|
+
{ template: "add/auth/cmd/seed/main.go.hbs", output: "cmd/seed/main.go" },
|
|
19
|
+
];
|
|
@@ -45,6 +45,10 @@ exports.CREATE_MANIFEST = [
|
|
|
45
45
|
template: "create/base/internal/shared/pagination/pagination.go.hbs",
|
|
46
46
|
output: "internal/shared/pagination/pagination.go",
|
|
47
47
|
},
|
|
48
|
+
{
|
|
49
|
+
template: "create/base/internal/shared/middleware/cors.go.hbs",
|
|
50
|
+
output: "internal/shared/middleware/cors.go",
|
|
51
|
+
},
|
|
48
52
|
{
|
|
49
53
|
template: "create/base/internal/shared/middleware/error.go.hbs",
|
|
50
54
|
output: "internal/shared/middleware/error.go",
|
|
@@ -58,6 +62,7 @@ exports.CREATE_MANIFEST = [
|
|
|
58
62
|
output: "internal/shared/middleware/requestid.go",
|
|
59
63
|
},
|
|
60
64
|
{ template: "create/base/migrations/.gitkeep.hbs", output: "migrations/.gitkeep" },
|
|
65
|
+
{ template: "create/base/migrations/embed.go.hbs", output: "migrations/embed.go" },
|
|
61
66
|
// architecture standards docs — always included, this is the point of the CLI
|
|
62
67
|
{
|
|
63
68
|
template: "create/features/docs/architecture.md.hbs",
|
|
@@ -107,4 +112,24 @@ exports.CREATE_MANIFEST = [
|
|
|
107
112
|
output: "docs/health/health-readyz.yaml",
|
|
108
113
|
when: (ctx) => ctx.openapiDocs,
|
|
109
114
|
},
|
|
115
|
+
{
|
|
116
|
+
template: "create/features/docs/observability/metrics.yaml.hbs",
|
|
117
|
+
output: "docs/observability/metrics.yaml",
|
|
118
|
+
when: (ctx) => ctx.openapiDocs && ctx.observability,
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
template: "create/features/observability/middleware/metrics.go.hbs",
|
|
122
|
+
output: "internal/shared/middleware/metrics.go",
|
|
123
|
+
when: (ctx) => ctx.observability,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
template: "create/features/observability/middleware/tracing.go.hbs",
|
|
127
|
+
output: "internal/shared/middleware/tracing.go",
|
|
128
|
+
when: (ctx) => ctx.observability,
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
template: "create/features/observability/platform/telemetry/tracing.go.hbs",
|
|
132
|
+
output: "internal/platform/telemetry/tracing.go",
|
|
133
|
+
when: (ctx) => ctx.observability,
|
|
134
|
+
},
|
|
110
135
|
];
|
|
@@ -12,6 +12,7 @@ exports.MODULE_FILES = [
|
|
|
12
12
|
{ template: "generate/module/handler.go.hbs", output: "handler.go" },
|
|
13
13
|
{ template: "generate/module/service_test.go.hbs", output: "service_test.go" },
|
|
14
14
|
{ template: "generate/module/handler_test.go.hbs", output: "handler_test.go" },
|
|
15
|
+
{ template: "generate/module/repository_test.go.hbs", output: "repository_test.go" },
|
|
15
16
|
];
|
|
16
17
|
// minimal: same model/errors/repository (generate method's patches assume the
|
|
17
18
|
// full data-access surface exists), but no default CRUD in dto/service/handler
|
|
@@ -25,4 +26,5 @@ exports.MODULE_FILES_MINIMAL = [
|
|
|
25
26
|
{ template: "generate/module/minimal/handler.go.hbs", output: "handler.go" },
|
|
26
27
|
{ template: "generate/module/minimal/service_test.go.hbs", output: "service_test.go" },
|
|
27
28
|
{ template: "generate/module/minimal/handler_test.go.hbs", output: "handler_test.go" },
|
|
29
|
+
{ template: "generate/module/repository_test.go.hbs", output: "repository_test.go" },
|
|
28
30
|
];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RBAC_FILES = void 0;
|
|
4
|
+
// output paths are relative to the project root
|
|
5
|
+
exports.RBAC_FILES = [
|
|
6
|
+
{ template: "add/rbac/internal/shared/middleware/authz.go.hbs", output: "internal/shared/middleware/authz.go" },
|
|
7
|
+
{ template: "add/rbac/internal/shared/middleware/authz_test.go.hbs", output: "internal/shared/middleware/authz_test.go" },
|
|
8
|
+
{ template: "add/rbac/internal/app/role/model/role.go.hbs", output: "internal/app/role/model/role.go" },
|
|
9
|
+
{ template: "add/rbac/internal/app/role/model/permission.go.hbs", output: "internal/app/role/model/permission.go" },
|
|
10
|
+
{ template: "add/rbac/internal/app/role/model/role_permission.go.hbs", output: "internal/app/role/model/role_permission.go" },
|
|
11
|
+
{ template: "add/rbac/internal/app/role/repository.go.hbs", output: "internal/app/role/repository.go" },
|
|
12
|
+
{ template: "add/rbac/internal/app/role/service.go.hbs", output: "internal/app/role/service.go" },
|
|
13
|
+
{ template: "add/rbac/internal/app/role/service_test.go.hbs", output: "internal/app/role/service_test.go" },
|
|
14
|
+
{ template: "add/rbac/internal/app/role/handler.go.hbs", output: "internal/app/role/handler.go" },
|
|
15
|
+
{ template: "add/rbac/internal/app/role/dto.go.hbs", output: "internal/app/role/dto.go" },
|
|
16
|
+
{ template: "add/rbac/internal/app/role/errors.go.hbs", output: "internal/app/role/errors.go" },
|
|
17
|
+
];
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WORKER_FILES = void 0;
|
|
4
|
+
// output paths are relative to the project root
|
|
5
|
+
exports.WORKER_FILES = [
|
|
6
|
+
{ template: "add/worker/internal/platform/cache/redis.go.hbs", output: "internal/platform/cache/redis.go" },
|
|
7
|
+
{ template: "add/worker/internal/platform/queue/client.go.hbs", output: "internal/platform/queue/client.go" },
|
|
8
|
+
{ template: "add/worker/internal/platform/queue/server.go.hbs", output: "internal/platform/queue/server.go" },
|
|
9
|
+
{ template: "add/worker/internal/platform/mail/mail.go.hbs", output: "internal/platform/mail/mail.go" },
|
|
10
|
+
{ template: "add/worker/internal/platform/mail/task.go.hbs", output: "internal/platform/mail/task.go" },
|
|
11
|
+
{ template: "add/worker/cmd/worker/main.go.hbs", output: "cmd/worker/main.go" },
|
|
12
|
+
];
|