Add monorepo configuration and development environment

This commit is contained in:
2025-07-25 19:14:05 -03:00
parent cedf771f16
commit 9eb293ccb1
8 changed files with 523 additions and 173 deletions

34
.devcontainer/Dockerfile Normal file
View File

@@ -0,0 +1,34 @@
FROM node:18-bullseye
# Install additional tools including Ionic CLI
RUN apt-get update && apt-get install -y \
git \
curl \
vim \
mongodb-clients \
&& rm -rf /var/lib/apt/lists/*
# Install global npm packages for development
RUN npm install -g \
@ionic/cli \
@angular/cli \
nodemon \
concurrently \
eslint \
prettier
# Set working directory
WORKDIR /workspaces/PfosiLooking
# Copy package files for dependency caching
COPY package*.json ./
COPY app/package*.json ./app/
COPY backend/package*.json ./backend/
# Install dependencies
RUN npm install
RUN cd app && npm install
RUN cd backend && npm install
# Keep container running
CMD ["sleep", "infinity"]

18
.devcontainer/dev.env Normal file
View File

@@ -0,0 +1,18 @@
NODE_ENV=development
MONGODB_URI=mongodb://admin:password@localhost:27017/urge?authSource=admin
JWT_SECRET=your-dev-jwt-secret-here
PORT=3069
REACT_APP_API_URL=http://localhost:3069
# MongoDB
MONGO_ROOT_USER=admin
MONGO_ROOT_PASSWORD=password
MONGO_EXPRESS_USER=admin
MONGO_EXPRESS_PASSWORD=password
# Optional API keys for development
GOOGLE_MAPS_API_KEY=your-google-maps-api-key
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USER=your-email@gmail.com
MAIL_PASS=your-email-password

View File

@@ -0,0 +1,60 @@
{
"name": "PfosiLooking Full Stack",
"dockerComposeFile": "docker-compose.yml",
"service": "app",
"workspaceFolder": "/workspaces/PfosiLooking",
"shutdownAction": "stopCompose",
"features": {
"ghcr.io/devcontainers/features/node:1": {
"version": "18"
},
"ghcr.io/devcontainers/features/git:1": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
},
"customizations": {
"vscode": {
"extensions": [
"ms-vscode.vscode-json",
"bradlc.vscode-tailwindcss",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"ms-vscode.vscode-typescript-next",
"formulahendry.auto-rename-tag",
"christian-kohler.path-intellisense",
"ms-vscode.vscode-json",
"mongodb.mongodb-vscode"
],
"settings": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"emmet.includeLanguages": {
"javascript": "javascriptreact"
}
}
}
},
"forwardPorts": [8100, 3069, 27017, 8081],
"portsAttributes": {
"8100": {
"label": "Frontend (Ionic)",
"onAutoForward": "notify"
},
"3069": {
"label": "Backend API",
"onAutoForward": "notify"
},
"27017": {
"label": "MongoDB",
"onAutoForward": "silent"
},
"8081": {
"label": "Mongo Express",
"onAutoForward": "notify"
}
},
"postCreateCommand": "npm install && cd app && npm install && cd ../backend && npm install",
"postStartCommand": "npm run dev:all"
}

View File

@@ -0,0 +1,70 @@
version: "3.8"
services:
app:
build:
context: ..
dockerfile: .devcontainer/Dockerfile
volumes:
- ../..:/workspaces:cached
- /workspaces/PfosiLooking/app/node_modules
- /workspaces/PfosiLooking/backend/node_modules
command: sleep infinity
environment:
- NODE_ENV=development
- MONGODB_URI=mongodb://mongo:27017/urge
- REACT_APP_API_URL=http://localhost:3069
- PORT=3069
- IONIC_PORT=8100
env_file:
- dev.env
networks:
- dev-network
depends_on:
mongo:
condition: service_healthy
mongo:
image: mongo:4.4
restart: unless-stopped
environment:
- MONGO_INITDB_DATABASE=urge
- MONGO_INITDB_ROOT_USERNAME=admin
- MONGO_INITDB_ROOT_PASSWORD=password
ports:
- "27017:27017"
networks:
- dev-network
volumes:
- mongo_data:/data/db
- ../backend/data:/docker-entrypoint-initdb.d:ro
healthcheck:
test: echo 'db.runCommand("ping").ok' | mongo localhost:27017/urge --quiet
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
mongo-express:
image: mongo-express:latest
restart: unless-stopped
environment:
- ME_CONFIG_MONGODB_SERVER=mongo
- ME_CONFIG_MONGODB_PORT=27017
- ME_CONFIG_MONGODB_ADMINUSERNAME=admin
- ME_CONFIG_MONGODB_ADMINPASSWORD=password
- ME_CONFIG_BASICAUTH_USERNAME=admin
- ME_CONFIG_BASICAUTH_PASSWORD=password
ports:
- "8081:8081"
networks:
- dev-network
depends_on:
- mongo
volumes:
mongo_data:
networks:
dev-network:
driver: bridge

View File

@@ -1,181 +1,132 @@
kind: pipeline
type: docker
name: Publish Pipeline
workspace:
path: /drone/looking-api
name: looking-fullstack
steps:
- name: Publish Image
image: plugins/docker
settings:
auto_tag: true
repo: git.mifi.dev/mifi/pfosi-looking-api
registry: git.mifi.dev
build_args:
- MONGO_ENTRY_FILE=latest
- MONGO_VERSION=latest
- NPM_TOKEN:
from_secret: reg_token
ssh-agent-key:
from_secret: reg_token
username: <token>
password:
from_secret: reg_token
secrets: [reg_token]
- name: Report Image Publish Status
image: plugins/webhook
settings:
urls: https://lab.mifi.dev/hooks/ccw34hdf7tgbjmzp96nptn938r
content_type: application/json
template: |
{
"icon_url":"https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/apple/198/freezing-face_1f976.png",
"text": "[{{ repo.name }} - New docker image release {{tag}} from # {{ build.number }}] Deploy {{ build.status }} {{#success build.status}}:tada:{{else}}:poop:{{/success}}",
"username":"DroneBot"
}
when:
status:
- success
- failure
# Install dependencies for both apps
- name: install-root
image: node:18-alpine
commands:
- npm ci
volumes:
- name: dockerconfig
host:
path: /volume1/docker/dockerconfig.json
- name: dockersock
host:
path: /var/run/docker.sock
- name: install-frontend
image: node:18-alpine
commands:
- cd app && npm ci
depends_on:
- install-root
- name: install-backend
image: node:18-alpine
commands:
- cd backend && npm ci
depends_on:
- install-root
# Linting
- name: lint-frontend
image: node:18-alpine
commands:
- cd app && npm run lint
depends_on:
- install-frontend
- name: lint-backend
image: node:18-alpine
commands:
- cd backend && npm run lint
depends_on:
- install-backend
# Testing
- name: test-frontend
image: node:18-alpine
commands:
- cd app && npm run test:ci
depends_on:
- install-frontend
- name: test-backend
image: node:18-alpine
commands:
- cd backend && npm test
depends_on:
- install-backend
# Build
- name: build-frontend
image: node:18-alpine
commands:
- cd app && npm run build
depends_on:
- lint-frontend
- test-frontend
# Docker builds
- name: docker-build-frontend
image: plugins/docker
settings:
registry: git.mifi.dev:12023
repo: git.mifi.dev:12023/mifi/pfosi-looking-frontend
username:
from_secret: docker_username
password:
from_secret: docker_password
tags:
- latest
- ${DRONE_COMMIT_SHA:0:8}
dockerfile: app/Dockerfile
context: app
depends_on:
- build-frontend
when:
branch:
- master
- main
- name: docker-build-backend
image: plugins/docker
settings:
registry: git.mifi.dev:12023
repo: git.mifi.dev:12023/mifi/pfosi-looking-backend
username:
from_secret: docker_username
password:
from_secret: docker_password
tags:
- latest
- ${DRONE_COMMIT_SHA:0:8}
dockerfile: backend/Dockerfile
context: backend
depends_on:
- lint-backend
- test-backend
when:
branch:
- master
- main
# Deploy both services
- name: deploy-stack
image: curlimages/curl
commands:
- curl -X POST $PORTAINER_WEBHOOK_URL
environment:
PORTAINER_WEBHOOK_URL:
from_secret: portainer_webhook_fullstack
depends_on:
- docker-build-frontend
- docker-build-backend
when:
branch:
- master
- main
trigger:
branch:
- master
- develop
- master
- main
- develop
event:
- push
---
kind: pipeline
type: docker
name: Staging Deploy Pipeline
workspace:
path: /drone/looking-api
steps:
- name: Deploy Container
image: docker
privileged: true
environment:
CONTAINER_PREFIX: staging
HOST: bikini.mifi.dev
ROUTE_PREFIX: /looking/api
PORT: 9001
commands:
- docker compose -f docker-compose.yml build --pull --no-cache
- docker compose -f docker-compose.yml up --remove-orphans --force-recreate --wait
volumes:
- name: env-secrets
path: /drone/looking-api/staging.env
- name: dockersock
path: /var/run/docker.sock
- name: dockerconfig
path: /drone/looking-api/.docker/config.json
- name: Send Status Notifications
image: plugins/webhook
privileged: true
settings:
urls: https://lab.mifi.dev/hooks/ccw34hdf7tgbjmzp96nptn938r
content_type: application/json
template: |
{
"icon_url":"https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/apple/198/freezing-face_1f976.png",
"text": "[{{ repo.name }} - Build # {{ build.number }}] Staging Deploy {{ build.status }} {{#success build.status}}:tada:{{else}}:poop:{{/success}}",
"username":"DroneBot"
}
when:
status:
- success
- failure
volumes:
- name: dockerconfig
host:
path: /volume1/docker/dockerconfig.json
- name: dockersock
host:
path: /var/run/docker.sock
- name: env-secrets
host:
path: /volume1/docker/beethoven/looking-api/staging.env
# depends_on:
# - Test Pipeline
trigger:
branch:
- develop
- master
event:
- push
# ---
# kind: pipeline
# type: docker
# name: Production Deploy Pipeline
# workspace:
# path: /drone/looking
# clone:
# disable: true
# steps:
# - name: Deploy Container
# image: plugins/webhook
# settings:
# # urls: https://portainer.mifi.dev/api/stacks/webhooks/968d2244-2548-4f0b-8c18-bbc9bc35305d
# - name: Send Status Notifications
# image: plugins/webhook
# privileged: true
# settings:
# urls: https://lab.mifi.dev/hooks/ccw34hdf7tgbjmzp96nptn938r
# content_type: application/json
# template: |
# {
# "icon_url":"https://emojipedia-us.s3.dualstack.us-west-1.amazonaws.com/thumbs/120/apple/198/freezing-face_1f976.png",
# "text": "[{{ repo.name }} - Build # {{ build.number }}] Production Deploy {{ build.status }} {{#success build.status}}:tada:{{else}}:poop:{{/success}}",
# "username":"DroneBot"
# }
# when:
# status:
# - success
# - failure
# depends_on:
# - Publish Pipeline
# trigger:
# event:
# - promote
# target:
# - production
# kind: pipeline
# type: docker
# name: Deploy to miCloud
# steps:
# - name: deploy-dev
# image: node:latest
# commands:
# - npm install -g forever
# - npm install
# - forever start bin/www
# trigger:
# branch:
# - master
# event:
# - push
- push
- pull_request

55
.gitignore vendored
View File

@@ -1 +1,54 @@
.vscode/settings.json
# Dependencies
node_modules/
*/node_modules/
# Production builds
/app/www/
/app/dist/
/backend/dist/
# Logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Environment files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# IDE
.vscode/
.idea/
*.swp
*.swo
# OS
.DS_Store
Thumbs.db
# Cache
.cache/
.parcel-cache/
.angular/
# Coverage
coverage/
.nyc_output/
# Docker
.dockerignore
# Database
*.db
*.sqlite
# Images (if large)
/backend/src/images/uploads/
# Temporary
tmp/
temp/

