env file and yml file consistency
This commit is contained in:
parent
a41858427b
commit
b5268a0fe8
@ -1,26 +1,42 @@
|
||||
# ─── O*NET ───────────────────────────────
|
||||
ONET_USERNAME=aptivaai
|
||||
ONET_PASSWORD=2296ahq
|
||||
|
||||
REACT_APP_BLS_API_KEY=80d7a65a809a43f3a306a41ec874d231
|
||||
GOOGLE_MAPS_API_KEY=AIzaSyCTMgjiHUF2Vl3QriQu2kDEuZWz39ZAR20
|
||||
# ─── Public‐facing React build ───────────
|
||||
NODE_ENV=development
|
||||
REACT_APP_ENV=production
|
||||
APTIVA_API_BASE=https://dev1.aptivaai.com/api
|
||||
REACT_APP_API_URL=${APTIVA_API_BASE}
|
||||
REACT_APP_GOOGLE_MAPS_API_KEY=AIzaSyCTMgjiHUF2Vl3QriQu2kDEuZWz39ZAR20
|
||||
COLLEGE_SCORECARD_KEY = BlZ0tIdmXVGI4G8NxJ9e6dXEiGUfAfnQJyw8bumj
|
||||
REACT_APP_BLS_API_KEY=80d7a65a809a43f3a306a41ec874d231
|
||||
REACT_APP_OPENAI_API_KEY=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
|
||||
|
||||
# ─── Back-end services ───────────────────
|
||||
OPENAI_API_KEY=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
|
||||
GOOGLE_MAPS_API_KEY=AIzaSyCTMgjiHUF2Vl3QriQu2kDEuZWz39ZAR20
|
||||
COLLEGE_SCORECARD_KEY=BlZ0tIdmXVGI4G8NxJ9e6dXEiGUfAfnQJyw8bumj
|
||||
SALARY_DB=/home/jcoakley/aptiva-dev1-app/salary_info.db
|
||||
|
||||
# ─── Database (premium server) ───────────
|
||||
DB_HOST=34.67.180.54
|
||||
DB_PORT=3306
|
||||
DB_USER=sqluser
|
||||
DB_NAME=user_profile_db
|
||||
DB_PASSWORD=ps<g+2DO-eTb2mb5
|
||||
|
||||
APTIVA_API_BASE=https://dev1.aptivaai.com/api
|
||||
REACT_APP_API_URL=https://dev1.aptivaai.com/api
|
||||
REACT_APP_ENV=production
|
||||
REACT_APP_OPENAI_API_KEY=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
|
||||
OPENAI_API_KEY=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
|
||||
DB_NAME=user_profile_db
|
||||
GCP_CLOUD_SQL_PASSWORD=q2O}1PU-R:|l57S0
|
||||
|
||||
# ── Twilio (needed only by server3) ─────────────────────────
|
||||
TWILIO_ACCOUNT_SID=ACd700c6fb9f691ccd9ccab73f2dd4173d
|
||||
TWILIO_AUTH_TOKEN=fb8979ccb172032a249014c9c30eba80
|
||||
TWILIO_MESSAGING_SERVICE_SID=MGMGaa07992a9231c841b1bfb879649026d6
|
||||
|
||||
JWT_SECRET=gW4QsOu4AJA4MooIUC9ld2i71VbBovzV1INsaU6ftxYPrxLIeMq6/OY61j0X2RV7
|
||||
# ─── Anything new goes here ──────────────
|
||||
JWT_SECRET=a35F0iFAkkdWvSjnaLzepAl/JIxPRUh4NpcGptJgry2Z3KVLX4ZcYY5KaTf7kJY0
|
||||
|
||||
# ------------ CORS ------------
|
||||
CORS_ALLOWED_ORIGINS=http://localhost:3000,http://34.16.120.118:3000,https://dev1.aptivaai.com
|
||||
SERVER1_PORT=5000
|
||||
SERVER2_PORT=5001
|
||||
SERVER3_PORT=5002
|
||||
|
||||
IMG_TAG=20250716
|
42
.env.staging
Normal file
42
.env.staging
Normal file
@ -0,0 +1,42 @@
|
||||
# ─── O*NET ───────────────────────────────
|
||||
ONET_USERNAME=aptivaai
|
||||
ONET_PASSWORD=2296ahq
|
||||
|
||||
# ─── Public‐facing React build ───────────
|
||||
NODE_ENV=staging
|
||||
REACT_APP_ENV=production
|
||||
APTIVA_API_BASE=https://staging.aptivaai.com/api
|
||||
REACT_APP_API_URL=${APTIVA_API_BASE}
|
||||
REACT_APP_GOOGLE_MAPS_API_KEY=AIzaSyCTMgjiHUF2Vl3QriQu2kDEuZWz39ZAR20
|
||||
REACT_APP_BLS_API_KEY=80d7a65a809a43f3a306a41ec874d231
|
||||
REACT_APP_OPENAI_API_KEY=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
|
||||
|
||||
# ─── Back-end services ───────────────────
|
||||
OPENAI_API_KEY=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
|
||||
GOOGLE_MAPS_API_KEY=AIzaSyCTMgjiHUF2Vl3QriQu2kDEuZWz39ZAR20
|
||||
COLLEGE_SCORECARD_KEY=BlZ0tIdmXVGI4G8NxJ9e6dXEiGUfAfnQJyw8bumj
|
||||
SALARY_DB=/home/jcoakley/aptiva-dev1-app/salary_info.db
|
||||
|
||||
# ─── Database (premium server) ───────────
|
||||
DB_HOST=34.67.180.54
|
||||
DB_PORT=3306
|
||||
DB_USER=sqluser
|
||||
DB_PASSWORD=ps<g+2DO-eTb2mb5
|
||||
DB_NAME=user_profile_db
|
||||
GCP_CLOUD_SQL_PASSWORD=q2O}1PU-R:|l57S0
|
||||
|
||||
# ── Twilio (needed only by server3) ─────────────────────────
|
||||
TWILIO_ACCOUNT_SID=ACd700c6fb9f691ccd9ccab73f2dd4173d
|
||||
TWILIO_AUTH_TOKEN=fb8979ccb172032a249014c9c30eba80
|
||||
TWILIO_MESSAGING_SERVICE_SID=MGMGaa07992a9231c841b1bfb879649026d6
|
||||
|
||||
# ─── Anything new goes here ──────────────
|
||||
JWT_SECRET=a35F0iFAkkdWvSjnaLzepAl/JIxPRUh4NpcGptJgry2Z3KVLX4ZcYY5KaTf7kJY0
|
||||
|
||||
# ------------ env/staging.env ------------
|
||||
CORS_ALLOWED_ORIGINS=https://staging.aptivaai.com,http://34.61.84.49:3000,http://localhost:3000
|
||||
SERVER1_PORT=5000
|
||||
SERVER2_PORT=5001
|
||||
SERVER3_PORT=5002
|
||||
|
||||
IMG_TAG=20250716
|
@ -55,14 +55,24 @@ pool.query('SELECT 1', (err) => {
|
||||
});
|
||||
|
||||
const app = express();
|
||||
const PORT = 5000;
|
||||
const PORT = process.env.SERVER1_PORT || 5000;
|
||||
|
||||
/* ─── Require critical env vars ───────────────────────────────── */
|
||||
if (!process.env.CORS_ALLOWED_ORIGINS) {
|
||||
console.error('FATAL CORS_ALLOWED_ORIGINS is not set'); // eslint-disable-line
|
||||
process.exit(1);
|
||||
}
|
||||
if (!process.env.APTIVA_API_BASE) {
|
||||
console.error('FATAL APTIVA_API_BASE is not set'); // eslint-disable-line
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
/* ─── Allowed origins for CORS (comma-separated in env) ──────── */
|
||||
const allowedOrigins = process.env.CORS_ALLOWED_ORIGINS
|
||||
.split(',')
|
||||
.map(o => o.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
// Allowed origins for CORS
|
||||
const allowedOrigins = [
|
||||
'http://localhost:3000',
|
||||
'http://34.16.120.118:3000',
|
||||
'https://dev1.aptivaai.com',
|
||||
];
|
||||
|
||||
app.disable('x-powered-by');
|
||||
app.use(bodyParser.json());
|
||||
@ -101,7 +111,7 @@ app.use(
|
||||
|
||||
// Handle preflight requests explicitly
|
||||
app.options('*', (req, res) => {
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('Access-Control-Allow-Origin', req.headers.origin || '');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||
res.setHeader(
|
||||
'Access-Control-Allow-Headers',
|
||||
|
@ -38,22 +38,20 @@ const chatLimiter = rateLimit({
|
||||
keyGenerator: req => req.user?.id || req.ip
|
||||
});
|
||||
|
||||
// Whitelist CORS
|
||||
const allowedOrigins = [
|
||||
'http://localhost:3000',
|
||||
'http://34.16.120.118:3000',
|
||||
'https://dev1.aptivaai.com',
|
||||
];
|
||||
if (!process.env.APTIVA_API_BASE) {
|
||||
console.error('FATAL APTIVA_API_BASE is not set');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// CIP->SOC mapping file
|
||||
const mappingFilePath = '/home/jcoakley/aptiva-dev1-app/public/CIP_to_ONET_SOC.xlsx';
|
||||
|
||||
// Institution data
|
||||
const institutionFilePath = path.resolve(rootPath, 'public', 'Institution_data.json');
|
||||
const institutionFilePath = 'home/jcoakley/aptiva-dev1-app/public/Institution_data.json';
|
||||
|
||||
// Create Express app
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 5001;
|
||||
const PORT = process.env.SERVER2_PORT || 5001;
|
||||
|
||||
// at top of backend/server.js (do once per server codebase)
|
||||
app.get('/healthz', (req, res) => res.sendStatus(204)); // 204 No Content
|
||||
@ -86,9 +84,23 @@ async function initDatabases() {
|
||||
|
||||
await initDatabases();
|
||||
|
||||
/**************************************************
|
||||
* Security, CORS, JSON Body
|
||||
**************************************************/
|
||||
/* ──────────────────────────────────────────────────────────────
|
||||
* SECURITY, CORS, JSON Body
|
||||
* ────────────────────────────────────────────────────────────── */
|
||||
|
||||
/* 1 — Require critical env var up-front */
|
||||
if (!process.env.CORS_ALLOWED_ORIGINS) {
|
||||
console.error('FATAL CORS_ALLOWED_ORIGINS is not set');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
/* 2 — Build allow-list from env (comma-separated) */
|
||||
const allowedOrigins = process.env.CORS_ALLOWED_ORIGINS
|
||||
.split(',')
|
||||
.map(o => o.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
/* 3 — Security headers */
|
||||
app.use(
|
||||
helmet({
|
||||
contentSecurityPolicy: false,
|
||||
@ -96,8 +108,11 @@ app.use(
|
||||
})
|
||||
);
|
||||
|
||||
/* 4 — Dynamic CORS / pre-flight handling */
|
||||
app.use((req, res, next) => {
|
||||
const origin = req.headers.origin;
|
||||
|
||||
/* 4a — Whitelisted origins (credentials allowed) */
|
||||
if (origin && allowedOrigins.includes(origin)) {
|
||||
res.setHeader('Access-Control-Allow-Origin', origin);
|
||||
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
||||
@ -105,17 +120,22 @@ app.use((req, res, next) => {
|
||||
'Access-Control-Allow-Headers',
|
||||
'Authorization, Content-Type, Accept, Origin, X-Requested-With, Access-Control-Allow-Methods'
|
||||
);
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||
res.setHeader(
|
||||
'Access-Control-Allow-Methods',
|
||||
'GET, POST, OPTIONS'
|
||||
);
|
||||
|
||||
/* 4b — Public JSON exception */
|
||||
} else if (req.path.includes('Institution_data')) {
|
||||
// For that JSON
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
||||
res.setHeader(
|
||||
'Access-Control-Allow-Headers',
|
||||
'Content-Type, Accept, Origin, X-Requested-With'
|
||||
);
|
||||
|
||||
/* 4c — Default permissive fallback (same as your original) */
|
||||
} else {
|
||||
// default
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||
res.setHeader(
|
||||
@ -123,21 +143,22 @@ app.use((req, res, next) => {
|
||||
'Authorization, Content-Type, Accept, Origin, X-Requested-With'
|
||||
);
|
||||
}
|
||||
|
||||
/* 4d — Short-circuit pre-flight requests */
|
||||
if (req.method === 'OPTIONS') {
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||
res.setHeader('Access-Control-Allow-Headers', 'Authorization, Content-Type');
|
||||
return res.status(204).end();
|
||||
res.status(204).end();
|
||||
return;
|
||||
}
|
||||
|
||||
next();
|
||||
});
|
||||
|
||||
/* 5 — JSON parsing & static assets */
|
||||
app.use(express.json());
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
|
||||
// For completeness
|
||||
app.use((req, res, next) => {
|
||||
next();
|
||||
});
|
||||
/* 6 — No-op pass-through (kept for completeness) */
|
||||
app.use((req, res, next) => next());
|
||||
|
||||
/**************************************************
|
||||
* Load CIP->SOC mapping
|
||||
@ -383,7 +404,7 @@ app.post('/api/onet/submit_answers', async (req, res) => {
|
||||
const token = req.headers.authorization?.split(' ')[1];
|
||||
if (token) {
|
||||
try {
|
||||
await axios.post(`${process.env.MAIN_API_URL}/api/user-profile`,
|
||||
await axios.post(`${process.env.APTIVA_API_BASE}/api/user-profile`,
|
||||
{
|
||||
interest_inventory_answers: answers,
|
||||
riasec: riasecCode
|
||||
@ -454,7 +475,7 @@ app.get('/api/onet/career-details/:socCode', async (req, res) => {
|
||||
try {
|
||||
const response = await axios.get(`https://services.onetcenter.org/ws/mnm/careers/${socCode}`, {
|
||||
auth: {
|
||||
username: process.env.ONet_USERNAME,
|
||||
username: process.env.ONET_USERNAME,
|
||||
password: process.env.ONET_PASSWORD,
|
||||
},
|
||||
headers: { Accept: 'application/json' },
|
||||
@ -1000,5 +1021,5 @@ chatFreeEndpoint(app, {
|
||||
* Start the Express server
|
||||
**************************************************/
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server running on https://34.16.120.118:${PORT}`);
|
||||
console.log(`Server running on port ${PORT}`);
|
||||
});
|
||||
|
@ -7,7 +7,6 @@ const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import helmet from 'helmet';
|
||||
import fs from 'fs/promises';
|
||||
import multer from 'multer';
|
||||
@ -30,7 +29,7 @@ dotenv.config({ path: envPath });
|
||||
const apiBase = process.env.APTIVA_API_BASE || "http://localhost:5002/api";
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PREMIUM_PORT || 5002;
|
||||
const PORT = process.env.SERVER3_PORT || 5002;
|
||||
const { getDocument } = pkg;
|
||||
const bt = "`".repeat(3);
|
||||
|
||||
@ -45,14 +44,55 @@ function internalFetch(req, url, opts = {}) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 2) Basic middlewares
|
||||
app.use(helmet());
|
||||
app.use(helmet({ contentSecurityPolicy:false, crossOriginEmbedderPolicy:false }));
|
||||
app.use(express.json({ limit: '5mb' }));
|
||||
|
||||
const allowedOrigins = ['https://dev1.aptivaai.com'];
|
||||
app.use(cors({ origin: allowedOrigins, credentials: true }));
|
||||
/* ─── Require critical env vars ─────────────────────────────── */
|
||||
if (!process.env.CORS_ALLOWED_ORIGINS) {
|
||||
console.error('FATAL CORS_ALLOWED_ORIGINS is not set');
|
||||
process.exit(1);
|
||||
}
|
||||
if (!process.env.APTIVA_API_BASE) {
|
||||
console.error('FATAL APTIVA_API_BASE is not set');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
/* ─── Allowed origins for CORS (comma-separated in env) ─────── */
|
||||
const allowedOrigins = process.env.CORS_ALLOWED_ORIGINS
|
||||
.split(',')
|
||||
.map(o => o.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
/* ─── Dynamic CORS middleware (matches server1 / server2) ────────────── */
|
||||
app.use((req, res, next) => {
|
||||
const origin = req.headers.origin;
|
||||
|
||||
// A) whitelisted origins (credentials allowed)
|
||||
if (origin && allowedOrigins.includes(origin)) {
|
||||
res.setHeader('Access-Control-Allow-Origin', origin);
|
||||
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
||||
res.setHeader(
|
||||
'Access-Control-Allow-Headers',
|
||||
'Authorization, Content-Type, Accept, Origin, X-Requested-With, Access-Control-Allow-Methods'
|
||||
);
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||
|
||||
// B) default permissive fallback (same as server2’s behaviour)
|
||||
} else {
|
||||
res.setHeader('Access-Control-Allow-Origin', '*');
|
||||
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
||||
res.setHeader(
|
||||
'Access-Control-Allow-Headers',
|
||||
'Authorization, Content-Type, Accept, Origin, X-Requested-With'
|
||||
);
|
||||
}
|
||||
|
||||
if (req.method === 'OPTIONS') {
|
||||
return res.status(204).end();
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
// 3) Authentication middleware
|
||||
const authenticatePremiumUser = (req, res, next) => {
|
||||
|
5
docker-compose.dev.yml
Normal file
5
docker-compose.dev.yml
Normal file
@ -0,0 +1,5 @@
|
||||
services:
|
||||
server1: { env_file: .env.dev }
|
||||
server2: { env_file: .env.dev }
|
||||
server3: { env_file: .env.dev }
|
||||
nginx : { env_file: .env.dev }
|
@ -1,42 +1,5 @@
|
||||
services:
|
||||
# ─── server1 ───
|
||||
server1:
|
||||
extends:
|
||||
file: docker-compose.yml
|
||||
service: server1
|
||||
env_file: [ ./env/prod.env ]
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- SALARY_DB=/app/data/salary_info.db
|
||||
volumes:
|
||||
- /home/jcoakley/aptiva-dev1-app/salary_info.db:/app/data/salary_info.db:ro
|
||||
- /home/jcoakley/aptiva-dev1-app/public:/home/jcoakley/aptiva-dev1-app/public:ro
|
||||
|
||||
# ─── server2 ───
|
||||
server2:
|
||||
extends:
|
||||
file: docker-compose.yml
|
||||
service: server2
|
||||
env_file: [ ./env/prod.env ]
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- SALARY_DB=/home/jcoakley/aptiva-dev1-app/salary_info.db
|
||||
volumes:
|
||||
- /home/jcoakley/aptiva-dev1-app/salary_info.db:/home/jcoakley/aptiva-dev1-app/salary_info.db:ro
|
||||
- /home/jcoakley/aptiva-dev1-app/user_profile.db:/home/jcoakley/aptiva-dev1-app/user_profile.db
|
||||
- /home/jcoakley/aptiva-dev1-app/public:/home/jcoakley/aptiva-dev1-app/public:ro
|
||||
|
||||
# ─── server3 ───
|
||||
server3:
|
||||
extends:
|
||||
file: docker-compose.yml
|
||||
service: server3
|
||||
env_file: [ ./env/prod.env ]
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- TWILIO_ACCOUNT_SID=ACd700c6fb9f691ccd9ccab73f2dd4173d
|
||||
- TWILIO_AUTH_TOKEN=fb8979ccb172032a249014c9c30eba80
|
||||
- TWILIO_MESSAGING_SERVICE_SID=MGMGaa07992a9231c841b1bfb879649026d6
|
||||
volumes:
|
||||
- /home/jcoakley/aptiva-dev1-app/public:/home/jcoakley/aptiva-dev1-app/public:ro
|
||||
- /home/jcoakley/aptiva-dev1-app/user_profile.db:/home/jcoakley/aptiva-dev1-app/user_profile.db
|
||||
server1: { env_file: .env.prod }
|
||||
server2: { env_file: .env.prod }
|
||||
server3: { env_file: .env.prod }
|
||||
nginx : { env_file: .env.prod }
|
@ -1,39 +1,5 @@
|
||||
services:
|
||||
# ─── server1 ───
|
||||
server1:
|
||||
extends:
|
||||
file: docker-compose.yml
|
||||
service: server1
|
||||
env_file: [ ./env/staging.env ]
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- SALARY_DB=/app/data/salary_info.db
|
||||
volumes:
|
||||
- /home/jcoakley/aptiva-dev1-app/salary_info.db:/app/data/salary_info.db:ro
|
||||
- /home/jcoakley/aptiva-dev1-app/public:/home/jcoakley/aptiva-dev1-app/public:ro
|
||||
|
||||
# ─── server2 ───
|
||||
server2:
|
||||
extends:
|
||||
file: docker-compose.yml
|
||||
service: server2
|
||||
env_file: [ ./env/staging.env ]
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- SALARY_DB=/home/jcoakley/aptiva-dev1-app/salary_info.db
|
||||
volumes:
|
||||
- /home/jcoakley/aptiva-dev1-app/salary_info.db:/home/jcoakley/aptiva-dev1-app/salary_info.db:ro
|
||||
- /home/jcoakley/aptiva-dev1-app/public:/home/jcoakley/aptiva-dev1-app/public:ro
|
||||
- /home/jcoakley/aptiva-dev1-app/user_profile.db:/home/jcoakley/aptiva-dev1-app/user_profile.db
|
||||
|
||||
# ─── server3 ───
|
||||
server3:
|
||||
extends:
|
||||
file: docker-compose.yml
|
||||
service: server3
|
||||
env_file: [ ./env/staging.env ]
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
volumes:
|
||||
- /home/jcoakley/aptiva-dev1-app/public:/home/jcoakley/aptiva-dev1-app/public:ro
|
||||
- /home/jcoakley/aptiva-dev1-app/user_profile.db:/home/jcoakley/aptiva-dev1-app/user_profile.db
|
||||
server1: { env_file: .env.staging }
|
||||
server2: { env_file: .env.staging }
|
||||
server3: { env_file: .env.staging }
|
||||
nginx : { env_file: .env.staging }
|
@ -1,50 +1,45 @@
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
server1:
|
||||
image: us-central1-docker.pkg.dev/aptivaai-dev/aptiva-repo/server1:prod-20250710
|
||||
image: us-central1-docker.pkg.dev/aptivaai-dev/aptiva-repo/server1:${IMG_TAG}
|
||||
expose: ["${SERVER1_PORT}"]
|
||||
restart: unless-stopped
|
||||
expose: ["5000"]
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:5000/healthz || exit 1"]
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:${SERVER1_PORT}/healthz || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
server2:
|
||||
image: us-central1-docker.pkg.dev/aptivaai-dev/aptiva-repo/server2:prod-20250710
|
||||
image: us-central1-docker.pkg.dev/aptivaai-dev/aptiva-repo/server2:${IMG_TAG}
|
||||
expose: ["${SERVER2_PORT}"]
|
||||
restart: unless-stopped
|
||||
expose: ["5001"]
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:5001/healthz || exit 1"]
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:${SERVER2_PORT}/healthz || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
server3:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.server3
|
||||
image: us-central1-docker.pkg.dev/aptivaai-dev/aptiva-repo/server3:${IMG_TAG}
|
||||
expose: ["${SERVER3_PORT}"]
|
||||
restart: unless-stopped
|
||||
expose: ["5002"]
|
||||
environment:
|
||||
NODE_ENV: production
|
||||
JWT_SECRET: gW4QsOu4AJA4MooIUC9ld2i71VbBovzV1INsaU6ftxYPrxLIeMq6/OY61j0X2RV7
|
||||
TWILIO_ACCOUNT_SID: ACd700c6fb9f691ccd9ccab73f2dd4173d
|
||||
TWILIO_AUTH_TOKEN: fb8979ccb172032a249014c9c30eba80
|
||||
TWILIO_MESSAGING_SERVICE_SID: MGMGaa07992a9231c841b1bfb879649026d6
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:5002/healthz || exit 1"]
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:${SERVER3_PORT}/healthz || exit 1"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
|
||||
nginx:
|
||||
image: nginx:1.25-alpine
|
||||
command: ["nginx", "-g", "daemon off;"]
|
||||
command: ["nginx","-g","daemon off;"]
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./build:/usr/share/nginx/html:ro # React build
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro # overwrite default
|
||||
- /etc/letsencrypt:/etc/letsencrypt:ro # certs
|
||||
- ./empty:/etc/nginx/conf.d # hide default.conf
|
||||
- ./build:/usr/share/nginx/html:ro
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- /etc/letsencrypt:/etc/letsencrypt:ro
|
||||
- ./empty:/etc/nginx/conf.d
|
||||
depends_on: [server1, server2, server3]
|
||||
|
@ -10,6 +10,7 @@ function SignIn({ setIsAuthenticated, setUser }) {
|
||||
const [error, setError] = useState('');
|
||||
const [showSessionExpiredMsg, setShowSessionExpiredMsg] = useState(false);
|
||||
const location = useLocation();
|
||||
const apiUrl = process.env.REACT_APP_API_URL;
|
||||
|
||||
useEffect(() => {
|
||||
// Check if the URL query param has ?session=expired
|
||||
@ -42,10 +43,10 @@ function SignIn({ setIsAuthenticated, setUser }) {
|
||||
}
|
||||
|
||||
try {
|
||||
const resp = await fetch('https://dev1.aptivaai.com/api/signin', {
|
||||
const resp = await fetch(`${apiUrl}/signin`, {
|
||||
method : 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body : JSON.stringify({ username, password })
|
||||
body : JSON.stringify(formData),
|
||||
});
|
||||
|
||||
const data = await resp.json(); // ← read ONCE
|
||||
|
Loading…
Reference in New Issue
Block a user