Setup initial project
This commit is contained in:
commit
db79af06f7
119 changed files with 20761 additions and 0 deletions
10
docker/.dockerignore
Normal file
10
docker/.dockerignore
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
node_modules
|
||||
.next
|
||||
dist
|
||||
.turbo
|
||||
*.tsbuildinfo
|
||||
.env*
|
||||
.git
|
||||
docs/
|
||||
coverage
|
||||
*.md
|
||||
40
docker/Dockerfile.api
Normal file
40
docker/Dockerfile.api
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# ---- Base ----
|
||||
FROM node:22-alpine AS base
|
||||
WORKDIR /app
|
||||
|
||||
# ---- Dependencies ----
|
||||
FROM base AS dependencies
|
||||
COPY package.json package-lock.json* .npmrc* ./
|
||||
COPY packages/api/package.json ./packages/api/
|
||||
COPY packages/shared/package.json ./packages/shared/
|
||||
RUN npm install --workspace=packages/shared --workspace=packages/api 2>/dev/null || npm install
|
||||
|
||||
# ---- Build ----
|
||||
FROM dependencies AS build
|
||||
COPY packages/shared/ ./packages/shared/
|
||||
COPY packages/api/ ./packages/api/
|
||||
COPY tsconfig.base.json ./
|
||||
RUN npm run build --workspace=packages/shared
|
||||
RUN npm run build --workspace=packages/api
|
||||
|
||||
# ---- Production ----
|
||||
FROM base AS production
|
||||
ENV NODE_ENV=production
|
||||
COPY --from=build /app/packages/api/dist ./packages/api/dist
|
||||
COPY --from=build /app/packages/shared/dist ./packages/shared/dist
|
||||
COPY --from=build /app/node_modules ./node_modules
|
||||
COPY --from=build /app/packages/api/node_modules ./packages/api/node_modules 2>/dev/null || true
|
||||
COPY --from=build /app/packages/api/package.json ./packages/api/
|
||||
COPY --from=build /app/packages/shared/package.json ./packages/shared/
|
||||
COPY --from=build /app/package.json ./
|
||||
EXPOSE 3001
|
||||
CMD ["node", "packages/api/dist/main.js"]
|
||||
|
||||
# ---- Development ----
|
||||
FROM dependencies AS development
|
||||
COPY packages/shared/ ./packages/shared/
|
||||
COPY packages/api/ ./packages/api/
|
||||
COPY tsconfig.base.json ./
|
||||
RUN npm run build --workspace=packages/shared
|
||||
EXPOSE 3001
|
||||
CMD ["node_modules/.bin/tsx", "watch", "packages/api/src/main.ts"]
|
||||
42
docker/Dockerfile.web
Normal file
42
docker/Dockerfile.web
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# ---- Base ----
|
||||
FROM node:22-alpine AS base
|
||||
WORKDIR /app
|
||||
|
||||
# ---- Dependencies ----
|
||||
FROM base AS dependencies
|
||||
COPY package.json package-lock.json* .npmrc* ./
|
||||
COPY packages/web/package.json ./packages/web/
|
||||
COPY packages/shared/package.json ./packages/shared/
|
||||
RUN npm install --workspace=packages/shared --workspace=packages/web 2>/dev/null || npm install
|
||||
|
||||
# ---- Build ----
|
||||
FROM dependencies AS build
|
||||
COPY packages/shared/ ./packages/shared/
|
||||
COPY packages/web/ ./packages/web/
|
||||
COPY tsconfig.base.json ./
|
||||
RUN npm run build --workspace=packages/shared
|
||||
RUN npm run build --workspace=packages/web
|
||||
|
||||
# ---- Production ----
|
||||
FROM base AS production
|
||||
ENV NODE_ENV=production
|
||||
COPY --from=build /app/packages/web/.next ./packages/web/.next
|
||||
COPY --from=build /app/packages/web/public ./packages/web/public
|
||||
COPY --from=build /app/packages/web/package.json ./packages/web/
|
||||
COPY --from=build /app/packages/shared/dist ./packages/shared/dist
|
||||
COPY --from=build /app/packages/shared/package.json ./packages/shared/
|
||||
COPY --from=build /app/node_modules ./node_modules
|
||||
COPY --from=build /app/package.json ./
|
||||
EXPOSE 3000
|
||||
WORKDIR /app/packages/web
|
||||
CMD ["node", "/app/node_modules/.bin/next", "start", "-p", "3000"]
|
||||
|
||||
# ---- Development ----
|
||||
FROM dependencies AS development
|
||||
COPY packages/shared/ ./packages/shared/
|
||||
COPY packages/web/ ./packages/web/
|
||||
COPY tsconfig.base.json ./
|
||||
RUN npm run build --workspace=packages/shared
|
||||
EXPOSE 3000
|
||||
WORKDIR /app/packages/web
|
||||
CMD ["node", "/app/node_modules/.bin/next", "dev", "--port", "3000", "--turbopack"]
|
||||
139
docker/docker-compose.yml
Normal file
139
docker/docker-compose.yml
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
services:
|
||||
mongodb:
|
||||
image: mongo:7
|
||||
container_name: meshitrack-mongodb
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '27017:27017'
|
||||
environment:
|
||||
MONGO_INITDB_ROOT_USERNAME: meshitrack
|
||||
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD:-devpassword}
|
||||
MONGO_INITDB_DATABASE: meshitrack
|
||||
volumes:
|
||||
- mongo-data:/data/db
|
||||
- ./mongo/init-replica.js:/docker-entrypoint-initdb.d/init-replica.js:ro
|
||||
- ./mongo/keyfile:/tmp/mongo-keyfile:ro
|
||||
- ./mongo/docker-entrypoint-init.sh:/usr/local/bin/docker-entrypoint-init.sh:ro
|
||||
entrypoint: ['/bin/bash', '/usr/local/bin/docker-entrypoint-init.sh']
|
||||
command: ['--replSet', 'rs0', '--bind_ip_all', '--keyFile', '/etc/mongodb/keyfile']
|
||||
healthcheck:
|
||||
test: ['CMD', 'mongosh', '--eval', "db.adminCommand('ping')"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
keycloak:
|
||||
image: quay.io/keycloak/keycloak:24.0
|
||||
container_name: meshitrack-keycloak
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '8080:8080'
|
||||
environment:
|
||||
KC_DB: dev-file
|
||||
KEYCLOAK_ADMIN: admin
|
||||
KEYCLOAK_ADMIN_PASSWORD: ${KC_ADMIN_PASSWORD:-admin}
|
||||
KC_HEALTH_ENABLED: 'true'
|
||||
KC_HOSTNAME_URL: http://localhost:8080
|
||||
command: start-dev --import-realm
|
||||
volumes:
|
||||
- ./keycloak/realm-export.json:/opt/keycloak/data/import/realm-export.json:ro
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
'CMD',
|
||||
'bash',
|
||||
'-c',
|
||||
"exec 3<>/dev/tcp/127.0.0.1/8080 && echo -e 'GET /health/ready HTTP/1.0\\r\\n\\r\\n' >&3 && cat <&3 | grep -q 'UP'",
|
||||
]
|
||||
interval: 15s
|
||||
timeout: 10s
|
||||
retries: 15
|
||||
start_period: 60s
|
||||
|
||||
mongo-init:
|
||||
image: mongo:7
|
||||
container_name: meshitrack-mongo-init
|
||||
restart: on-failure
|
||||
depends_on:
|
||||
mongodb:
|
||||
condition: service_healthy
|
||||
entrypoint: >
|
||||
mongosh --host mongodb:27017
|
||||
--username meshitrack
|
||||
--password ${MONGO_PASSWORD:-devpassword}
|
||||
--authenticationDatabase admin
|
||||
--eval "
|
||||
try { rs.initiate({_id:'rs0',members:[{_id:0,host:'mongodb:27017'}]}) }
|
||||
catch(e) { if(e.codeName !== 'AlreadyInitialized') throw e }
|
||||
"
|
||||
|
||||
api:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/Dockerfile.api
|
||||
target: development
|
||||
container_name: meshitrack-api
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '3001:3001'
|
||||
depends_on:
|
||||
mongo-init:
|
||||
condition: service_completed_successfully
|
||||
keycloak:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
NODE_ENV: development
|
||||
PORT: 3001
|
||||
MONGODB_URI: mongodb://meshitrack:${MONGO_PASSWORD:-devpassword}@mongodb:27017/meshitrack?authSource=admin&replicaSet=rs0
|
||||
KEYCLOAK_URL: http://keycloak:8080
|
||||
KEYCLOAK_ISSUER_URL: http://localhost:8080
|
||||
KEYCLOAK_REALM: meshitrack
|
||||
KEYCLOAK_CLIENT_ID: meshitrack-api
|
||||
CORS_ORIGIN: http://localhost:3000
|
||||
volumes:
|
||||
- ../packages/api/src:/app/packages/api/src
|
||||
- ../packages/shared/src:/app/packages/shared/src
|
||||
|
||||
web:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: docker/Dockerfile.web
|
||||
target: development
|
||||
container_name: meshitrack-web
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- '3000:3000'
|
||||
depends_on:
|
||||
- api
|
||||
environment:
|
||||
NODE_ENV: development
|
||||
NEXT_PUBLIC_API_URL: http://localhost:3001/api/v1
|
||||
NEXT_PUBLIC_KEYCLOAK_URL: http://localhost:8080
|
||||
NEXT_PUBLIC_KEYCLOAK_REALM: meshitrack
|
||||
NEXT_PUBLIC_KEYCLOAK_CLIENT_ID: meshitrack-web
|
||||
KEYCLOAK_URL: http://keycloak:8080
|
||||
KEYCLOAK_REALM: meshitrack
|
||||
KEYCLOAK_CLIENT_ID: meshitrack-web
|
||||
KEYCLOAK_CLIENT_SECRET: dev-web-client-secret
|
||||
NEXTAUTH_URL: http://localhost:3000
|
||||
NEXTAUTH_SECRET: ${NEXTAUTH_SECRET:-dev-secret-change-in-production}
|
||||
volumes:
|
||||
- ../packages/web/src:/app/packages/web/src
|
||||
|
||||
mongo-express:
|
||||
image: mongo-express
|
||||
container_name: meshitrack-mongo-express
|
||||
ports:
|
||||
- '8081:8081'
|
||||
depends_on:
|
||||
mongodb:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
ME_CONFIG_MONGODB_ADMINUSERNAME: meshitrack
|
||||
ME_CONFIG_MONGODB_ADMINPASSWORD: ${MONGO_PASSWORD:-devpassword}
|
||||
ME_CONFIG_MONGODB_URL: mongodb://meshitrack:${MONGO_PASSWORD:-devpassword}@mongodb:27017/
|
||||
profiles:
|
||||
- dev
|
||||
|
||||
volumes:
|
||||
mongo-data:
|
||||
123
docker/keycloak/realm-export.json
Normal file
123
docker/keycloak/realm-export.json
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
{
|
||||
"realm": "meshitrack",
|
||||
"enabled": true,
|
||||
"displayName": "MeshiTrack",
|
||||
"registrationAllowed": true,
|
||||
"loginWithEmailAllowed": true,
|
||||
"duplicateEmailsAllowed": false,
|
||||
"resetPasswordAllowed": true,
|
||||
"editUsernameAllowed": false,
|
||||
"sslRequired": "none",
|
||||
"accessTokenLifespan": 1800,
|
||||
"ssoSessionIdleTimeout": 86400,
|
||||
"ssoSessionMaxLifespan": 604800,
|
||||
"roles": {
|
||||
"realm": [
|
||||
{
|
||||
"name": "admin",
|
||||
"description": "Administrator role - can manage household settings",
|
||||
"composite": false
|
||||
},
|
||||
{
|
||||
"name": "member",
|
||||
"description": "Standard member role",
|
||||
"composite": false
|
||||
}
|
||||
]
|
||||
},
|
||||
"defaultRoles": ["member"],
|
||||
"clients": [
|
||||
{
|
||||
"clientId": "meshitrack-web",
|
||||
"name": "MeshiTrack Web App",
|
||||
"enabled": true,
|
||||
"publicClient": false,
|
||||
"secret": "dev-web-client-secret",
|
||||
"standardFlowEnabled": true,
|
||||
"implicitFlowEnabled": false,
|
||||
"directAccessGrantsEnabled": true,
|
||||
"redirectUris": [
|
||||
"http://localhost:3000/*",
|
||||
"http://localhost:3000",
|
||||
"http://localhost:3000/api/auth/callback/keycloak"
|
||||
],
|
||||
"webOrigins": ["http://localhost:3000"],
|
||||
"attributes": {},
|
||||
"protocolMappers": [
|
||||
{
|
||||
"name": "household-ids-mapper",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-usermodel-attribute-mapper",
|
||||
"config": {
|
||||
"claim.name": "householdIds",
|
||||
"user.attribute": "householdIds",
|
||||
"jsonType.label": "JSON",
|
||||
"id.token.claim": "true",
|
||||
"access.token.claim": "true",
|
||||
"userinfo.token.claim": "true",
|
||||
"multivalued": "false"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "audience-mapper",
|
||||
"protocol": "openid-connect",
|
||||
"protocolMapper": "oidc-audience-mapper",
|
||||
"config": {
|
||||
"included.client.audience": "meshitrack-api",
|
||||
"id.token.claim": "false",
|
||||
"access.token.claim": "true"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"clientId": "meshitrack-api",
|
||||
"name": "MeshiTrack API",
|
||||
"enabled": true,
|
||||
"publicClient": false,
|
||||
"bearerOnly": true,
|
||||
"standardFlowEnabled": false,
|
||||
"directAccessGrantsEnabled": false
|
||||
}
|
||||
],
|
||||
"users": [
|
||||
{
|
||||
"username": "testuser1",
|
||||
"enabled": true,
|
||||
"email": "testuser1@meshitrack.local",
|
||||
"firstName": "Test",
|
||||
"lastName": "User1",
|
||||
"emailVerified": true,
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "test1234",
|
||||
"temporary": false
|
||||
}
|
||||
],
|
||||
"realmRoles": ["member", "admin"],
|
||||
"attributes": {
|
||||
"householdIds": ["[\"000000000000000000000001\"]"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"username": "testuser2",
|
||||
"enabled": true,
|
||||
"email": "testuser2@meshitrack.local",
|
||||
"firstName": "Test",
|
||||
"lastName": "User2",
|
||||
"emailVerified": true,
|
||||
"credentials": [
|
||||
{
|
||||
"type": "password",
|
||||
"value": "test1234",
|
||||
"temporary": false
|
||||
}
|
||||
],
|
||||
"realmRoles": ["member"],
|
||||
"attributes": {
|
||||
"householdIds": ["[\"000000000000000000000001\"]"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
7
docker/mongo/docker-entrypoint-init.sh
Normal file
7
docker/mongo/docker-entrypoint-init.sh
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
#!/bin/bash
|
||||
# Copy the mounted keyfile and set required permissions
|
||||
mkdir -p /etc/mongodb
|
||||
cp /tmp/mongo-keyfile /etc/mongodb/keyfile
|
||||
chmod 400 /etc/mongodb/keyfile
|
||||
chown mongodb:mongodb /etc/mongodb/keyfile
|
||||
exec docker-entrypoint.sh "$@"
|
||||
15
docker/mongo/init-replica.js
Normal file
15
docker/mongo/init-replica.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
// MongoDB replica set initialization script
|
||||
// Runs on first startup via /docker-entrypoint-initdb.d/
|
||||
try {
|
||||
rs.initiate({
|
||||
_id: 'rs0',
|
||||
members: [{ _id: 0, host: 'mongodb:27017' }],
|
||||
});
|
||||
print('Replica set initiated successfully');
|
||||
} catch (e) {
|
||||
if (e.codeName === 'AlreadyInitialized') {
|
||||
print('Replica set already initialized');
|
||||
} else {
|
||||
print('Error initiating replica set: ' + e.message);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue