Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
run: |
echo "Building all services..."
cd services/auth-service && npm install && npm run build
cd services/notification-service && npm install && npm run build
cd ../event-service && npm install && npm run build
cd ../venue-service && npm install && npm run build
cd ../attendee-service && npm install && npm run build
Expand Down
51 changes: 51 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@ services:
- EVENT_SERVICE_URL=http://event-service:3002
- VENUE_SERVICE_URL=http://venue-service:3003
- ATTENDEE_SERVICE_URL=http://attendee-service:3004
- NOTIFICATION_SERVICE_URL=http://notification-service:3005
depends_on:
- auth-service
- event-service
- venue-service
- attendee-service
- notification-service
networks:
- orchestrate-network

Expand All @@ -31,9 +33,12 @@ services:
- DATABASE_URL=postgresql://postgres:postgres@auth-db:5432/auth
- JWT_SECRET=hfkesahr3q489345iueiourt
- JWT_REFRESH_SECRET=kojwreh389589357
- RABBITMQ_URL=amqp://rabbitmq:5672
depends_on:
auth-db:
condition: service_healthy
rabbitmq:
condition: service_healthy
networks:
- orchestrate-network

Expand All @@ -48,9 +53,12 @@ services:
- PORT=3002
- DATABASE_URL=postgresql://postgres:postgres@event-db:5432/events
- JWT_SECRET=hfkesahr3q489345iueiourt
- RABBITMQ_URL=amqp://rabbitmq:5672
depends_on:
event-db:
condition: service_healthy
rabbitmq:
condition: service_healthy
networks:
- orchestrate-network

Expand Down Expand Up @@ -82,9 +90,51 @@ services:
- PORT=3004
- DATABASE_URL=postgresql://postgres:postgres@attendee-db:5432/attendees
- JWT_SECRET=hfkesahr3q489345iueiourt
- RABBITMQ_URL=amqp://rabbitmq:5672
depends_on:
attendee-db:
condition: service_healthy
rabbitmq:
condition: service_healthy
networks:
- orchestrate-network

notification-service:
build:
context: ./services/notification-service
dockerfile: Dockerfile
ports:
- "3005:3005"
environment:
- NODE_ENV=development
- PORT=3005
- RABBITMQ_URL=amqp://rabbitmq:5672
- SMTP_HOST=smtp.gmail.com
- SMTP_PORT=587
- SMTP_USER=your-email@gmail.com
- SMTP_PASS=your-app-password
depends_on:
rabbitmq:
condition: service_healthy
networks:
- orchestrate-network

rabbitmq:
image: rabbitmq:3-management
container_name: rabbitmq
ports:
- "5672:5672" # AMQP port
- "15672:15672" # Management UI
environment:
- RABBITMQ_DEFAULT_USER=guest
- RABBITMQ_DEFAULT_PASS=guest
volumes:
- rabbitmq-data:/var/lib/rabbitmq
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
interval: 30s
timeout: 30s
retries: 3
networks:
- orchestrate-network

Expand Down Expand Up @@ -170,6 +220,7 @@ volumes:
event-data:
venue-data:
attendee-data:
rabbitmq-data:

networks:
orchestrate-network:
Expand Down
1 change: 1 addition & 0 deletions scripts/check-services.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ services=(
"http://localhost:3002/health,Event Service"
"http://localhost:3003/health,Venue Service"
"http://localhost:3004/health,Attendee Service"
"http://localhost:3005/health,Notification Service"
"http://localhost:3000/health,API Gateway"
)

