mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 19:41:09 +02:00
refactor(credits): route credit calls to mana-credits service
Update consumers to call the new standalone mana-credits service instead of the credit endpoints embedded in mana-core-auth. Changes: - CreditClientService: Add getCreditsUrl() reading MANA_CREDITS_URL (falls back to MANA_CORE_AUTH_URL for backward compatibility). All credit calls now use /api/v1/internal/* endpoints. - BetterAuthService: Replace direct DB inserts for credit balance and guild pool init with HTTP calls to mana-credits internal API. Replace local gift redemption with HTTP call. - .env.development: Add MANA_CREDITS_URL=http://localhost:3060 - CLAUDE.md: Add mana-credits to services list Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
64f7f768eb
commit
b0009c200b
4 changed files with 59 additions and 33 deletions
|
|
@ -23,7 +23,9 @@ PUBLIC_GLITCHTIP_DSN=
|
|||
|
||||
# Mana Core Auth Service
|
||||
MANA_CORE_AUTH_URL=http://localhost:3001
|
||||
# Service key for bot-to-auth communication (Matrix-SSO-Link)
|
||||
# Mana Credits Service
|
||||
MANA_CREDITS_URL=http://localhost:3060
|
||||
# Service key for service-to-service communication
|
||||
MANA_CORE_SERVICE_KEY=dev-service-key-for-bot-sso-2024
|
||||
|
||||
# WebAuthn / Passkeys (localhost for dev, mana.how for production)
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ manacore-monorepo/
|
|||
│ └── {game-name}/ # Individual games
|
||||
├── services/ # Standalone microservices
|
||||
│ ├── mana-core-auth/ # Central authentication service
|
||||
│ ├── mana-credits/ # Credit system (Hono + Bun, extracted from auth)
|
||||
│ ├── mana-search/ # Central search & content extraction (NestJS, legacy)
|
||||
│ ├── mana-search-go/ # Central search & content extraction (Go, active)
|
||||
│ ├── mana-crawler/ # Web crawler service
|
||||
|
|
|
|||
|
|
@ -35,6 +35,18 @@ export class CreditClientService {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the credits service URL. Uses MANA_CREDITS_URL if available,
|
||||
* falls back to MANA_CORE_AUTH_URL for backward compatibility.
|
||||
*/
|
||||
private getCreditsUrl(): string {
|
||||
return (
|
||||
this.configService?.get<string>('MANA_CREDITS_URL') ||
|
||||
process.env.MANA_CREDITS_URL ||
|
||||
this.getAuthUrl()
|
||||
);
|
||||
}
|
||||
|
||||
private getServiceKey(): string {
|
||||
return (
|
||||
this.options?.serviceKey ||
|
||||
|
|
@ -76,7 +88,7 @@ export class CreditClientService {
|
|||
}
|
||||
|
||||
async getBalance(userId: string): Promise<CreditBalance> {
|
||||
const authUrl = this.getAuthUrl();
|
||||
const creditsUrl = this.getCreditsUrl();
|
||||
const serviceKey = this.getServiceKey();
|
||||
|
||||
if (!serviceKey) {
|
||||
|
|
@ -89,7 +101,7 @@ export class CreditClientService {
|
|||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${authUrl}/api/v1/credits/balance/${userId}`, {
|
||||
const response = await fetch(`${creditsUrl}/api/v1/internal/credits/balance/${userId}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
|
@ -127,7 +139,7 @@ export class CreditClientService {
|
|||
metadata?: Record<string, any>,
|
||||
creditSource?: { type: 'personal' } | { type: 'guild'; guildId: string }
|
||||
): Promise<boolean> {
|
||||
const authUrl = this.getAuthUrl();
|
||||
const creditsUrl = this.getCreditsUrl();
|
||||
const serviceKey = this.getServiceKey();
|
||||
|
||||
if (!serviceKey) {
|
||||
|
|
@ -136,7 +148,7 @@ export class CreditClientService {
|
|||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${authUrl}/api/v1/credits/use`, {
|
||||
const response = await fetch(`${creditsUrl}/api/v1/internal/credits/use`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
|
@ -179,7 +191,7 @@ export class CreditClientService {
|
|||
description: string,
|
||||
metadata?: Record<string, any>
|
||||
): Promise<boolean> {
|
||||
const authUrl = this.getAuthUrl();
|
||||
const creditsUrl = this.getCreditsUrl();
|
||||
const serviceKey = this.getServiceKey();
|
||||
|
||||
if (!serviceKey) {
|
||||
|
|
@ -188,7 +200,7 @@ export class CreditClientService {
|
|||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${authUrl}/api/v1/credits/refund`, {
|
||||
const response = await fetch(`${creditsUrl}/api/v1/internal/credits/refund`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
|
|
|||
|
|
@ -158,22 +158,29 @@ export class BetterAuthService {
|
|||
// Create personal credit balance
|
||||
await this.createPersonalCreditBalance(user.id);
|
||||
|
||||
// Redeem any pending gift codes sent to this email
|
||||
if (this.giftCodeService) {
|
||||
try {
|
||||
const giftResult = await this.giftCodeService.redeemPendingGifts(user.id, dto.email);
|
||||
if (giftResult.redeemedCount > 0) {
|
||||
// Redeem any pending gift codes via mana-credits service
|
||||
try {
|
||||
const creditsUrl = process.env.MANA_CREDITS_URL || 'http://localhost:3060';
|
||||
const serviceKey = process.env.MANA_CORE_SERVICE_KEY || '';
|
||||
const giftRes = await fetch(`${creditsUrl}/api/v1/internal/gifts/redeem-pending`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-Service-Key': serviceKey },
|
||||
body: JSON.stringify({ userId: user.id, email: dto.email }),
|
||||
});
|
||||
if (giftRes.ok) {
|
||||
const giftResult = await giftRes.json();
|
||||
if (giftResult.redeemed > 0) {
|
||||
this.logger.log('Redeemed pending gifts on registration', {
|
||||
userId: user.id,
|
||||
redeemedCount: giftResult.redeemedCount,
|
||||
redeemedCount: giftResult.redeemed,
|
||||
totalCredits: giftResult.totalCredits,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.warn('Failed to redeem pending gifts (non-critical)', {
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
this.logger.warn('Failed to redeem pending gifts via mana-credits (non-critical)', {
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -1754,37 +1761,41 @@ export class BetterAuthService {
|
|||
* @param userId - User ID
|
||||
* @private
|
||||
*/
|
||||
/**
|
||||
* Initialize credit balance via mana-credits service.
|
||||
* Non-critical — lazy init on first access if this fails.
|
||||
*/
|
||||
private async createPersonalCreditBalance(userId: string) {
|
||||
const db = getDb(this.databaseUrl);
|
||||
|
||||
try {
|
||||
await db.insert(balances).values({
|
||||
userId: userId as any, // Cast to handle UUID type
|
||||
balance: 0,
|
||||
totalEarned: 0,
|
||||
totalSpent: 0,
|
||||
const creditsUrl = process.env.MANA_CREDITS_URL || 'http://localhost:3060';
|
||||
const serviceKey = process.env.MANA_CORE_SERVICE_KEY || '';
|
||||
await fetch(`${creditsUrl}/api/v1/internal/credits/init`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-Service-Key': serviceKey },
|
||||
body: JSON.stringify({ userId }),
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.warn('Failed to create personal credit balance (non-critical)', {
|
||||
this.logger.warn('Failed to init credit balance via mana-credits (non-critical)', {
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
// Don't throw - this is a non-critical operation
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize a guild pool for an organization.
|
||||
* Non-critical — if it fails, the pool can be created later.
|
||||
* Initialize guild pool via mana-credits service.
|
||||
* Non-critical — lazy init on first access if this fails.
|
||||
*/
|
||||
private async initializeGuildPool(organizationId: string) {
|
||||
const db = getDb(this.databaseUrl);
|
||||
|
||||
try {
|
||||
await db.insert(guildPools).values({
|
||||
organizationId,
|
||||
const creditsUrl = process.env.MANA_CREDITS_URL || 'http://localhost:3060';
|
||||
const serviceKey = process.env.MANA_CORE_SERVICE_KEY || '';
|
||||
await fetch(`${creditsUrl}/api/v1/internal/guild-pool/init`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-Service-Key': serviceKey },
|
||||
body: JSON.stringify({ organizationId }),
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.warn('Failed to initialize guild pool (non-critical)', {
|
||||
this.logger.warn('Failed to init guild pool via mana-credits (non-critical)', {
|
||||
organizationId,
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue