Skip to content

Commit 54086c7

Browse files
fix:Deployment initiation
1 parent ce4dd45 commit 54086c7

File tree

15 files changed

+227
-48
lines changed

15 files changed

+227
-48
lines changed

.github/workflows/deploy.yml

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
name: KisunaUI CI/CD Pipeline
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
lint:
10+
name: Lint Code
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
- name: Install deps
15+
run: npm ci
16+
- name: Run linter
17+
run: npm run lint
18+
19+
build:
20+
name: Build API
21+
runs-on: ubuntu-latest
22+
needs: lint
23+
steps:
24+
- uses: actions/checkout@v4
25+
- name: Install deps
26+
run: npm ci
27+
- name: Build project
28+
run: npm run build
29+
30+
deploy:
31+
name: Deploy to VPS
32+
runs-on: ubuntu-latest
33+
needs: build
34+
steps:
35+
- name: Checkout repo
36+
uses: actions/checkout@v4
37+
38+
- name: Setup SSH
39+
uses: webfactory/ssh-agent@v0.9.0
40+
with:
41+
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
42+
43+
- name: Add VPS to known_hosts
44+
run: |
45+
ssh-keyscan -H ${{ secrets.VPS_HOST }} >> ~/.ssh/known_hosts
46+
47+
- name: Set env vars
48+
run: |
49+
ssh-keyscan -H ${{ secrets.VPS_HOST }} >> ~/.ssh/known_hosts
50+
echo "DEPLOY_DIR=~/deployments/kisuna/api/current" >> $GITHUB_ENV
51+
52+
- name: Deploy to VPS
53+
run: |
54+
ssh ${{ secrets.VPS_USER }}@${{ secrets.VPS_HOST }} 'bash -s' << EOF
55+
set -euo pipefail
56+
57+
DEPLOY_DIR=~/deployments/kisuna/api/current
58+
59+
if [ ! -d $DEPLOY_DIR ]; then
60+
mkdir -p $DEPLOY_DIR
61+
git clone https://github.com/${{ github.repository }} $DEPLOY_DIR
62+
else
63+
cd $DEPLOY_DIR
64+
git pull origin main
65+
fi
66+
67+
ls /root
68+
69+
cd $DEPLOY_DIR
70+
71+
export DOCKER_BUILDKIT=0
72+
73+
# Remove any containers that might conflict
74+
docker rm -f kisunaapi 2>/dev/null || true
75+
docker rmi current-kisunaapi:latest 2>/dev/null || true
76+
77+
# Build and run the new image
78+
docker compose up -d --build
79+
80+
# Health check loop
81+
for i in {1..10}; do
82+
if curl --fail http://localhost:5002; then
83+
echo "✅ Health check passed"
84+
break
85+
fi
86+
echo "⏳ Waiting for app to be ready... ($i/10)"
87+
sleep 6
88+
done
89+
90+
echo "🎯 Deployment complete"
91+
exit 0
92+
EOF
93+
94+
- name: Confirm remote session is done
95+
run: echo "🧠 SSH session completed cleanly"

Dockerfile

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# ---- Build Stage ----
2+
FROM node:22-alpine AS base
3+
4+
WORKDIR /app
5+
6+
COPY package*.json ./
7+
RUN npm ci
8+
COPY . .
9+
10+
RUN npx prisma generate && \
11+
npm run build
12+
13+
# ---- Runtime Stage ----
14+
FROM base AS runtime
15+
16+
WORKDIR /app
17+
18+
# Copy built files
19+
COPY --from=base /app/package*.json ./
20+
COPY --from=base /app/node_modules ./node_modules
21+
# COPY --from=base /app/generated/prisma ./generated/prisma
22+
COPY --from=base /app/prisma ./prisma
23+
COPY --from=base /app/build ./build
24+
25+
# Copy runtime code if needed
26+
COPY --from=base /app/src ./src
27+
28+
# Install production-only dependencies
29+
# (optional if you've already installed them above)
30+
# RUN npm ci --omit=dev
31+
32+
# Wait-for script (can also be added via volume or Dockerfile ADD)
33+
ADD https://raw.githubusercontent.com/eficode/wait-for/v2.2.3/wait-for /wait-for
34+
RUN chmod +x /wait-for
35+
36+
EXPOSE 5000
37+
38+
# Run prisma migrations and start app after MySQL is up
39+
# CMD sh -c "/wait-for ${DB_HOST:-localhost}:${DB_PORT:-3306} --timeout=360 -- \
40+
# npx prisma migrate deploy && \
41+
# npm run start"
42+
43+
# CMD sh -c "npx prisma migrate reset --force && npx prisma migrate deploy && \
44+
# npm run start"
45+
CMD sh -c "npx prisma migrate deploy && \
46+
npm run start"
47+

