Skip to content

Commit 2a43eee

Browse files
committed
fix(setup): fix seed 409 bug, README, docker-compose volumes, and deps
Signed-off-by: yogeshk34 <khutwadyogesh34@gmail.com>
1 parent 6e4d260 commit 2a43eee

5 files changed

Lines changed: 323 additions & 196 deletions

File tree

README.md

Lines changed: 216 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# CREDEBL SSI Platform
22

3-
This repository hosts the codebase for CREDEBL SSI Platform backend.
3+
This repository hosts the codebase for the CREDEBL SSI Platform backend.
4+
5+
> **Note:** This guide covers the GitHub repo-based local setup. For the hosted/cloud setup, see [docs.credebl.id](https://docs.credebl.id).
6+
7+
---
48

59
## Prerequisites
610

@@ -11,15 +15,40 @@ See: https://docs.docker.com/engine/install/
1115
Version: >= 18.17.0
1216
See: https://nodejs.dev/en/learn/how-to-install-nodejs/
1317

18+
### • Install pnpm
19+
20+
> ⚠️ **This project uses `pnpm` as its package manager.** Using `npm install` will fail or produce incorrect results. Do not use `npm`.
21+
22+
```bash
23+
npm install -g pnpm
24+
```
25+
26+
The project is pinned to `pnpm@9.15.3` (see `"packageManager"` in `package.json`).
27+
1428
### • Install NestJS CLI
1529
```bash
16-
npm i @nestjs/cli@latest
30+
pnpm add -g @nestjs/cli
1731
```
1832

33+
---
34+
1935
## Setup Instructions
2036

21-
### • Setup and Run PostgreSQL
22-
Start the PostgreSQL service using Docker:
37+
### Step 1 — Clone the repo and copy env
38+
39+
```bash
40+
git clone https://github.com/credebl/platform.git
41+
cd platform
42+
cp .env.demo .env
43+
```
44+
45+
Edit `.env` with your actual values before proceeding. Key variables are called out in each step below.
46+
47+
---
48+
49+
### Step 2 — Set Up and Run PostgreSQL
50+
51+
Start PostgreSQL via Docker. The credentials and DB name **must match** what you set in `DATABASE_URL` / `POOL_DATABASE_URL` in your `.env`.
2352

2453
```bash
2554
docker run --name credebl-postgres \
@@ -28,67 +57,195 @@ docker run --name credebl-postgres \
2857
-e POSTGRES_PASSWORD=changeme \
2958
-e POSTGRES_DB=credebl \
3059
-v credebl_pgdata:/var/lib/postgresql/data \
60+
--network platform_default \
3161
-d postgres:16
3262
```
3363

34-
### • Run Prisma to Generate Database Schema
64+
Then update your `.env` to match those credentials:
65+
66+
```env
67+
DATABASE_URL="postgresql://credebl:changeme@localhost:5432/credebl"
68+
POOL_DATABASE_URL="postgresql://credebl:changeme@localhost:5432/credebl"
69+
```
70+
71+
> ⚠️ **Do not use `localhost` in `DATABASE_URL` when services run inside Docker containers.** Inside a container, `localhost` resolves to the container itself — not the host. Use your machine's LAN IP (e.g. `192.168.x.x`) or a Docker service name instead. This applies to `KEYCLOAK_DOMAIN` and `KEYCLOAK_ADMIN_URL` as well (see Step 5).
72+
73+
---
74+
75+
### Step 3 — Run Prisma Migrations (Schema Generation)
76+
77+
> ⚠️ **Migrations must run before seeding.** If you seed first, it will fail because the tables don't exist yet.
78+
79+
From the repo root:
3580

3681
```bash
37-
cd ./libs/prisma-service/prisma
38-
npx prisma generate
39-
npx prisma db push
82+
cd libs/prisma-service
83+
npx prisma migrate deploy
4084
```
4185

42-
### • Seed Initial Data
86+
Or use the root-level script:
4387

4488
```bash
45-
cd ./libs/prisma-service
46-
npx prisma db seed
89+
# From repo root
90+
npx prisma migrate deploy --schema=./libs/prisma-service/prisma/schema.prisma
4791
```
4892

49-
## Install NATS Message Broker
93+
---
5094

51-
### • Pull NATS Docker Image
95+
### Step 4 — Set Up Keycloak
5296

53-
NATS is used for inter-service communication. The only prerequisite here is to install Docker.
97+
Keycloak is required for authentication. It is **not started automatically** — you must run it separately and configure it fully before seeding.
98+
99+
#### 4a — Run the Keycloak container
100+
101+
> ⚠️ **Keycloak must be on the same Docker network as the platform services** (`platform_default`), otherwise the containers cannot reach it. Include `--network platform_default` when creating the container.
54102
55103
```bash
56-
docker pull nats:latest
104+
docker run --name credebl-keycloak \
105+
-p 8080:8080 \
106+
-e KEYCLOAK_ADMIN=admin \
107+
-e KEYCLOAK_ADMIN_PASSWORD=admin \
108+
--network platform_default \
109+
-d quay.io/keycloak/keycloak:latest start-dev
110+
```
111+
112+
#### 4b — Create a Realm
113+
114+
1. Open the Keycloak Admin Console: `http://localhost:8080`
115+
2. Log in with `admin` / `admin`
116+
3. Create a new **Realm** named exactly: `credebl-platform`
117+
118+
#### 4c — Create Client 1: `adminClient`
119+
120+
This client is used by the platform seed script and user-service to authenticate platform admin users.
121+
122+
1. In the `credebl-platform` realm → **Clients****Create client**
123+
2. **Client ID:** `adminClient`
124+
3. **Client authentication:** ON (confidential)
125+
4. **Service accounts enabled:** ON
126+
5. Go to **Service account roles** tab → **Assign role** → filter by `realm-management` → add:
127+
- `manage-users`
128+
- `view-users`
129+
- `query-users`
130+
6. Go to **Credentials** tab → copy the **Client Secret**
131+
7. Update `.env`:
132+
133+
```env
134+
ADMIN_KEYCLOAK_ID=adminClient
135+
ADMIN_KEYCLOAK_SECRET=<copied-secret-from-keycloak>
136+
```
137+
138+
#### 4d — Create Client 2: `credeblClient`
139+
140+
This client is the management client used for general Keycloak operations.
141+
142+
1. **Clients****Create client**
143+
2. **Client ID:** `credeblClient`
144+
3. **Client authentication:** ON (confidential)
145+
4. **Service accounts enabled:** ON
146+
5. Go to **Service account roles** tab → **Assign role** → filter by `realm-management` → add:
147+
- `manage-users`
148+
- `view-users`
149+
- `query-users`
150+
- `manage-realm`
151+
6. Go to **Credentials** tab → copy the **Client Secret**
152+
7. Update `.env`:
153+
154+
```env
155+
KEYCLOAK_MANAGEMENT_CLIENT_ID=credeblClient
156+
KEYCLOAK_MANAGEMENT_CLIENT_SECRET=<copied-secret-from-keycloak>
157+
KEYCLOAK_REALM=credebl-platform
158+
KEYCLOAK_MASTER_REALM=master
159+
```
160+
161+
#### 4e — Set Keycloak domain in `.env`
162+
163+
> ⚠️ **If platform services run in Docker containers, do NOT use `localhost` for Keycloak URLs.**
164+
> Use your machine's LAN IP address instead (e.g. `192.168.1.x`). You can find it with `ip addr show` or `hostname -I`.
165+
166+
```env
167+
# For Docker-based deployments — replace with your actual LAN IP:
168+
KEYCLOAK_DOMAIN=http://192.168.x.x:8080/
169+
KEYCLOAK_ADMIN_URL=http://192.168.x.x:8080
170+
171+
# For host-only (no Docker for platform services):
172+
# KEYCLOAK_DOMAIN=http://localhost:8080/
173+
# KEYCLOAK_ADMIN_URL=http://localhost:8080
174+
```
175+
176+
---
177+
178+
### Step 5 — Configure Remaining `.env` Values
179+
180+
Set the following before seeding:
181+
182+
```env
183+
PLATFORM_ADMIN_EMAIL=platform.admin@yopmail.com
184+
CRYPTO_PRIVATE_KEY=YourSecretPrivateKeyHere
57185
```
58186

59-
### • Run NATS using Docker Compose
60-
The `docker-compose.yml` file is available in the root folder.
187+
> `CRYPTO_PRIVATE_KEY` is used to encrypt/decrypt Keycloak client credentials stored in the DB. Keep it consistent across all runs — changing it after seeding will break decryption.
188+
189+
---
190+
191+
### Step 6 — Seed Initial Data
192+
193+
```bash
194+
# From repo root
195+
cd libs/prisma-service
196+
npx prisma db seed
197+
```
198+
199+
The seed script will:
200+
1. Create org roles, agent types, ecosystem roles, ledgers, and user roles
201+
2. Create the platform admin user and organization
202+
3. Create the Keycloak user for the platform admin (or look up an existing one — see note below)
203+
4. Encrypt and store Keycloak `clientId` / `clientSecret` in the DB
204+
205+
> **Re-seeding note:** If the Keycloak user already exists (e.g. on a re-seed), the script will look up the existing user's Keycloak ID and still update the DB record — so `keycloakUserId`, `clientId`, and `clientSecret` are always kept in sync.
206+
207+
---
208+
209+
### Step 7 — Install NATS Message Broker
210+
211+
NATS is used for inter-service communication.
61212

62213
```bash
63-
docker-compose up
214+
docker pull nats:latest
64215
```
65216

66-
## Run CREDEBL Microservices
217+
Then start it (along with other infrastructure) using Docker Compose:
67218

68-
### • Install Dependencies
69219
```bash
70-
npm install
220+
docker compose up -d
71221
```
72222

73-
### • Configure Environment Variables
74-
Configure environment variables in `.env` before you start the API Gateway.
223+
---
75224

76-
### • Running the API Gateway
77-
You can optionally use the `--watch` flag during development/testing.
225+
### Step 8 — Install Dependencies
78226

79227
```bash
80-
nest start [--watch]
228+
# From repo root — use pnpm, not npm
229+
pnpm install
81230
```
82231

83-
### • Starting Individual Microservices
232+
---
233+
234+
### Step 9 — Run CREDEBL Microservices
235+
236+
#### Configure environment variables
237+
238+
Ensure all values in `.env` are set correctly before starting services (see Steps 4–5 above).
84239

85-
For example, to start the `organization service` microservice, run the following command in a separate terminal window:
240+
#### Running the API Gateway
86241

87242
```bash
88-
nest start organization [--watch]
243+
nest start [--watch]
89244
```
90245

91-
Start all the microservices one after another in separate terminal windows:
246+
#### Starting Individual Microservices
247+
248+
Start each microservice in a separate terminal window:
92249

93250
```bash
94251
nest start user [--watch]
@@ -100,18 +257,44 @@ nest start agent-provisioning [--watch]
100257
nest start agent-service [--watch]
101258
```
102259

260+
---
261+
103262
## Access Microservice Endpoints
104263

105-
To access microservice endpoints using the API Gateway, navigate to:
264+
Once the API Gateway is running, Swagger UI is available at:
106265

107266
```
108267
http://localhost:5000/api
109268
```
110269

270+
---
271+
272+
## Troubleshooting
273+
274+
### Sign-in returns 401 after setup
275+
276+
1. **Check `keycloakUserId` in the DB** — it must not be empty for the platform admin user. If it is, re-run the seed (it will now look up and fix this automatically).
277+
2. **Check `KEYCLOAK_DOMAIN`** — if services run in Docker, `localhost` won't resolve to your host machine. Use your LAN IP.
278+
3. **Check Keycloak logs** to confirm the password grant is succeeding.
279+
280+
### Seeding fails with Prisma errors
281+
282+
Ensure `prisma migrate deploy` ran successfully **before** running `prisma db seed`. The tables must exist first.
283+
284+
### Seeding fails with connection errors
285+
286+
Ensure `DATABASE_URL` in `.env` is reachable from where you're running the seed command (host vs. inside Docker makes a difference).
287+
288+
### `npm install` fails or produces wrong results
289+
290+
Use `pnpm install` — the project is configured for `pnpm` and will not work correctly with `npm`.
291+
292+
---
293+
111294
## Credit
112295

113-
The CREDEBL platform is built by AYANWORKS team.
114-
For the core SSI capabilities, it leverages the great work from multiple open-source projects such as Hyperledger Aries, Bifold, Asker, Indy, etc.
296+
The CREDEBL platform is built by the AYANWORKS team.
297+
For core SSI capabilities, it leverages the great work from multiple open-source projects such as Hyperledger Aries, Bifold, Askar, Indy, and others.
115298

116299
## Contributing
117300

docker-compose.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,4 +250,6 @@ services:
250250

251251
volumes:
252252
cache:
253+
driver: local
254+
platform-volume:
253255
driver: local

libs/prisma-service/prisma/seed.ts

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -728,22 +728,39 @@ export async function createKeycloakUser(): Promise<void> {
728728
})
729729
});
730730

