Skip to content

Commit e76b991

Browse files
committed
feat: payment gateways (CCAvenue + Wise), launch pricing (/₹1,999), 5 free AI interviews, BYOK enforcement, billing admin tab, subscription expiry reminders
1 parent ccf425e commit e76b991

17 files changed

Lines changed: 1486 additions & 479 deletions

.gitignore

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
1-
node_modules/
1+
node_modules/
22

33
# wrangler files
44
.wrangler
55
.dev.vars*
66
!.dev.vars.example
77
.env*
88
!.env.example
9+
10+
# Test & debug files
11+
test-*.js
12+
req.js
13+
fix-*.js
14+
commit-fixes.bat
15+
git_status.txt
16+
file-list.txt
17+
18+
# Temp SQL files
19+
fix-*.sql
20+
fix_*.sql
21+
schema-audit.sql

auth/register-company.html

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -518,20 +518,10 @@ <h3 style="font-size: 1rem; margin-bottom: 1rem;">Setup Preferences</h3>
518518
console.warn('[registration] Worker company create failed, trying direct:', workerErr);
519519
}
520520

521-
// 3. Fallback: direct insert if Worker unavailable
521+
// 3. If Worker API failed, show user-friendly error instead of bypassing server validation
522522
if (!companyId) {
523-
try {
524-
const { data: company, error: ce } = await db.from('companies').insert({
525-
name: payload.company_name, email: payload.email,
526-
contact_email: payload.email, industry: payload.industry,
527-
company_size: payload.company_size, website: payload.website,
528-
subscription_plan: 'trial', is_active: true,
529-
subscription_start: new Date().toISOString().split('T')[0],
530-
subscription_end: new Date(Date.now() + 2 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]
531-
}).select().single();
532-
if (!ce && company) companyId = company.id;
533-
else console.warn('[registration] Direct companies insert failed:', ce?.message);
534-
} catch (e) { console.warn('[registration] Direct insert error:', e); }
523+
toast('Our registration service is temporarily unavailable. Please try again in a few minutes.', 'error');
524+
return;
535525
}
536526

537527
// 4. Create user profile

backend/simpatico-ats.js

Lines changed: 431 additions & 273 deletions
Large diffs are not rendered by default.

backend/wrangler.toml

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ workers_dev = true
2525
PLATFORM_NAME = "Simpatico HR Enterprise"
2626
ENVIRONMENT = "production"
2727
API_VERSION = "5.0.0-Industrial"
28+
CCAVENUE_ENV = "test"
29+
FRONTEND_URL = "https://simpaticohrconsultancy.com"
30+
WORKER_URL = "https://simpatico-hr-ats.simpaticohrconsultancy.workers.dev"
2831

2932
# ── Cloudflare AI (This Fixes the AI Assistant Tab) ──
3033
[env.production.ai]
@@ -55,16 +58,12 @@ binding = "HR_KV"
5558
id = "01a7d0500ff94d09b7086b56be975d0c"
5659

5760
# ── Payment Gateway Config ──
58-
# Set secrets via: wrangler secret put CASHFREE_APP_ID --env production
61+
# Set secrets via: wrangler secret put CCAVENUE_MERCHANT_ID --env production
5962
# Required secrets:
60-
# CASHFREE_APP_ID — From Cashfree dashboard
61-
# CASHFREE_SECRET_KEY — From Cashfree dashboard
62-
# PADDLE_API_KEY — From Paddle dashboard > Developer Tools
63-
# PADDLE_WEBHOOK_SECRET — From Paddle dashboard > Notifications
63+
# CCAVENUE_MERCHANT_ID — From CCAvenue M.A.R.S. dashboard
64+
# CCAVENUE_ACCESS_CODE — From CCAvenue dashboard > API Keys
65+
# CCAVENUE_WORKING_KEY — From CCAvenue dashboard > API Keys
66+
# WISE_API_TOKEN — From Wise Business > API Tokens (optional)
6467

65-
# Non-secret vars:
66-
# [env.production.vars]
67-
# CASHFREE_ENV = "sandbox" # "sandbox" or "production"
68-
# PADDLE_ENV = "sandbox" # "sandbox" or "production"
69-
# FRONTEND_URL = "https://simpaticohr.github.io"
70-
# WORKER_URL = "https://simpatico-hr-ats.simpaticohrconsultancy.workers.dev"
68+
# Non-secret vars (added to [env.production.vars] above):
69+
# CCAVENUE_ENV, FRONTEND_URL, WORKER_URL are set in [env.production.vars]

contact.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ <h3>HRMS & Payroll</h3>
518518
<div class="how-card">
519519
<div class="h-icon"><i class="fas fa-shield-halved" style="color:#dc2626"></i></div>
520520
<h3>Enterprise Security</h3>
521-
<p>Multi-tenant isolation, RBAC, JWT auth, TLS 1.3, Razorpay PCI DSS L1 payments</p>
521+
<p>Multi-tenant isolation, RBAC, JWT auth, TLS 1.3, CCAvenue PCI DSS L1 payments</p>
522522
</div>
523523
</div>
524524

@@ -528,7 +528,7 @@ <h3>Built With Modern Infrastructure</h3>
528528
<span class="region-tag"><i class="fas fa-cloud" style="color:var(--accent);margin-right:4px"></i> Cloudflare Workers</span>
529529
<span class="region-tag"><i class="fas fa-database" style="color:#059669;margin-right:4px"></i> Supabase PostgreSQL</span>
530530
<span class="region-tag"><i class="fas fa-brain" style="color:#7c3aed;margin-right:4px"></i> AI/LLM Integration</span>
531-
<span class="region-tag"><i class="fas fa-credit-card" style="color:#0078d4;margin-right:4px"></i> Razorpay Payments</span>
531+
<span class="region-tag"><i class="fas fa-credit-card" style="color:#0078d4;margin-right:4px"></i> CCAvenue + Wise Payments</span>
532532
<span class="region-tag"><i class="fas fa-lock" style="color:#dc2626;margin-right:4px"></i> Row-Level Security</span>
533533
<span class="region-tag"><i class="fas fa-language" style="color:var(--orange);margin-right:4px"></i> Multi-Language</span>
534534
<span class="region-tag"><i class="fas fa-key" style="color:#eab308;margin-right:4px"></i> BYOK AI Support</span>
@@ -547,7 +547,7 @@ <h2 class="fade-in">Frequently Asked Questions</h2>
547547
</div>
548548
<div class="faq-item fade-in">
549549
<div class="faq-q" onclick="toggleFaq(this)">How is my company's data secured? <i class="fas fa-chevron-down"></i></div>
550-
<div class="faq-a">We use <strong>multi-tenant row-level security</strong> on Supabase (PostgreSQL), TLS 1.3 encryption in transit, JWT-based authentication via Cloudflare Workers, and Razorpay PCI DSS Level 1 for payments. Each organization's data is completely isolated.</div>
550+
<div class="faq-a">We use <strong>multi-tenant row-level security</strong> on Supabase (PostgreSQL), TLS 1.3 encryption in transit, JWT-based authentication via Cloudflare Workers, and CCAvenue PCI DSS Level 1 for domestic payments and Wise for international payments. Each organization's data is completely isolated.</div>
551551
</div>
552552
<div class="faq-item fade-in">
553553
<div class="faq-q" onclick="toggleFaq(this)">How long does enterprise onboarding take? <i class="fas fa-chevron-down"></i></div>

dashboard/hr.html

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2051,10 +2051,11 @@ <h4>Multi-Platform Job Syndication</h4>
20512051
const saveData = await saveRes.json();
20522052
console.log('[BYOK] Config saved via backend:', saveData);
20532053

2054-
// Also update local cache for UI state
2055-
localStorage.setItem('simpatico_ai_settings_' + tenantId, JSON.stringify(updates));
2056-
Object.assign(compData, updates);
2057-
localStorage.setItem('simpatico_company', JSON.stringify(compData));
2054+
// Also update local cache for UI state (never store api_key in localStorage)
2055+
const safeUpdates = { ai_provider: updates.ai_provider, ai_model: updates.ai_model, ai_base_url: updates.ai_base_url };
2056+
localStorage.setItem('simpatico_ai_settings_' + tenantId, JSON.stringify(safeUpdates));
2057+
const { ai_api_key: _discardKey, ...safeCompData } = { ...compData, ...safeUpdates };
2058+
localStorage.setItem('simpatico_company', JSON.stringify(safeCompData));
20582059

20592060
if (typeof showToast === 'function') {
20602061
let modelLabel;

js/hr-config.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ window.SIMPATICO_CONFIG = {
2929
},
3030
appVersion: '5.0.0-Industrial',
3131

32-
// 5. PAYMENT GATEWAYRazorpay (Test Mode)
33-
razorpayKeyId: 'rzp_test_yourtestkeyhere', // Replace with your Razorpay Test Key ID
34-
razorpayEnv: 'test', // 'test' or 'live'
32+
// 5. PAYMENT GATEWAYSCCAvenue (Domestic) + Wise (International)
33+
ccavenueMerchantId: '', // Set your CCAvenue Merchant ID
34+
ccavenueEnv: 'test', // 'test' or 'production'
3535

3636
// Helper to generate Trace IDs for debugging (crypto-safe)
3737
generateTraceId: () => {
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
-- ═══════════════════════════════════════════════════════════════════════════════
2+
-- SIMPATICO HR — COMPANIES TABLE RLS + BYOK COLUMN PROTECTION
3+
-- ═══════════════════════════════════════════════════════════════════════════════
4+
-- Fixes Critical Issue C5: The `companies` table had NO Row-Level Security.
5+
-- This migration enables RLS and adds tenant-scoped policies to prevent
6+
-- cross-tenant access to BYOK AI configuration (api keys, provider, model).
7+
-- ═══════════════════════════════════════════════════════════════════════════════
8+
9+
-- 1. Enable RLS on the companies table
10+
ALTER TABLE public.companies ENABLE ROW LEVEL SECURITY;
11+
12+
-- 2. Service role bypass (Worker API uses service_role for backend operations)
13+
CREATE POLICY "service_full_access" ON public.companies
14+
FOR ALL TO service_role
15+
USING (true)
16+
WITH CHECK (true);
17+
18+
-- 3. Authenticated users can only read their own company row
19+
-- The tenant_id in JWT claims must match the company's id
20+
CREATE POLICY "tenant_read_own_company" ON public.companies
21+
FOR SELECT TO authenticated
22+
USING (
23+
id = COALESCE(
24+
(auth.jwt()->'app_metadata'->>'tenant_id'),
25+
(auth.jwt()->'app_metadata'->>'company_id'),
26+
(auth.jwt()->'user_metadata'->>'tenant_id'),
27+
(auth.jwt()->'user_metadata'->>'company_id'),
28+
'SIMP_PRO_MAIN'
29+
)
30+
);
31+
32+
-- 4. Only service_role (backend Worker) can update company rows
33+
-- Authenticated users must go through the Worker API endpoints
34+
-- which enforce role checks (admin, company_admin, etc.)
35+
CREATE POLICY "tenant_update_own_company" ON public.companies
36+
FOR UPDATE TO authenticated
37+
USING (
38+
id = COALESCE(
39+
(auth.jwt()->'app_metadata'->>'tenant_id'),
40+
(auth.jwt()->'app_metadata'->>'company_id'),
41+
(auth.jwt()->'user_metadata'->>'tenant_id'),
42+
(auth.jwt()->'user_metadata'->>'company_id'),
43+
'SIMP_PRO_MAIN'
44+
)
45+
)
46+
WITH CHECK (
47+
id = COALESCE(
48+
(auth.jwt()->'app_metadata'->>'tenant_id'),
49+
(auth.jwt()->'app_metadata'->>'company_id'),
50+
(auth.jwt()->'user_metadata'->>'tenant_id'),
51+
(auth.jwt()->'user_metadata'->>'company_id'),
52+
'SIMP_PRO_MAIN'
53+
)
54+
);
55+
56+
-- ═══════════════════════════════════════════════════════════════════════════════
57+
-- DONE. After running this migration:
58+
-- 1. The `companies` table now has RLS enabled
59+
-- 2. Authenticated users can only read/update their OWN company row
60+
-- 3. The backend Worker (service_role) retains full access for admin operations
61+
-- 4. Direct Supabase API calls with anon/authenticated keys are now tenant-scoped
62+
-- ═══════════════════════════════════════════════════════════════════════════════
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
-- Migration 024: Update payment tables for CCAvenue + Wise gateway switch
2+
-- Replaces Razorpay references with dual-gateway support:
3+
-- CCAvenue (domestic INR) + Wise (international USD)
4+
-- ═══════════════════════════════════════════════════════════════════
5+
6+
-- 1. Add new columns to payment_transactions for richer tracking
7+
ALTER TABLE payment_transactions ADD COLUMN IF NOT EXISTS gateway_payment_id TEXT;
8+
ALTER TABLE payment_transactions ADD COLUMN IF NOT EXISTS payment_method TEXT; -- upi, card, netbanking, wallet, bank_transfer
9+
ALTER TABLE payment_transactions ADD COLUMN IF NOT EXISTS gateway_response JSONB DEFAULT '{}';
10+
ALTER TABLE payment_transactions ADD COLUMN IF NOT EXISTS customer_email TEXT;
11+
ALTER TABLE payment_transactions ADD COLUMN IF NOT EXISTS customer_name TEXT;
12+
ALTER TABLE payment_transactions ADD COLUMN IF NOT EXISTS is_international BOOLEAN DEFAULT false;
13+
14+
-- 2. Add amount column to subscriptions if not present
15+
ALTER TABLE subscriptions ADD COLUMN IF NOT EXISTS amount NUMERIC(12, 2);
16+
17+
-- 3. Create indexes for new columns
18+
CREATE INDEX IF NOT EXISTS idx_payment_transactions_gateway ON payment_transactions(gateway);
19+
CREATE INDEX IF NOT EXISTS idx_payment_transactions_gateway_payment_id ON payment_transactions(gateway_payment_id);
20+
CREATE INDEX IF NOT EXISTS idx_payment_transactions_is_international ON payment_transactions(is_international);
21+
22+
-- 4. Update any existing gateway references (data migration)
23+
-- Convert old 'razorpay' gateway entries to 'legacy_razorpay' for audit trail
24+
UPDATE payment_transactions SET gateway = 'legacy_razorpay' WHERE gateway = 'razorpay';
25+
UPDATE subscriptions SET gateway = 'legacy_razorpay' WHERE gateway = 'razorpay';

0 commit comments

Comments
 (0)