docker-compose.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
services:
2+
kisunaapi:
3+
container_name: kisunaapi
4+
build:
5+
context: ./
6+
dockerfile: Dockerfile
7+
restart: unless-stopped
8+
env_file:
9+
- ../.env
10+
volumes:
11+
- /root/backup/kisuna/api-data:/app/uploads
12+
ports:
13+
- "5002:5000"
14+
depends_on:
15+
- postgres
16+
networks:
17+
- caddy-net
18+
19+
postgres:
20+
container_name: kisuna_postgres
21+
image: postgres:16
22+
restart: unless-stopped
23+
env_file:
24+
- ../.env
25+
volumes:
26+
- /root/backup/kisuna/postgres-data:/var/lib/postgresql/data
27+
ports:
28+
- "5432:5432"
29+
networks:
30+
- caddy-net
31+
32+
networks:
33+
caddy-net:
34+
driver: bridge
35+
attachable: true

eslint.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default defineConfig([
1212
},
1313
{
1414
rules: {
15-
"@typescript-eslint/no-explicit-any": "off"
15+
// "@typescript-eslint/no-explicit-any": "off"
1616
}
1717
}
1818
]);

src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ class ApiServer {
4646
this.app.use(`/api/v${GENERAL_CONFIG.app.version}/health`, (req, res) => {
4747
res.status(200).json("Up and running");
4848
});
49+
this.baseModule();
4950
}
5051

5152
// connect base module
@@ -85,8 +86,6 @@ class ApiServer {
8586
}
8687

