@insureco/cli 0.1.1 → 0.1.5
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/dist/commands/git.d.ts +30 -0
- package/dist/commands/git.d.ts.map +1 -0
- package/dist/commands/git.js +300 -0
- package/dist/commands/git.js.map +1 -0
- package/dist/commands/oauth.d.ts +33 -0
- package/dist/commands/oauth.d.ts.map +1 -0
- package/dist/commands/oauth.js +181 -0
- package/dist/commands/oauth.js.map +1 -0
- package/dist/commands/user.d.ts +13 -0
- package/dist/commands/user.d.ts.map +1 -0
- package/dist/commands/user.js +96 -0
- package/dist/commands/user.js.map +1 -0
- package/dist/index.js +142 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/bio.d.ts +13 -0
- package/dist/lib/bio.d.ts.map +1 -0
- package/dist/lib/bio.js +63 -0
- package/dist/lib/bio.js.map +1 -0
- package/dist/lib/builder.d.ts +17 -1
- package/dist/lib/builder.d.ts.map +1 -1
- package/dist/lib/builder.js +53 -2
- package/dist/lib/builder.js.map +1 -1
- package/dist/lib/config.js +1 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/forgejo.d.ts +149 -0
- package/dist/lib/forgejo.d.ts.map +1 -0
- package/dist/lib/forgejo.js +137 -0
- package/dist/lib/forgejo.js.map +1 -0
- package/dist/templates/api/.env.example +15 -0
- package/dist/templates/api/Dockerfile +45 -0
- package/dist/templates/api/README.md +85 -0
- package/dist/templates/api/catalog-info.yaml +51 -0
- package/dist/templates/api/helm/{{name}}/Chart.yaml +9 -0
- package/dist/templates/api/helm/{{name}}/templates/deployment.yaml +68 -0
- package/dist/templates/api/helm/{{name}}/templates/service.yaml +17 -0
- package/dist/templates/api/helm/{{name}}/values.yaml +55 -0
- package/dist/templates/api/package.json +33 -0
- package/dist/templates/api/src/index.ts +61 -0
- package/dist/templates/api/src/routes/example.ts +162 -0
- package/dist/templates/api/tsconfig.json +18 -0
- package/dist/templates/crosspod/README.md +87 -0
- package/dist/templates/crosspod/service-a/Dockerfile +27 -0
- package/dist/templates/crosspod/service-a/catalog-info.yaml +54 -0
- package/dist/templates/crosspod/service-a/helm/{{name}}-service-a/Chart.yaml +6 -0
- package/dist/templates/crosspod/service-a/helm/{{name}}-service-a/values.yaml +35 -0
- package/dist/templates/crosspod/service-a/package.json +29 -0
- package/dist/templates/crosspod/service-a/src/index.ts +89 -0
- package/dist/templates/crosspod/service-a/tsconfig.json +14 -0
- package/dist/templates/crosspod/service-b/Dockerfile +27 -0
- package/dist/templates/crosspod/service-b/catalog-info.yaml +27 -0
- package/dist/templates/crosspod/service-b/helm/{{name}}-service-b/Chart.yaml +6 -0
- package/dist/templates/crosspod/service-b/helm/{{name}}-service-b/values.yaml +38 -0
- package/dist/templates/crosspod/service-b/package.json +26 -0
- package/dist/templates/crosspod/service-b/src/index.ts +143 -0
- package/dist/templates/crosspod/service-b/tsconfig.json +14 -0
- package/dist/templates/nextjs/.env.example +11 -0
- package/dist/templates/nextjs/Dockerfile +51 -0
- package/dist/templates/nextjs/README.md +87 -0
- package/dist/templates/nextjs/catalog-info.yaml +16 -0
- package/dist/templates/nextjs/helm/{{name}}/Chart.yaml +9 -0
- package/dist/templates/nextjs/helm/{{name}}/templates/deployment.yaml +68 -0
- package/dist/templates/nextjs/helm/{{name}}/templates/service.yaml +17 -0
- package/dist/templates/nextjs/helm/{{name}}/values.yaml +51 -0
- package/dist/templates/nextjs/next.config.js +23 -0
- package/dist/templates/nextjs/package.json +29 -0
- package/dist/templates/nextjs/public/.gitkeep +0 -0
- package/dist/templates/nextjs/src/app/api/example/route.ts +63 -0
- package/dist/templates/nextjs/src/app/api/health/route.ts +10 -0
- package/dist/templates/nextjs/src/app/layout.tsx +18 -0
- package/dist/templates/nextjs/src/app/page.tsx +49 -0
- package/dist/templates/nextjs/tsconfig.json +26 -0
- package/dist/templates/worker/.env.example +13 -0
- package/dist/templates/worker/Dockerfile +26 -0
- package/dist/templates/worker/README.md +106 -0
- package/dist/templates/worker/catalog-info.yaml +19 -0
- package/dist/templates/worker/helm/{{name}}/Chart.yaml +9 -0
- package/dist/templates/worker/helm/{{name}}/templates/deployment.yaml +64 -0
- package/dist/templates/worker/helm/{{name}}/values.yaml +55 -0
- package/dist/templates/worker/package.json +26 -0
- package/dist/templates/worker/src/index.ts +185 -0
- package/dist/templates/worker/tsconfig.json +14 -0
- package/dist/types/index.d.ts +77 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}-service-b",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Consumer service - calls service-a internally",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc",
|
|
8
|
+
"dev": "tsx watch src/index.ts",
|
|
9
|
+
"start": "node dist/index.js",
|
|
10
|
+
"lint": "eslint src --ext .ts",
|
|
11
|
+
"typecheck": "tsc --noEmit"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"express": "^4.21.0",
|
|
15
|
+
"helmet": "^8.0.0"
|
|
16
|
+
},
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/express": "^5.0.0",
|
|
19
|
+
"@types/node": "^22.0.0",
|
|
20
|
+
"tsx": "^4.0.0",
|
|
21
|
+
"typescript": "^5.7.0"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=20.0.0"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import express, { type Request, type Response, type NextFunction } from 'express'
|
|
2
|
+
import helmet from 'helmet'
|
|
3
|
+
|
|
4
|
+
const app = express()
|
|
5
|
+
const PORT = process.env.PORT || 3000
|
|
6
|
+
const SERVICE_NAME = '{{name}}-service-b'
|
|
7
|
+
|
|
8
|
+
// Service A URL - uses Kubernetes internal DNS
|
|
9
|
+
// Format: http://<service-name>.<namespace>.svc.cluster.local:<port>
|
|
10
|
+
// Simplified: http://<service-name>:<port> when in same namespace
|
|
11
|
+
const SERVICE_A_URL = process.env.SERVICE_A_URL || 'http://{{name}}-service-a:3000'
|
|
12
|
+
|
|
13
|
+
// Middleware
|
|
14
|
+
app.use(helmet())
|
|
15
|
+
app.use(express.json())
|
|
16
|
+
|
|
17
|
+
// Request logging
|
|
18
|
+
app.use((req: Request, _res: Response, next: NextFunction) => {
|
|
19
|
+
const timestamp = new Date().toISOString()
|
|
20
|
+
process.stdout.write(`[${timestamp}] ${req.method} ${req.path}\n`)
|
|
21
|
+
next()
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
// Health check
|
|
25
|
+
app.get('/health', (_req: Request, res: Response) => {
|
|
26
|
+
res.json({
|
|
27
|
+
status: 'healthy',
|
|
28
|
+
service: SERVICE_NAME,
|
|
29
|
+
timestamp: new Date().toISOString(),
|
|
30
|
+
})
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
// Helper function to call service-a
|
|
34
|
+
async function callServiceA(path: string): Promise<unknown> {
|
|
35
|
+
const url = `${SERVICE_A_URL}${path}`
|
|
36
|
+
process.stdout.write(`Calling service-a: ${url}\n`)
|
|
37
|
+
|
|
38
|
+
const response = await fetch(url, {
|
|
39
|
+
headers: {
|
|
40
|
+
'Content-Type': 'application/json',
|
|
41
|
+
// Identify ourselves for logging/tracing
|
|
42
|
+
'X-Service-Name': SERVICE_NAME,
|
|
43
|
+
// In production, include service credentials for auth: service routes
|
|
44
|
+
// 'Authorization': `Bearer ${process.env.SERVICE_TOKEN}`,
|
|
45
|
+
},
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
throw new Error(`Service A returned ${response.status}`)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return response.json()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Public API that aggregates data from service-a
|
|
56
|
+
app.get('/api/data', async (_req: Request, res: Response) => {
|
|
57
|
+
try {
|
|
58
|
+
// Call service-a's internal API
|
|
59
|
+
const serviceAResponse = await callServiceA('/api/internal/items') as {
|
|
60
|
+
success: boolean
|
|
61
|
+
data: Array<{ id: string; name: string; value: number; source: string }>
|
|
62
|
+
meta: { source: string; timestamp: string }
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Process and transform the data
|
|
66
|
+
const processedData = {
|
|
67
|
+
items: serviceAResponse.data.map(item => ({
|
|
68
|
+
...item,
|
|
69
|
+
processedBy: SERVICE_NAME,
|
|
70
|
+
displayValue: `$${item.value.toFixed(2)}`,
|
|
71
|
+
})),
|
|
72
|
+
totalValue: serviceAResponse.data.reduce((sum, item) => sum + item.value, 0),
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
res.json({
|
|
76
|
+
success: true,
|
|
77
|
+
data: processedData,
|
|
78
|
+
meta: {
|
|
79
|
+
aggregator: SERVICE_NAME,
|
|
80
|
+
source: serviceAResponse.meta.source,
|
|
81
|
+
timestamp: new Date().toISOString(),
|
|
82
|
+
},
|
|
83
|
+
})
|
|
84
|
+
} catch (error) {
|
|
85
|
+
process.stderr.write(`Error calling service-a: ${error}\n`)
|
|
86
|
+
res.status(502).json({
|
|
87
|
+
success: false,
|
|
88
|
+
error: {
|
|
89
|
+
code: 'UPSTREAM_ERROR',
|
|
90
|
+
message: 'Failed to retrieve data from upstream service',
|
|
91
|
+
},
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
// Get specific item with enrichment
|
|
97
|
+
app.get('/api/data/:id', async (req: Request, res: Response) => {
|
|
98
|
+
try {
|
|
99
|
+
const response = await callServiceA(`/api/internal/items/${req.params.id}`) as {
|
|
100
|
+
success: boolean
|
|
101
|
+
data: { id: string; name: string; value: number; source: string }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const enrichedItem = {
|
|
105
|
+
...response.data,
|
|
106
|
+
processedBy: SERVICE_NAME,
|
|
107
|
+
displayValue: `$${response.data.value.toFixed(2)}`,
|
|
108
|
+
retrievedAt: new Date().toISOString(),
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
res.json({
|
|
112
|
+
success: true,
|
|
113
|
+
data: enrichedItem,
|
|
114
|
+
})
|
|
115
|
+
} catch (error) {
|
|
116
|
+
const err = error as Error
|
|
117
|
+
if (err.message.includes('404')) {
|
|
118
|
+
res.status(404).json({
|
|
119
|
+
success: false,
|
|
120
|
+
error: { code: 'NOT_FOUND', message: 'Item not found' },
|
|
121
|
+
})
|
|
122
|
+
return
|
|
123
|
+
}
|
|
124
|
+
res.status(502).json({
|
|
125
|
+
success: false,
|
|
126
|
+
error: { code: 'UPSTREAM_ERROR', message: 'Failed to retrieve item' },
|
|
127
|
+
})
|
|
128
|
+
}
|
|
129
|
+
})
|
|
130
|
+
|
|
131
|
+
// Error handler
|
|
132
|
+
app.use((err: Error, _req: Request, res: Response, _next: NextFunction) => {
|
|
133
|
+
process.stderr.write(`Error: ${err.message}\n`)
|
|
134
|
+
res.status(500).json({
|
|
135
|
+
success: false,
|
|
136
|
+
error: { code: 'INTERNAL_ERROR', message: 'Internal error' },
|
|
137
|
+
})
|
|
138
|
+
})
|
|
139
|
+
|
|
140
|
+
app.listen(PORT, () => {
|
|
141
|
+
process.stdout.write(`${SERVICE_NAME} listening on port ${PORT}\n`)
|
|
142
|
+
process.stdout.write(`Configured to call service-a at: ${SERVICE_A_URL}\n`)
|
|
143
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*"],
|
|
13
|
+
"exclude": ["node_modules", "dist"]
|
|
14
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
FROM node:22-alpine AS base
|
|
2
|
+
|
|
3
|
+
# Install dependencies only when needed
|
|
4
|
+
FROM base AS deps
|
|
5
|
+
RUN apk add --no-cache libc6-compat
|
|
6
|
+
WORKDIR /app
|
|
7
|
+
|
|
8
|
+
COPY package*.json ./
|
|
9
|
+
RUN npm ci
|
|
10
|
+
|
|
11
|
+
# Build the application
|
|
12
|
+
FROM base AS builder
|
|
13
|
+
WORKDIR /app
|
|
14
|
+
COPY --from=deps /app/node_modules ./node_modules
|
|
15
|
+
COPY . .
|
|
16
|
+
|
|
17
|
+
ENV NEXT_TELEMETRY_DISABLED 1
|
|
18
|
+
|
|
19
|
+
RUN npm run build
|
|
20
|
+
|
|
21
|
+
# Production image
|
|
22
|
+
FROM base AS runner
|
|
23
|
+
WORKDIR /app
|
|
24
|
+
|
|
25
|
+
ENV NODE_ENV production
|
|
26
|
+
ENV NEXT_TELEMETRY_DISABLED 1
|
|
27
|
+
|
|
28
|
+
RUN addgroup --system --gid 1001 nodejs
|
|
29
|
+
RUN adduser --system --uid 1001 nextjs
|
|
30
|
+
|
|
31
|
+
COPY --from=builder /app/public ./public
|
|
32
|
+
|
|
33
|
+
# Set correct permissions for prerender cache
|
|
34
|
+
RUN mkdir .next
|
|
35
|
+
RUN chown nextjs:nodejs .next
|
|
36
|
+
|
|
37
|
+
# Automatically leverage output traces to reduce image size
|
|
38
|
+
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
|
39
|
+
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
|
40
|
+
|
|
41
|
+
USER nextjs
|
|
42
|
+
|
|
43
|
+
EXPOSE 3000
|
|
44
|
+
|
|
45
|
+
ENV PORT 3000
|
|
46
|
+
ENV HOSTNAME "0.0.0.0"
|
|
47
|
+
|
|
48
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|
49
|
+
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
|
|
50
|
+
|
|
51
|
+
CMD ["node", "server.js"]
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# {{name}}
|
|
2
|
+
|
|
3
|
+
{{description}}
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
### Prerequisites
|
|
8
|
+
|
|
9
|
+
- Node.js 20+
|
|
10
|
+
- npm or pnpm
|
|
11
|
+
|
|
12
|
+
### Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm install
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Development
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm run dev
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Open [http://localhost:3000](http://localhost:3000) in your browser.
|
|
25
|
+
|
|
26
|
+
### Production Build
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npm run build
|
|
30
|
+
npm start
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Project Structure
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
{{name}}/
|
|
37
|
+
├── src/
|
|
38
|
+
│ └── app/
|
|
39
|
+
│ ├── layout.tsx # Root layout
|
|
40
|
+
│ ├── page.tsx # Home page
|
|
41
|
+
│ └── api/
|
|
42
|
+
│ ├── health/ # Health check endpoint
|
|
43
|
+
│ │ └── route.ts
|
|
44
|
+
│ └── example/ # Example API route
|
|
45
|
+
│ └── route.ts
|
|
46
|
+
├── public/ # Static assets
|
|
47
|
+
├── helm/
|
|
48
|
+
│ └── {{name}}/ # Kubernetes Helm chart
|
|
49
|
+
├── next.config.js # Next.js configuration
|
|
50
|
+
├── Dockerfile
|
|
51
|
+
└── catalog-info.yaml # Backstage service catalog
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## API Routes
|
|
55
|
+
|
|
56
|
+
### Health Check
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
GET /api/health
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Example API
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
GET /api/example # List items
|
|
66
|
+
POST /api/example # Create item (body: { name: string })
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Deployment
|
|
70
|
+
|
|
71
|
+
### Using iec-cli
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# Link repository for auto-deploy
|
|
75
|
+
iec link
|
|
76
|
+
|
|
77
|
+
# Manual deploy to sandbox
|
|
78
|
+
iec deploy
|
|
79
|
+
|
|
80
|
+
# Deploy to production
|
|
81
|
+
iec deploy --prod
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Learn More
|
|
85
|
+
|
|
86
|
+
- [Next.js Documentation](https://nextjs.org/docs)
|
|
87
|
+
- [Tawa Platform Docs](https://docs.tawa.insureco.io)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
apiVersion: backstage.io/v1alpha1
|
|
2
|
+
kind: Component
|
|
3
|
+
metadata:
|
|
4
|
+
name: {{name}}
|
|
5
|
+
description: {{description}}
|
|
6
|
+
tags:
|
|
7
|
+
- tawa
|
|
8
|
+
- frontend
|
|
9
|
+
- nextjs
|
|
10
|
+
annotations:
|
|
11
|
+
insureco.io/framework: nextjs
|
|
12
|
+
insureco.io/language: typescript
|
|
13
|
+
spec:
|
|
14
|
+
type: service
|
|
15
|
+
lifecycle: experimental
|
|
16
|
+
owner: team-platform
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
apiVersion: apps/v1
|
|
2
|
+
kind: Deployment
|
|
3
|
+
metadata:
|
|
4
|
+
name: {{ .Release.Name }}
|
|
5
|
+
labels:
|
|
6
|
+
app: {{ .Release.Name }}
|
|
7
|
+
app.kubernetes.io/name: {{ .Release.Name }}
|
|
8
|
+
app.kubernetes.io/instance: {{ .Release.Name }}
|
|
9
|
+
spec:
|
|
10
|
+
replicas: {{ .Values.replicaCount }}
|
|
11
|
+
selector:
|
|
12
|
+
matchLabels:
|
|
13
|
+
app: {{ .Release.Name }}
|
|
14
|
+
template:
|
|
15
|
+
metadata:
|
|
16
|
+
labels:
|
|
17
|
+
app: {{ .Release.Name }}
|
|
18
|
+
app.kubernetes.io/name: {{ .Release.Name }}
|
|
19
|
+
app.kubernetes.io/instance: {{ .Release.Name }}
|
|
20
|
+
spec:
|
|
21
|
+
{{- with .Values.imagePullSecrets }}
|
|
22
|
+
imagePullSecrets:
|
|
23
|
+
{{- toYaml . | nindent 8 }}
|
|
24
|
+
{{- end }}
|
|
25
|
+
containers:
|
|
26
|
+
- name: {{ .Chart.Name }}
|
|
27
|
+
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
|
28
|
+
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
|
29
|
+
ports:
|
|
30
|
+
- name: http
|
|
31
|
+
containerPort: {{ .Values.service.port }}
|
|
32
|
+
protocol: TCP
|
|
33
|
+
envFrom:
|
|
34
|
+
- configMapRef:
|
|
35
|
+
name: {{ .Release.Name }}-config
|
|
36
|
+
optional: true
|
|
37
|
+
- secretRef:
|
|
38
|
+
name: {{ .Release.Name }}-secrets
|
|
39
|
+
optional: true
|
|
40
|
+
{{- with .Values.env }}
|
|
41
|
+
env:
|
|
42
|
+
{{- range $key, $value := . }}
|
|
43
|
+
- name: {{ $key }}
|
|
44
|
+
value: {{ $value | quote }}
|
|
45
|
+
{{- end }}
|
|
46
|
+
{{- end }}
|
|
47
|
+
{{- with .Values.livenessProbe }}
|
|
48
|
+
livenessProbe:
|
|
49
|
+
{{- toYaml . | nindent 12 }}
|
|
50
|
+
{{- end }}
|
|
51
|
+
{{- with .Values.readinessProbe }}
|
|
52
|
+
readinessProbe:
|
|
53
|
+
{{- toYaml . | nindent 12 }}
|
|
54
|
+
{{- end }}
|
|
55
|
+
resources:
|
|
56
|
+
{{- toYaml .Values.resources | nindent 12 }}
|
|
57
|
+
{{- with .Values.nodeSelector }}
|
|
58
|
+
nodeSelector:
|
|
59
|
+
{{- toYaml . | nindent 8 }}
|
|
60
|
+
{{- end }}
|
|
61
|
+
{{- with .Values.affinity }}
|
|
62
|
+
affinity:
|
|
63
|
+
{{- toYaml . | nindent 8 }}
|
|
64
|
+
{{- end }}
|
|
65
|
+
{{- with .Values.tolerations }}
|
|
66
|
+
tolerations:
|
|
67
|
+
{{- toYaml . | nindent 8 }}
|
|
68
|
+
{{- end }}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
apiVersion: v1
|
|
2
|
+
kind: Service
|
|
3
|
+
metadata:
|
|
4
|
+
name: {{ .Release.Name }}
|
|
5
|
+
labels:
|
|
6
|
+
app: {{ .Release.Name }}
|
|
7
|
+
app.kubernetes.io/name: {{ .Release.Name }}
|
|
8
|
+
app.kubernetes.io/instance: {{ .Release.Name }}
|
|
9
|
+
spec:
|
|
10
|
+
type: {{ .Values.service.type }}
|
|
11
|
+
ports:
|
|
12
|
+
- port: {{ .Values.service.port }}
|
|
13
|
+
targetPort: http
|
|
14
|
+
protocol: TCP
|
|
15
|
+
name: http
|
|
16
|
+
selector:
|
|
17
|
+
app: {{ .Release.Name }}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
replicaCount: 1
|
|
2
|
+
|
|
3
|
+
image:
|
|
4
|
+
repository: registry.digitalocean.com/insureco/{{name}}
|
|
5
|
+
tag: latest
|
|
6
|
+
pullPolicy: IfNotPresent
|
|
7
|
+
|
|
8
|
+
imagePullSecrets:
|
|
9
|
+
- name: do-registry
|
|
10
|
+
|
|
11
|
+
service:
|
|
12
|
+
type: ClusterIP
|
|
13
|
+
port: 3000
|
|
14
|
+
|
|
15
|
+
resources:
|
|
16
|
+
limits:
|
|
17
|
+
cpu: 500m
|
|
18
|
+
memory: 512Mi
|
|
19
|
+
requests:
|
|
20
|
+
cpu: 100m
|
|
21
|
+
memory: 128Mi
|
|
22
|
+
|
|
23
|
+
autoscaling:
|
|
24
|
+
enabled: false
|
|
25
|
+
minReplicas: 1
|
|
26
|
+
maxReplicas: 5
|
|
27
|
+
targetCPUUtilizationPercentage: 80
|
|
28
|
+
|
|
29
|
+
nodeSelector: {}
|
|
30
|
+
|
|
31
|
+
tolerations: []
|
|
32
|
+
|
|
33
|
+
affinity: {}
|
|
34
|
+
|
|
35
|
+
env: {}
|
|
36
|
+
|
|
37
|
+
secrets: {}
|
|
38
|
+
|
|
39
|
+
livenessProbe:
|
|
40
|
+
httpGet:
|
|
41
|
+
path: /api/health
|
|
42
|
+
port: 3000
|
|
43
|
+
initialDelaySeconds: 15
|
|
44
|
+
periodSeconds: 10
|
|
45
|
+
|
|
46
|
+
readinessProbe:
|
|
47
|
+
httpGet:
|
|
48
|
+
path: /api/health
|
|
49
|
+
port: 3000
|
|
50
|
+
initialDelaySeconds: 5
|
|
51
|
+
periodSeconds: 5
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** @type {import('next').NextConfig} */
|
|
2
|
+
const nextConfig = {
|
|
3
|
+
output: 'standalone',
|
|
4
|
+
reactStrictMode: true,
|
|
5
|
+
poweredByHeader: false,
|
|
6
|
+
|
|
7
|
+
// Enable experimental features as needed
|
|
8
|
+
// experimental: {
|
|
9
|
+
// serverActions: true,
|
|
10
|
+
// },
|
|
11
|
+
|
|
12
|
+
// Configure allowed image domains
|
|
13
|
+
// images: {
|
|
14
|
+
// remotePatterns: [
|
|
15
|
+
// {
|
|
16
|
+
// protocol: 'https',
|
|
17
|
+
// hostname: '*.insureco.io',
|
|
18
|
+
// },
|
|
19
|
+
// ],
|
|
20
|
+
// },
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module.exports = nextConfig
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{name}}",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "{{description}}",
|
|
5
|
+
"private": true,
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "next dev",
|
|
8
|
+
"build": "next build",
|
|
9
|
+
"start": "next start",
|
|
10
|
+
"lint": "next lint",
|
|
11
|
+
"typecheck": "tsc --noEmit"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"next": "^14.2.0",
|
|
15
|
+
"react": "^18.3.0",
|
|
16
|
+
"react-dom": "^18.3.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/node": "^22.0.0",
|
|
20
|
+
"@types/react": "^18.3.0",
|
|
21
|
+
"@types/react-dom": "^18.3.0",
|
|
22
|
+
"eslint": "^9.0.0",
|
|
23
|
+
"eslint-config-next": "^14.2.0",
|
|
24
|
+
"typescript": "^5.7.0"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=20.0.0"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { NextRequest, NextResponse } from 'next/server'
|
|
2
|
+
|
|
3
|
+
// In-memory storage for demo
|
|
4
|
+
const items: Map<string, { id: string; name: string; createdAt: string }> = new Map()
|
|
5
|
+
|
|
6
|
+
export async function GET() {
|
|
7
|
+
const itemList = Array.from(items.values())
|
|
8
|
+
return NextResponse.json({
|
|
9
|
+
success: true,
|
|
10
|
+
data: itemList,
|
|
11
|
+
meta: {
|
|
12
|
+
total: itemList.length,
|
|
13
|
+
timestamp: new Date().toISOString(),
|
|
14
|
+
},
|
|
15
|
+
})
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function POST(request: NextRequest) {
|
|
19
|
+
try {
|
|
20
|
+
const body = await request.json()
|
|
21
|
+
|
|
22
|
+
if (!body.name || typeof body.name !== 'string') {
|
|
23
|
+
return NextResponse.json(
|
|
24
|
+
{
|
|
25
|
+
success: false,
|
|
26
|
+
error: {
|
|
27
|
+
code: 'VALIDATION_ERROR',
|
|
28
|
+
message: 'Name is required',
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
{ status: 400 }
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const id = Date.now().toString(36) + Math.random().toString(36).substring(2)
|
|
36
|
+
const item = {
|
|
37
|
+
id,
|
|
38
|
+
name: body.name,
|
|
39
|
+
createdAt: new Date().toISOString(),
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
items.set(id, item)
|
|
43
|
+
|
|
44
|
+
return NextResponse.json(
|
|
45
|
+
{
|
|
46
|
+
success: true,
|
|
47
|
+
data: item,
|
|
48
|
+
},
|
|
49
|
+
{ status: 201 }
|
|
50
|
+
)
|
|
51
|
+
} catch {
|
|
52
|
+
return NextResponse.json(
|
|
53
|
+
{
|
|
54
|
+
success: false,
|
|
55
|
+
error: {
|
|
56
|
+
code: 'PARSE_ERROR',
|
|
57
|
+
message: 'Invalid JSON body',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{ status: 400 }
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Metadata } from 'next'
|
|
2
|
+
|
|
3
|
+
export const metadata: Metadata = {
|
|
4
|
+
title: '{{name}}',
|
|
5
|
+
description: '{{description}}',
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default function RootLayout({
|
|
9
|
+
children,
|
|
10
|
+
}: {
|
|
11
|
+
children: React.ReactNode
|
|
12
|
+
}) {
|
|
13
|
+
return (
|
|
14
|
+
<html lang="en">
|
|
15
|
+
<body>{children}</body>
|
|
16
|
+
</html>
|
|
17
|
+
)
|
|
18
|
+
}
|