File size: 5,244 Bytes
e14bacb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
global.isStrikeRunning = false;

require('dotenv').config();
const express = require('express');
const mongoose = require('mongoose');
const cors = require('cors');
const { generateKUS } = require('./utils/kusGenerator');

const authRoute = require('./routes/auth');
const marketRoute = require('./routes/market');
const adminRoute = require('./routes/admin');

// Import Models
const User = require('./models/User');
const Transaction = require('./models/Transaction');
const Asset = require('./models/Asset');
const notificationRoute = require('./routes/notification');

const startStrike = require('./jobs/strike');

const logTransaction = require('./utils/ledgerLogger');
const { sendToUser } = require('./utils/sendPush');

startStrike(); // Starts the internal clock

const app = express();

// Middleware
app.use(cors());
app.use(express.json()); // Allows us to read JSON from the iPhone

// Route Middlewares
app.use('/api/auth', authRoute);
app.use('/api/market', marketRoute);
app.use('/api/admin', adminRoute);
app.use('/api/notifications', notificationRoute);
app.use("/api/strike", require("./routes/strike"));
app.use('/api/fairness', require('./routes/fairness'));

// ------------------------------------------------------------------
// ROUTE 1: Health Check (To see if server is alive)
// ------------------------------------------------------------------
app.get('/', (req, res) => {
  res.send('KoshX System: Securely Running....');
});

// ------------------------------------------------------------------
// ROUTE 2: The Payment Webhook (Where the iPhone talks to us)
// ------------------------------------------------------------------
app.post('/api/webhook/sms-capture', async (req, res) => {
  try {
    // 1. Security Gate
    const secret = req.headers['x-admin-secret'];
    if (secret !== process.env.ADMIN_SECRET) {
      console.log('Unauthorized Webhook Attempt');
      return res.status(403).json({ error: "Access Denied" });
    }

    // 2. Extract Data
    const { utr, amount } = req.body;
    console.log(`[Webhook] Received UTR: ${utr}`);

    // 3. Find the Pending Transaction
    // NOTE: In a real flow, the user creates a "Pending" transaction via the App first.
    // If you are just testing the Webhook without the App, we might not find a transaction yet.
    // For now, let's assume the App created it.
    
    const transaction = await Transaction.findOne({ utr: utr, status: 'Pending' });

    if (!transaction) {
      return res.status(404).json({ message: "Transaction not found or already verified." });
    }

    // 4. Generate the Asset
    const newKUS = await generateKUS(transaction.tier);

    // 5. Assign to User
    const newAsset = new Asset({
      owner_id: transaction.user_id,
      kus_id: newKUS,
      tier: transaction.tier
    });
    await newAsset.save();

    // 6. Update Transaction Status
    transaction.status = 'Verified';
    await transaction.save();

    // 7. Referral Logic (Check if First Purchase)
    const assetCount = await Asset.countDocuments({ owner_id: tx.user_id });
        if (assetCount === 1) {
            const user = await User.findById(tx.user_id);
            if (user.referred_by) {
                const referrer = await User.findOne({ referral_code: user.referred_by });
                if (referrer) {
                    let reward = 0;
                    if (tx.tier === 'Silver') reward = 100;
                    if (tx.tier === 'Gold') reward = 150;
                    if (tx.tier === 'Platinum') reward = 250;
    
                    let userReward = 0;
                    if (tx.tier === 'Silver') reward = 50;
                    if (tx.tier === 'Gold') reward = 75;
                    if (tx.tier === 'Platinum') reward = 125;
                    
                    referrer.points += reward;
                    await referrer.save();
    
                    user.points += userReward;
                    await user.save();
    
                    await logTransaction(referrer._id, 'REFERRAL_BONUS', reward, 'INR', `Referral Bonus Tier: ${tx.tier}`);
                    await sendToUser(referrer._id, "Referral Bonus Credited", `${reward} points credited to your account.`, "/profile");
    
                    await logTransaction(user._id, 'REFERRAL_BONUS', userReward, 'INR', `Referral Bonus Tier: ${tx.tier}`);
                    await sendToUser(user._id, "Referral Bonus Credited", `${userReward} points credited to your account.`, "/profile");
    
                    console.log(`[Referral] ${reward} points added to ${referrer.name}`);
                }
            }
        }

    console.log(`[Success] Asset ${newKUS} generated for UTR ${utr}`);
    res.status(200).json({ success: true, kus: newKUS });

  } catch (error) {
    console.error("Webhook Error:", error);
    res.status(500).json({ error: "Server Internal Error" });
  }
});

// Database Connection & Server Start
mongoose.connect(process.env.MONGO_URI)
  .then(() => {
    console.log('βœ… Connected to MongoDB Atlas');
    app.listen(process.env.PORT, '0.0.0.0', () => {
      console.log(`πŸš€ Server running on port ${process.env.PORT}`);
    });
  })
  .catch((err) => console.error('❌ DB Connection Error:', err));