From 9eb293ccb1e139df5697b9a2dfe36d47ddb6a726 Mon Sep 17 00:00:00 2001 From: mifi Date: Fri, 25 Jul 2025 19:14:05 -0300 Subject: [PATCH] Add monorepo configuration and development environment --- .devcontainer/Dockerfile | 34 ++++ .devcontainer/dev.env | 18 ++ .devcontainer/devcontainer.json | 60 +++++++ .devcontainer/docker-compose.yml | 70 ++++++++ .drone.yml | 295 +++++++++++++------------------ .gitignore | 55 +++++- docker-compose.yml | 107 +++++++++++ package.json | 57 ++++++ 8 files changed, 523 insertions(+), 173 deletions(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/dev.env create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/docker-compose.yml create mode 100644 docker-compose.yml create mode 100644 package.json diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..47dc9e2 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -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"] \ No newline at end of file diff --git a/.devcontainer/dev.env b/.devcontainer/dev.env new file mode 100644 index 0000000..d0a4edb --- /dev/null +++ b/.devcontainer/dev.env @@ -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 \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..fdd8a47 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -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" +} diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml new file mode 100644 index 0000000..2f11a87 --- /dev/null +++ b/.devcontainer/docker-compose.yml @@ -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 diff --git a/.drone.yml b/.drone.yml index 8d8df2c..9e72559 100644 --- a/.drone.yml +++ b/.drone.yml @@ -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: - 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 diff --git a/.gitignore b/.gitignore index c6f9a44..3a6f837 100644 --- a/.gitignore +++ b/.gitignore @@ -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/ \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..ac3d757 --- /dev/null +++ b/docker-compose.yml @@ -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 diff --git a/package.json b/package.json new file mode 100644 index 0000000..0873036 --- /dev/null +++ b/package.json @@ -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" + } +}