Expand Down
53 changes: 53 additions & 0 deletions services/auth-service/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions services/auth-service/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"dependencies": {
"@orchestrate/shared": "file:../../shared",
"@prisma/client": "^6.6.0",
"amqplib": "^0.10.8",
"bcrypt": "^5.1.1",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
Expand All @@ -21,6 +22,7 @@
"orchestrate-shared": "^1.0.0"
},
"devDependencies": {
"@types/amqplib": "^0.10.7",
"@types/bcrypt": "^5.0.2",
"@types/cookie-parser": "^1.4.8",
"@types/cors": "^2.8.17",
Expand Down
15 changes: 10 additions & 5 deletions services/auth-service/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import cors from 'cors';
import cookieParser from 'cookie-parser';
import dotenv from 'dotenv';
import authRoutes from './routes/auth.routes';
import { connectRabbitMQ } from './rabbitmq/connection';

dotenv.config({ path: ".env" })

Expand All @@ -14,17 +15,21 @@ app.use(cors())
app.use(express.json())
app.use(cookieParser())

// Routes


app.get('/health', (req, res) => {
res.json({ status: 'ok' });
});

app.use('/', authRoutes);




app.listen(PORT, () => {
app.listen(PORT, async () => {
console.log(`Auth Service running on port ${PORT}`);

try {
await connectRabbitMQ();
console.log('Auth service successfully connected to RabbitMQ.');
} catch (error) {
console.warn('⚠️ Auth service: Could not connect to RabbitMQ for email notifications', error);
}
});
35 changes: 35 additions & 0 deletions services/auth-service/src/rabbitmq/connection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import amqp from "amqplib";

let channel: amqp.Channel | null = null;

const EMAIL_NOTIFICATIONS_EXCHANGE = "email_notifications";

export const connectRabbitMQ = async () => {
try {
const connectionString = process.env.RABBITMQ_URL || "amqp://localhost:5672";
const connection = await amqp.connect(connectionString);
channel = await connection.createChannel();

await channel.assertExchange(EMAIL_NOTIFICATIONS_EXCHANGE, "topic", {
durable: true,
});

console.log(
"Auth service connected to RabbitMQ and email_notifications exchange asserted"
);
} catch (error) {
console.error("Auth service RabbitMQ connection error:", error);
process.exit(1);
}
};

export const getChannel = (): amqp.Channel => {
if (!channel) {
throw new Error(
"RabbitMQ channel not initialized. Call connectRabbitMQ() first."
);
}
return channel;
};

export { EMAIL_NOTIFICATIONS_EXCHANGE };
44 changes: 44 additions & 0 deletions services/auth-service/src/rabbitmq/publisher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { getChannel, EMAIL_NOTIFICATIONS_EXCHANGE } from "./connection";

interface UserRegistrationEmailData {
name: string;
email: string;

}


export const publishUserRegisteredEvent = async (
userData: UserRegistrationEmailData
) => {
const channel = getChannel();

// Define the routing key for user registration events
// This should match the binding key used by the notification-service for the user registration queue
const routingKey = "user.registered";

const eventPayload = {
type: "USER_REGISTERED",
data: userData,
};

try {
channel.publish(
EMAIL_NOTIFICATIONS_EXCHANGE,
routingKey,
Buffer.from(JSON.stringify(eventPayload)),
{
contentType: "application/json",
persistent: true,
}
);
console.log(
`Auth service published USER_REGISTERED event for ${userData.email} to ${EMAIL_NOTIFICATIONS_EXCHANGE} with routing key ${routingKey}`
);
} catch (error) {
console.error(
`Auth service failed to publish USER_REGISTERED event for ${userData.email}:`,
error
);
// Handle publishing errors
}
};
7 changes: 7 additions & 0 deletions services/auth-service/src/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import jwt from 'jsonwebtoken'
import bcrypt from 'bcrypt'
import { UserRole } from '@prisma/client'
import {ApiError} from 'orchestrate-shared';
import { publishUserRegisteredEvent } from '../rabbitmq/publisher';



Expand Down Expand Up @@ -77,6 +78,12 @@ export const register = async ({

const { accessToken, refreshToken } = await generateTokens(user.id, user.roles as UserRole[])

// Publish email notification for user registration
await publishUserRegisteredEvent({
name: user.name!,
email: user.email
});

return {
user,
accessToken,
Expand Down
Loading