@nospt/plugin-tech-radar-ng-backend 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Migration: add default segments
3
+ *
4
+ * Stores segment entries — categories for the Tech Radar NG.
5
+ *
6
+ * NOTE: Migrations must be plain JS (not TS). Backstage runs them
7
+ * at runtime without a TypeScript loader.
8
+ */
9
+
10
+ const { id } = require('zod/v4/locales');
11
+
12
+ /**
13
+ * @param {import('knex').Knex} knex
14
+ */
15
+ exports.up = async function (knex) {
16
+ // Seed default segments
17
+ await knex('segments').insert([
18
+ {
19
+ id: 'ai-code-development',
20
+ name: 'AI Code Development',
21
+ description:
22
+ 'AI tools and assistants that support software development workflows.',
23
+ search_params: JSON.stringify([
24
+ 'code',
25
+ 'coding',
26
+ 'programming',
27
+ 'copilot',
28
+ 'code-generation',
29
+ 'developer',
30
+ 'ide',
31
+ 'autocomplete',
32
+ 'code generation',
33
+ ]),
34
+ },
35
+ {
36
+ id: 'infrastructure',
37
+ name: 'Infrastructure',
38
+ description:
39
+ 'Platforms, runtimes, and cloud services powering AI workloads.',
40
+ search_params: JSON.stringify([
41
+ 'infrastructure',
42
+ 'api',
43
+ 'platform',
44
+ 'runtime',
45
+ 'pipeline',
46
+ 'orchestration',
47
+ 'vector',
48
+ 'database',
49
+ 'deployment',
50
+ 'serving',
51
+ 'gateway',
52
+ ]),
53
+ },
54
+ {
55
+ id: 'llm-techniques',
56
+ name: 'LLM Techniques',
57
+ description:
58
+ 'Large language model architectures, fine-tuning, and prompting strategies.',
59
+ search_params: JSON.stringify([
60
+ 'llm',
61
+ 'language model',
62
+ 'gpt',
63
+ 'transformer',
64
+ 'prompt',
65
+ 'rag',
66
+ 'embedding',
67
+ 'fine-tuning',
68
+ 'agent',
69
+ 'chatbot',
70
+ 'assistant',
71
+ 'reasoning',
72
+ 'inference',
73
+ ]),
74
+ },
75
+ {
76
+ id: 'standards-protocols',
77
+ name: 'Standards & Protocols',
78
+ description:
79
+ 'Emerging standards, APIs, and interoperability protocols for AI systems.',
80
+ search_params: JSON.stringify([
81
+ 'standard',
82
+ 'protocol',
83
+ 'specification',
84
+ 'mcp',
85
+ 'openapi',
86
+ 'schema',
87
+ 'format',
88
+ 'interoperability',
89
+ ]),
90
+ },
91
+ {
92
+ id: 'ai-low-code-no-code',
93
+ name: 'AI Low-Code/No-Code',
94
+ description:
95
+ 'AI-powered low-code and no-code platforms for building applications.',
96
+ search_params: JSON.stringify([
97
+ 'no-code',
98
+ 'low-code',
99
+ 'nocode',
100
+ 'lowcode',
101
+ 'visual',
102
+ 'builder',
103
+ 'workflow',
104
+ 'automation',
105
+ 'drag',
106
+ ]),
107
+ },
108
+ ]);
109
+ };
110
+
111
+ /**
112
+ * @param {import('knex').Knex} knex
113
+ */
114
+ exports.down = async function (knex) {
115
+ await knex('segments')
116
+ .whereIn('id', [
117
+ 'ai-code-development',
118
+ 'infrastructure',
119
+ 'llm-techniques',
120
+ 'standards-protocols',
121
+ 'ai-low-code-no-code',
122
+ ])
123
+ .delete();
124
+ };
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Migration: create rings table
3
+ *
4
+ * Stores GenAITechCandidate entries — technologies discovered and
5
+ * proposed for the Tech Radar NG.
6
+ *
7
+ * NOTE: Migrations must be plain JS (not TS). Backstage runs them
8
+ * at runtime without a TypeScript loader.
9
+ */
10
+
11
+ /**
12
+ * Returns a DB-level default expression that generates a UUID v4.
13
+ * Works with PostgreSQL (gen_random_uuid) and SQLite (randomblob).
14
+ * @param {import('knex').Knex} knex
15
+ */
16
+ function uuidDefault(knex) {
17
+ if (knex.client.config.client === 'pg') {
18
+ return knex.raw('gen_random_uuid()');
19
+ }
20
+ return knex.raw(
21
+ "(lower(hex(randomblob(4))) || '-' || lower(hex(randomblob(2))) || '-' || '4' || substr(lower(hex(randomblob(2))),2) || '-' || substr('89ab', abs(random()) % 4 + 1, 1) || substr(lower(hex(randomblob(2))),2) || '-' || lower(hex(randomblob(6))))",
22
+ );
23
+ }
24
+
25
+ /**
26
+ * @param {import('knex').Knex} knex
27
+ */
28
+ exports.up = async function (knex) {
29
+ await knex.schema.createTable('rings', table => {
30
+ table.uuid('id').primary().defaultTo(uuidDefault(knex));
31
+
32
+ // Core identity
33
+ table.string('name').notNullable().unique();
34
+ table.string('color').notNullable().defaultTo('#000000');
35
+
36
+ table.timestamp('created_at').defaultTo(knex.fn.now());
37
+ table.timestamp('updated_at').defaultTo(knex.fn.now());
38
+ });
39
+ };
40
+
41
+ /**
42
+ * @param {import('knex').Knex} knex
43
+ */
44
+ exports.down = async function (knex) {
45
+ await knex.schema.dropTable('rings');
46
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Migration: create rings table
3
+ *
4
+ * Stores ring entries — categories for the Tech Radar NG.
5
+ *
6
+ * NOTE: Migrations must be plain JS (not TS). Backstage runs them
7
+ * at runtime without a TypeScript loader.
8
+ */
9
+
10
+ /**
11
+ * @param {import('knex').Knex} knex
12
+ */
13
+ exports.up = async function (knex) {
14
+ // Seed default rings
15
+ await knex('rings').insert([
16
+ { name: 'Adopt', color: '#5ba300' },
17
+ { name: 'Trial', color: '#009eb0' },
18
+ { name: 'Assess', color: '#c7ba00' },
19
+ { name: 'Hold', color: '#e09b96' },
20
+ ]);
21
+ };
22
+
23
+ /**
24
+ * @param {import('knex').Knex} knex
25
+ */
26
+ exports.down = async function (knex) {
27
+ await knex('rings')
28
+ .whereIn('name', ['Adopt', 'Trial', 'Assess', 'Hold'])
29
+ .delete();
30
+ };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Migration: create radar_candidates table
3
+ *
4
+ * Stores Tech radar candidate entries — candidates discovered and
5
+ * proposed for the Tech Radar.
6
+ *
7
+ * NOTE: Migrations must be plain JS (not TS). Backstage runs them
8
+ * at runtime without a TypeScript loader.
9
+ */
10
+
11
+ /**
12
+ * @param {import('knex').Knex} knex
13
+ */
14
+ exports.up = async function (knex) {
15
+ await knex.schema.createTable('radar_candidates', table => {
16
+ table.uuid('id').primary();
17
+
18
+ // Core identity
19
+ table.string('platform_id').notNullable().unique(); // GitHub node_id, HuggingFace repo id, etc.
20
+ table.string('full_name').notNullable().unique();
21
+ table.string('name').notNullable();
22
+ table.text('description').nullable();
23
+ table.text('url').notNullable();
24
+ table.text('homepage').nullable();
25
+ table.string('primary_language').nullable();
26
+ table.text('license').nullable();
27
+ table.uuid('ring').nullable().references('id').inTable('rings');
28
+ table.string('segment').nullable().references('id').inTable('segments');
29
+ table.boolean('in_radar').notNullable().defaultTo(false);
30
+ table.boolean('is_active').notNullable().defaultTo(true);
31
+ table.enum('platform', ['github', 'hugging_face']).notNullable();
32
+ table.timestamp('last_activity_at').notNullable();
33
+ table.timestamp('created_at').notNullable();
34
+ table.timestamp('last_synced_at').notNullable().defaultTo(knex.fn.now());
35
+ });
36
+ };
37
+
38
+ /**
39
+ * @param {import('knex').Knex} knex
40
+ */
41
+ exports.down = async function (knex) {
42
+ await knex.schema.dropTable('radar_candidates');
43
+ };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Migration: create radar_candidates_snapshots table
3
+ *
4
+ * Stores AI radar candidate snapshot entries — snapshots of candidates discovered and
5
+ * proposed for the Tech Radar NG.
6
+ *
7
+ * NOTE: Migrations must be plain JS (not TS). Backstage runs them
8
+ * at runtime without a TypeScript loader.
9
+ */
10
+
11
+ /**
12
+ * @param {import('knex').Knex} knex
13
+ */
14
+ exports.up = async function (knex) {
15
+ await knex.schema.createTable('radar_candidates_snapshots', table => {
16
+ table.uuid('id').primary();
17
+ table
18
+ .uuid('candidate_id')
19
+ .notNullable()
20
+ .references('id')
21
+ .inTable('radar_candidates')
22
+ .onDelete('CASCADE');
23
+ // Core identity
24
+ table.integer('popularity_score').notNullable();
25
+ table.integer('usage_score').notNullable();
26
+ table.timestamp('snapshot_at').notNullable().defaultTo(knex.fn.now());
27
+ });
28
+ };
29
+
30
+ /**
31
+ * @param {import('knex').Knex} knex
32
+ */
33
+ exports.down = async function (knex) {
34
+ await knex.schema.dropTable('radar_candidates_snapshots');
35
+ };
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@nospt/plugin-tech-radar-ng-backend",
3
+ "version": "0.9.0",
4
+ "license": "UNLICENSED",
5
+ "main": "dist/index.cjs.js",
6
+ "types": "dist/index.d.ts",
7
+ "publishConfig": {
8
+ "access": "public",
9
+ "main": "dist/index.cjs.js",
10
+ "types": "dist/index.d.ts"
11
+ },
12
+ "backstage": {
13
+ "role": "backend-plugin",
14
+ "pluginId": "tech-radar-ng",
15
+ "pluginPackages": [
16
+ "@nospt/plugin-tech-radar-ng",
17
+ "@nospt/plugin-tech-radar-ng-backend",
18
+ "@nospt/plugin-tech-radar-ng-common"
19
+ ],
20
+ "features": {
21
+ ".": "@backstage/BackendFeature"
22
+ }
23
+ },
24
+ "scripts": {
25
+ "start": "backstage-cli package start",
26
+ "build": "backstage-cli package build",
27
+ "lint": "backstage-cli package lint",
28
+ "test": "backstage-cli package test",
29
+ "clean": "backstage-cli package clean",
30
+ "prepack": "backstage-cli package prepack",
31
+ "postpack": "backstage-cli package postpack"
32
+ },
33
+ "dependencies": {
34
+ "@backstage/backend-defaults": "^0.15.2",
35
+ "@backstage/backend-plugin-api": "^1.7.0",
36
+ "@backstage/catalog-client": "^1.13.0",
37
+ "@backstage/errors": "^1.2.7",
38
+ "@backstage/integration": "^1.20.1",
39
+ "@backstage/plugin-catalog-node": "^2.0.0",
40
+ "@backstage/types": "^1.2.2",
41
+ "@nospt/plugin-tech-radar-ng-common": "workspace:^",
42
+ "better-sqlite3": "^12.6.2",
43
+ "express": "^4.17.1",
44
+ "express-promise-router": "^4.1.0",
45
+ "uuid": "^13.0.0",
46
+ "zod": "^4.3.6"
47
+ },
48
+ "devDependencies": {
49
+ "@backstage/backend-test-utils": "^1.11.0",
50
+ "@backstage/cli": "^0.35.4",
51
+ "@types/express": "^4.17.6",
52
+ "@types/jest": "^30.0.0",
53
+ "@types/supertest": "^2.0.12",
54
+ "supertest": "^6.2.4"
55
+ },
56
+ "files": [
57
+ "dist",
58
+ "migrations"
59
+ ],
60
+ "typesVersions": {
61
+ "*": {
62
+ "package.json": [
63
+ "package.json"
64
+ ]
65
+ }
66
+ }
67
+ }