107
docker-compose.yml Normal file
View File

@@ -0,0 +1,107 @@
version: "3.8"
services:
looking-frontend:
image: git.mifi.dev:12023/mifi/pfosi-looking-frontend:latest
container_name: looking-frontend
restart: unless-stopped
environment:
- NODE_ENV=production
networks:
- marina-net
labels:
- "traefik.enable=true"
- "traefik.http.routers.looking-frontend.rule=Host(`pfosi.mifi.dev`)"
- "traefik.http.routers.looking-frontend.tls=true"
- "traefik.http.routers.looking-frontend.tls.certresolver=letsencrypt"
- "traefik.http.services.looking-frontend.loadbalancer.server.port=80"
- "traefik.docker.network=marina-net"
looking-backend:
image: git.mifi.dev:12023/mifi/pfosi-looking-backend:latest
container_name: looking-backend
restart: unless-stopped
environment:
- NODE_ENV=production
- PORT=3069
- MONGODB_URI=mongodb://mongo:27017/urge
- JWT_SECRET=${JWT_SECRET}
- GOOGLE_MAPS_API_KEY=${GOOGLE_MAPS_API_KEY}
- MAIL_HOST=${MAIL_HOST}
- MAIL_PORT=${MAIL_PORT:-587}
- MAIL_USER=${MAIL_USER}
- MAIL_PASS=${MAIL_PASS}
networks:
- backend-net
- marina-net
depends_on:
mongo:
condition: service_healthy
volumes:
- api_images:/app/src/images
labels:
- "traefik.enable=true"
- "traefik.http.routers.looking-backend.rule=Host(`api.pfosi.mifi.dev`)"
- "traefik.http.routers.looking-backend.tls=true"
- "traefik.http.routers.looking-backend.tls.certresolver=letsencrypt"
- "traefik.http.services.looking-backend.loadbalancer.server.port=3069"
- "traefik.docker.network=marina-net"
- "traefik.http.routers.looking-backend.middlewares=api-cors"
- "traefik.http.middlewares.api-cors.headers.accesscontrolallowmethods=GET,OPTIONS,PUT,POST,DELETE,PATCH"
- "traefik.http.middlewares.api-cors.headers.accesscontrolalloworiginlist=https://pfosi.mifi.dev"
- "traefik.http.middlewares.api-cors.headers.accesscontrolallowcredentials=true"
- "traefik.http.middlewares.api-cors.headers.accesscontrolallowheaders=Origin,X-Requested-With,Content-Type,Accept,Authorization,Cache-Control"
mongo:
image: mongo:4.4
container_name: looking-mongo
restart: unless-stopped
environment:
- MONGO_INITDB_DATABASE=urge
- MONGO_INITDB_ROOT_USERNAME=${MONGO_ROOT_USER:-admin}
- MONGO_INITDB_ROOT_PASSWORD=${MONGO_ROOT_PASSWORD:-password}
networks:
- backend-net
volumes:
- mongo_data:/data/db
- ./backend/data:/docker-entrypoint-initdb.d:ro
healthcheck:
test: echo 'db.runCommand("ping").ok' | mongo localhost:27017/urge --quiet
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
mongo-express:
image: mongo-express:latest
container_name: looking-mongo-express
restart: unless-stopped
environment:
- ME_CONFIG_MONGODB_SERVER=mongo
- ME_CONFIG_MONGODB_PORT=27017
- ME_CONFIG_MONGODB_ADMINUSERNAME=${MONGO_ROOT_USER:-admin}
- ME_CONFIG_MONGODB_ADMINPASSWORD=${MONGO_ROOT_PASSWORD:-password}
- ME_CONFIG_BASICAUTH_USERNAME=${MONGO_EXPRESS_USER:-admin}
- ME_CONFIG_BASICAUTH_PASSWORD=${MONGO_EXPRESS_PASSWORD:-password}
networks:
- backend-net
- marina-net
depends_on:
- mongo
labels:
- "traefik.enable=true"
- "traefik.http.routers.mongo-express.rule=Host(`mongo.pfosi.mifi.dev`)"
- "traefik.http.routers.mongo-express.tls=true"
- "traefik.http.routers.mongo-express.tls.certresolver=letsencrypt"
- "traefik.http.services.mongo-express.loadbalancer.server.port=8081"
- "traefik.docker.network=marina-net"
volumes:
mongo_data:
api_images:
networks:
backend-net:
driver: bridge
marina-net:
external: true