731-
if (HttpStatus.CONFLICT === res.status) {
732-
logger.log(`⚠️ User ${user.username} already exists`);
733-
return;
734-
}
731+
let userId: string | undefined;
735732

736-
if (HttpStatus.CREATED !== res.status) {
733+
if (HttpStatus.CONFLICT === res.status) {
734+
// User already exists in Keycloak — look up their ID so we can still update the DB.
735+
// Without this, keycloakUserId stays empty and login silently falls through to Supabase.
736+
logger.log(`⚠️ User ${user.username} already exists in Keycloak — looking up existing user ID`);
737+
const lookupToken = await getKeycloakToken();
738+
const lookupRes = await fetch(
739+
`${KEYCLOAK_DOMAIN}admin/realms/${KEYCLOAK_REALM}/users?username=${encodeURIComponent(user.username)}&exact=true`,
740+
{
741+
headers: { Authorization: `Bearer ${lookupToken}` }
742+
}
743+
);
744+
if (!lookupRes.ok) {
745+
const errText = await lookupRes.text();
746+
throw new Error(`Failed to look up existing Keycloak user (${lookupRes.status}): ${errText}`);
747+
}
748+
const existingUsers = await lookupRes.json();
749+
if (!Array.isArray(existingUsers) || 0 === existingUsers.length) {
750+
throw new Error(`Keycloak returned 409 but no user found for username: ${user.username}`);
751+
}
752+
userId = existingUsers[0].id;
753+
logger.log(`✅ Found existing Keycloak user ID: ${userId}`);
754+
} else if (HttpStatus.CREATED !== res.status) {
737755
const errorText = await res.text();
738756
throw new Error(`Failed to create Keycloak user (${res.status}): ${errorText}`);
757+
} else {
758+
const location = res.headers.get('location');
759+
if (!location) {
760+
throw new Error('Keycloak did not return Location header');
761+
}
762+
userId = location.split('/').pop();
739763
}
740-
const location = res.headers.get('location');
741-
742-
if (!location) {
743-
throw new Error('Keycloak did not return Location header');
744-
}
745-
746-
const userId = location.split('/').pop();
747764

748765
if (userId) {
749766
logger.log('Check if platform admin exists');
@@ -768,7 +785,7 @@ export async function createKeycloakUser(): Promise<void> {
768785
clientSecret: encClientSecret
769786
}
770787
});
771-
logger.log(`✅ Platform admin added and updated to user's table sucessfully`);
788+
logger.log(`✅ Platform admin keycloakUserId, clientId, clientSecret updated in DB successfully`);
772789
} else {
773790
throw new Error('Failed to extract user ID from Location header');
774791
}

0 commit comments

Comments
 (0)