8788
public start() {
88-
this.baseModule();
89-
9089
// server swagger
9190
this.app.use(
9291
["/openapi", "/docs", "/swagger"],

src/lib/serverUtils.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ export async function checkModules(
99
}[]
1010
) {
1111
// utils/serviceHealth.ts
12-
const results: Record<string, any> = {};
12+
const results: Record<
13+
string,
14+
{ connected: boolean; details?: unknown; message?: string }
15+
> = {};
1316

1417
for (const module of modules) {
1518
try {
@@ -19,8 +22,8 @@ export async function checkModules(
1922
modules = modules.map((m) =>
2023
m.name === module.name ? { ...m, status: "active" } : m
2124
);
22-
} catch (err: any) {
23-
results[module.name] = { connected: false, message: err.message };
25+
} catch {
26+
results[module.name] = { connected: false, message: "error" };
2427
modules = modules.map((m) =>
2528
m.name === module.name ? { ...m, status: "inactive" } : m
2629
);
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import "dotenv/config";
22
import { defineConfig, env } from "prisma/config";
33

44
export default defineConfig({
5-
schema: "./schema.prisma",
5+
schema: "../prisma/schema.prisma",
66
migrations: {
7-
path: "./migrations",
7+
path: "../prisma/migrations",
88
},
99
datasource: {
1010
url: env("DATABASE_URL"),

src/routes/companyRoutes.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default class CompanyRout {
1616
.then((company) =>
1717
res.status(201).json({ message: "registered", data: company })
1818
)
19-
.catch((err) => res.status(400).json({ error: "could not register" }));
19+
.catch(() => res.status(400).json({ error: "could not register" }));
2020
});
2121

2222
this.routes.put("/:id", (req, res) => {
@@ -25,7 +25,7 @@ export default class CompanyRout {
2525
.then((company) =>
2626
res.status(201).json({ message: "updated", data: company })
2727
)
28-
.catch((err) => res.status(400).json({ error: "could not update" }));
28+
.catch(() => res.status(400).json({ error: "could not update" }));
2929
});
3030

3131
this.routes.get("/", (req, res) => {
@@ -34,7 +34,7 @@ export default class CompanyRout {
3434
.then((company) =>
3535
res.status(201).json({ message: "found", data: company })
3636
)
37-
.catch((err) => res.status(400).json({ error: "could not find" }));
37+
.catch(() => res.status(400).json({ error: "could not find" }));
3838
});
3939

4040
this.routes.get("/:id", (req, res) => {
@@ -43,7 +43,7 @@ export default class CompanyRout {
4343
.then((company) =>
4444
res.status(201).json({ message: "found", data: company })
4545
)
46-
.catch((err) => res.status(400).json({ error: "could not find" }));
46+
.catch(() => res.status(400).json({ error: "could not find" }));
4747
});
4848

4949
this.routes.delete("/:id", (req, res) => {
@@ -52,7 +52,7 @@ export default class CompanyRout {
5252
.then((company) =>
5353
res.status(201).json({ message: "deleted", data: company })
5454
)
55-
.catch((err) => res.status(400).json({ error: "could not delete" }));
55+
.catch(() => res.status(400).json({ error: "could not delete" }));
5656
});
5757
}
5858
}

src/routes/congeRoutes.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default class CongeRout {
1616
.then((conge) =>
1717
res.status(201).json({ message: "registered", data: conge })
1818
)
19-
.catch((err) => res.status(400).json({ error: "could not register" }));
19+
.catch(() => res.status(400).json({ error: "could not register" }));
2020
});
2121

2222
this.routes.put("/:id", (req, res) => {
@@ -25,7 +25,7 @@ export default class CongeRout {
2525
.then((conge) =>
2626
res.status(201).json({ message: "updated", data: conge })
2727
)
28-
.catch((err) => res.status(400).json({ error: "could not update" }));
28+
.catch(() => res.status(400).json({ error: "could not update" }));
2929
});
3030

3131
this.routes.get("/", (req, res) => {
@@ -34,7 +34,7 @@ export default class CongeRout {
3434
.then((conge) =>
3535
res.status(201).json({ message: "found", data: conge })
3636
)
37-
.catch((err) => res.status(400).json({ error: "could not find" }));
37+
.catch(() => res.status(400).json({ error: "could not find" }));
3838
});
3939

4040
this.routes.get("/:id", (req, res) => {
@@ -43,7 +43,7 @@ export default class CongeRout {
4343
.then((conge) =>
4444
res.status(201).json({ message: "found", data: conge })
4545
)
46-
.catch((err) => res.status(400).json({ error: "could not find" }));
46+
.catch(() => res.status(400).json({ error: "could not find" }));
4747
});
4848

4949
this.routes.delete("/:id", (req, res) => {
@@ -52,7 +52,7 @@ export default class CongeRout {
5252
.then((conge) =>
5353
res.status(201).json({ message: "deleted", data: conge })
5454
)
55-
.catch((err) => res.status(400).json({ error: "could not delete" }));
55+
.catch(() => res.status(400).json({ error: "could not delete" }));
5656
});
5757
}
5858
}

src/routes/dipeRoutes.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export default class DipeRout {
1616
.then((dipe) =>
1717
res.status(201).json({ message: "registered", data: dipe })
1818
)
19-
.catch((err) => res.status(400).json({ error: "could not register" }));
19+
.catch(() => res.status(400).json({ error: "could not register" }));
2020
});
2121

2222
this.routes.put("/:id", (req, res) => {
@@ -25,21 +25,21 @@ export default class DipeRout {
2525
.then((dipe) =>
2626
res.status(201).json({ message: "updated", data: dipe })
2727
)
28-
.catch((err) => res.status(400).json({ error: "could not update" }));
28+
.catch(() => res.status(400).json({ error: "could not update" }));
2929
});
3030

3131
this.routes.get("/", (req, res) => {
3232
this.dipeCtrl
3333
.getAll()
3434
.then((dipe) => res.status(201).json({ message: "found", data: dipe }))
35-
.catch((err) => res.status(400).json({ error: "could not find" }));
35+
.catch(() => res.status(400).json({ error: "could not find" }));
3636
});
3737

3838
this.routes.get("/:id", (req, res) => {
3939
this.dipeCtrl
4040
.getOne(req.params.id)
4141
.then((dipe) => res.status(201).json({ message: "found", data: dipe }))
42-
.catch((err) => res.status(400).json({ error: "could not find" }));
42+
.catch(() => res.status(400).json({ error: "could not find" }));
4343
});
4444

4545
this.routes.delete("/:id", (req, res) => {
@@ -48,7 +48,7 @@ export default class DipeRout {
4848
.then((dipe) =>
4949
res.status(201).json({ message: "deleted", data: dipe })
5050
)
51-
.catch((err) => res.status(400).json({ error: "could not delete" }));
51+
.catch(() => res.status(400).json({ error: "could not delete" }));
5252
});
5353
}
5454
}

0 commit comments

Comments
 (0)