57
package.json Normal file
View File

@@ -0,0 +1,57 @@
{
"name": "pfosi-looking-monorepo",
"version": "1.0.0",
"description": "Looking App - Art project about gay dating culture (Full Stack)",
"private": true,
"workspaces": [
"app",
"backend"
],
"scripts": {
"dev:all": "concurrently \"npm run dev:backend\" \"npm run dev:app\"",
"dev:backend": "cd backend && npm run dev",
"dev:app": "cd app && ionic serve --host=0.0.0.0 --port=8100",
"dev:backend-only": "cd backend && npm run dev",
"dev:app-only": "cd app && ionic serve --host=0.0.0.0 --port=8100",
"install:all": "npm install && npm run install:workspaces",
"install:workspaces": "npm install --workspaces",
"seed": "cd backend && npm run seed",
"test": "npm run test:backend && npm run test:app",
"test:backend": "cd backend && npm test",
"test:app": "cd app && npm run test:ci",
"lint": "npm run lint:backend && npm run lint:app",
"lint:backend": "cd backend && npm run lint",
"lint:app": "cd app && npm run lint",
"build": "npm run build:app && npm run build:backend",
"build:app": "cd app && ionic build",
"build:backend": "echo 'Backend build not needed for Node.js'",
"docker:build": "npm run docker:build:frontend && npm run docker:build:backend",
"docker:build:frontend": "docker build -t pfosi-looking-frontend ./app",
"docker:build:backend": "docker build -t pfosi-looking-backend ./backend",
"deploy": "docker-compose up -d",
"mongo:shell": "mongo mongodb://admin:password@localhost:27017/urge?authSource=admin"
},
"devDependencies": {
"concurrently": "^7.6.0",
"npm-run-all": "^4.1.5"
},
"keywords": [
"Art",
"LGBT",
"Grindr",
"Dating",
"Photography",
"Documentary",
"Ionic",
"Angular",
"Express",
"MongoDB",
"Monorepo"
],
"author": "Nicholas Pfosi & Mike Fitzpatrick",
"license": "ISC",
"repository": {
"type": "git",
"url": "git@git.mifi.dev:12022/mifi/Pfosi-Looking.git"
}
}