2026-07-15 05:50:21 +05:30
|
|
|
// retrigger-build-marker-6
|
2026-07-15 04:14:58 +05:30
|
|
|
// retrigger-build-marker-4
|
2026-07-06 03:00:37 +05:30
|
|
|
#![allow(dead_code)]
|
|
|
|
|
|
2026-07-06 02:23:29 +05:30
|
|
|
mod ai;
|
feat: Complete Ask Ash AI Credits implementation on high-performance branch (Tasks 1-10)
- Task 1: Admin endpoints for wallet management
- Task 2: AI Credits admin UI (pricing.tsx, credit.tsx)
- Task 3: Ollama security (NetworkPolicy, prompt validation, audit)
- Task 4: LiteLLM integration (litellm.rs, migrated AI feature handlers)
- Task 5: Refund architecture (ai_refunds table, endpoints)
- Task 6: Coupons, promotions, referrals (order creation with coupon)
- Task 7: Subscription lifecycle (plan upgrades/downgrades, cron jobs)
- Task 8: Credit expiration enforcement (daily cron task)
- Task 9: Token cost engine (ai_model_cost_config, margin view)
- Task 10: Observability (metrics tables, aggregation function)
Cherry-picked from main branch commit 3c0f45f
2026-07-06 01:49:16 +05:30
|
|
|
mod ai_credits;
|
|
|
|
|
mod ai_subscription;
|
2026-03-17 20:42:51 +01:00
|
|
|
mod handlers;
|
feat: Complete Ask Ash AI Credits implementation on high-performance branch (Tasks 1-10)
- Task 1: Admin endpoints for wallet management
- Task 2: AI Credits admin UI (pricing.tsx, credit.tsx)
- Task 3: Ollama security (NetworkPolicy, prompt validation, audit)
- Task 4: LiteLLM integration (litellm.rs, migrated AI feature handlers)
- Task 5: Refund architecture (ai_refunds table, endpoints)
- Task 6: Coupons, promotions, referrals (order creation with coupon)
- Task 7: Subscription lifecycle (plan upgrades/downgrades, cron jobs)
- Task 8: Credit expiration enforcement (daily cron task)
- Task 9: Token cost engine (ai_model_cost_config, margin view)
- Task 10: Observability (metrics tables, aggregation function)
Cherry-picked from main branch commit 3c0f45f
2026-07-06 01:49:16 +05:30
|
|
|
mod litellm;
|
2026-03-17 20:42:51 +01:00
|
|
|
mod mail;
|
|
|
|
|
|
feat: add Redis for OTP, auth tokens, rate limiting, lead dedup and marketplace cache
- Add crates/cache with client, otp, rate_limit, token, lead, jobs modules
- OTP tokens stored in Redis (15-min TTL, single-use GETDEL on verify)
- Refresh tokens stored in Redis (30-day TTL) — removed DB storage
- Password reset tokens stored in Redis (1-hour TTL, single-use)
- Rate limiting: register (10/hr), login (10/15min), OTP resend (3/hr), lead (5/hr), job post (20/hr)
- Lead request deduplication: 24-hour Redis lock per professional+requirement pair
- Marketplace listings cached in Redis (5-min TTL per profession+page+limit)
- Add ProfessionState{pool, redis} to contracts crate, replacing bare PgPool in all 9 profession apps
- All profession handlers and main.rs updated to use ProfessionState
- REDIS_URL env var (default: redis://127.0.0.1:6379) used across all services
- Fix profession model struct name mangling in 6 handlers (MakeupArtistRepository etc.)
- Add custom_data JSONB migration for all 9 profession profile tables
- Add onboarding_state model and repository (save_progress, complete, is_complete)
- Add onboarding handler accepting roleKey:String (not role_id:UUID) for frontend compat
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 22:58:42 +01:00
|
|
|
use axum::{routing::get, Router};
|
2026-03-17 20:42:51 +01:00
|
|
|
use std::net::SocketAddr;
|
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
|
|
|
|
use sqlx::PgPool;
|
|
|
|
|
use mail::Mailer;
|
|
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
|
|
|
pub struct AppState {
|
feat: profile photo upload, PDF resume generation, AI auto-apply, schema fixes
- Profile photo upload: POST /api/profile/photo for all roles, stores via B2 storage
- PDF resume: auto-generated from job seeker portfolio on every profile save (printpdf)
- Company applications: enriched with applicant name, avatar, headline, skills, education
- AI auto-apply cron: rewrote run_auto_apply with correct schema (job_seeker_profiles,
cover_note, ai_auto_apply_settings, ai_auto_apply_logs, credit deduction)
- Schema fix: job_seeker_profiles table name (was incorrectly 'job_seekers' in two places)
- Migration: add resume_url column to job_seeker_profiles
- Migrations: PayU rename, tracecoin hardening, lead reserve linkage, invoice/wallet crates
- PayU integration: ai_credits, packages, admin payment handlers
- Wallet and invoice crates added
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 13:15:43 +02:00
|
|
|
pub pool: PgPool,
|
|
|
|
|
pub mail: Arc<Mailer>,
|
|
|
|
|
pub redis: cache::RedisPool,
|
|
|
|
|
pub storage: Arc<storage::StorageClient>,
|
2026-03-17 20:42:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[tokio::main]
|
|
|
|
|
async fn main() {
|
|
|
|
|
tracing_subscriber::registry()
|
|
|
|
|
.with(tracing_subscriber::EnvFilter::new(
|
|
|
|
|
std::env::var("RUST_LOG").unwrap_or_else(|_| "info".into()),
|
|
|
|
|
))
|
|
|
|
|
.with(tracing_subscriber::fmt::layer())
|
|
|
|
|
.init();
|
|
|
|
|
|
feat: add Redis for OTP, auth tokens, rate limiting, lead dedup and marketplace cache
- Add crates/cache with client, otp, rate_limit, token, lead, jobs modules
- OTP tokens stored in Redis (15-min TTL, single-use GETDEL on verify)
- Refresh tokens stored in Redis (30-day TTL) — removed DB storage
- Password reset tokens stored in Redis (1-hour TTL, single-use)
- Rate limiting: register (10/hr), login (10/15min), OTP resend (3/hr), lead (5/hr), job post (20/hr)
- Lead request deduplication: 24-hour Redis lock per professional+requirement pair
- Marketplace listings cached in Redis (5-min TTL per profession+page+limit)
- Add ProfessionState{pool, redis} to contracts crate, replacing bare PgPool in all 9 profession apps
- All profession handlers and main.rs updated to use ProfessionState
- REDIS_URL env var (default: redis://127.0.0.1:6379) used across all services
- Fix profession model struct name mangling in 6 handlers (MakeupArtistRepository etc.)
- Add custom_data JSONB migration for all 9 profession profile tables
- Add onboarding_state model and repository (save_progress, complete, is_complete)
- Add onboarding handler accepting roleKey:String (not role_id:UUID) for frontend compat
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 22:58:42 +01:00
|
|
|
// Fail fast — critical env vars must be present before binding any port
|
|
|
|
|
std::env::var("JWT_SECRET").expect("JWT_SECRET must be set");
|
|
|
|
|
|
2026-03-17 20:42:51 +01:00
|
|
|
let database_url =
|
|
|
|
|
std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
|
|
|
|
|
|
|
|
|
let pool = db::establish_connection(&database_url)
|
|
|
|
|
.await
|
|
|
|
|
.expect("Failed to connect to the database");
|
|
|
|
|
|
|
|
|
|
tracing::info!("Connected to the database");
|
|
|
|
|
|
feat: add Redis for OTP, auth tokens, rate limiting, lead dedup and marketplace cache
- Add crates/cache with client, otp, rate_limit, token, lead, jobs modules
- OTP tokens stored in Redis (15-min TTL, single-use GETDEL on verify)
- Refresh tokens stored in Redis (30-day TTL) — removed DB storage
- Password reset tokens stored in Redis (1-hour TTL, single-use)
- Rate limiting: register (10/hr), login (10/15min), OTP resend (3/hr), lead (5/hr), job post (20/hr)
- Lead request deduplication: 24-hour Redis lock per professional+requirement pair
- Marketplace listings cached in Redis (5-min TTL per profession+page+limit)
- Add ProfessionState{pool, redis} to contracts crate, replacing bare PgPool in all 9 profession apps
- All profession handlers and main.rs updated to use ProfessionState
- REDIS_URL env var (default: redis://127.0.0.1:6379) used across all services
- Fix profession model struct name mangling in 6 handlers (MakeupArtistRepository etc.)
- Add custom_data JSONB migration for all 9 profession profile tables
- Add onboarding_state model and repository (save_progress, complete, is_complete)
- Add onboarding handler accepting roleKey:String (not role_id:UUID) for frontend compat
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 22:58:42 +01:00
|
|
|
let redis_url = std::env::var("REDIS_URL")
|
|
|
|
|
.unwrap_or_else(|_| "redis://127.0.0.1:6379".to_string());
|
|
|
|
|
let redis = cache::connect(&redis_url)
|
|
|
|
|
.await
|
|
|
|
|
.expect("Failed to connect to Redis");
|
|
|
|
|
tracing::info!("Connected to Redis");
|
|
|
|
|
|
2026-03-17 20:42:51 +01:00
|
|
|
let mailer = Arc::new(Mailer::new());
|
|
|
|
|
|
feat: profile photo upload, PDF resume generation, AI auto-apply, schema fixes
- Profile photo upload: POST /api/profile/photo for all roles, stores via B2 storage
- PDF resume: auto-generated from job seeker portfolio on every profile save (printpdf)
- Company applications: enriched with applicant name, avatar, headline, skills, education
- AI auto-apply cron: rewrote run_auto_apply with correct schema (job_seeker_profiles,
cover_note, ai_auto_apply_settings, ai_auto_apply_logs, credit deduction)
- Schema fix: job_seeker_profiles table name (was incorrectly 'job_seekers' in two places)
- Migration: add resume_url column to job_seeker_profiles
- Migrations: PayU rename, tracecoin hardening, lead reserve linkage, invoice/wallet crates
- PayU integration: ai_credits, packages, admin payment handlers
- Wallet and invoice crates added
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 13:15:43 +02:00
|
|
|
let storage = Arc::new(storage::StorageClient::from_env().await);
|
|
|
|
|
|
2026-03-17 20:42:51 +01:00
|
|
|
let state = AppState {
|
|
|
|
|
pool,
|
feat: profile photo upload, PDF resume generation, AI auto-apply, schema fixes
- Profile photo upload: POST /api/profile/photo for all roles, stores via B2 storage
- PDF resume: auto-generated from job seeker portfolio on every profile save (printpdf)
- Company applications: enriched with applicant name, avatar, headline, skills, education
- AI auto-apply cron: rewrote run_auto_apply with correct schema (job_seeker_profiles,
cover_note, ai_auto_apply_settings, ai_auto_apply_logs, credit deduction)
- Schema fix: job_seeker_profiles table name (was incorrectly 'job_seekers' in two places)
- Migration: add resume_url column to job_seeker_profiles
- Migrations: PayU rename, tracecoin hardening, lead reserve linkage, invoice/wallet crates
- PayU integration: ai_credits, packages, admin payment handlers
- Wallet and invoice crates added
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 13:15:43 +02:00
|
|
|
mail: mailer,
|
feat: add Redis for OTP, auth tokens, rate limiting, lead dedup and marketplace cache
- Add crates/cache with client, otp, rate_limit, token, lead, jobs modules
- OTP tokens stored in Redis (15-min TTL, single-use GETDEL on verify)
- Refresh tokens stored in Redis (30-day TTL) — removed DB storage
- Password reset tokens stored in Redis (1-hour TTL, single-use)
- Rate limiting: register (10/hr), login (10/15min), OTP resend (3/hr), lead (5/hr), job post (20/hr)
- Lead request deduplication: 24-hour Redis lock per professional+requirement pair
- Marketplace listings cached in Redis (5-min TTL per profession+page+limit)
- Add ProfessionState{pool, redis} to contracts crate, replacing bare PgPool in all 9 profession apps
- All profession handlers and main.rs updated to use ProfessionState
- REDIS_URL env var (default: redis://127.0.0.1:6379) used across all services
- Fix profession model struct name mangling in 6 handlers (MakeupArtistRepository etc.)
- Add custom_data JSONB migration for all 9 profession profile tables
- Add onboarding_state model and repository (save_progress, complete, is_complete)
- Add onboarding handler accepting roleKey:String (not role_id:UUID) for frontend compat
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 22:58:42 +01:00
|
|
|
redis,
|
feat: profile photo upload, PDF resume generation, AI auto-apply, schema fixes
- Profile photo upload: POST /api/profile/photo for all roles, stores via B2 storage
- PDF resume: auto-generated from job seeker portfolio on every profile save (printpdf)
- Company applications: enriched with applicant name, avatar, headline, skills, education
- AI auto-apply cron: rewrote run_auto_apply with correct schema (job_seeker_profiles,
cover_note, ai_auto_apply_settings, ai_auto_apply_logs, credit deduction)
- Schema fix: job_seeker_profiles table name (was incorrectly 'job_seekers' in two places)
- Migration: add resume_url column to job_seeker_profiles
- Migrations: PayU rename, tracecoin hardening, lead reserve linkage, invoice/wallet crates
- PayU integration: ai_credits, packages, admin payment handlers
- Wallet and invoice crates added
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-02 13:15:43 +02:00
|
|
|
storage,
|
2026-03-17 20:42:51 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let app = Router::new()
|
|
|
|
|
// ── Auth ─────────────────────────────────────────────────────────
|
|
|
|
|
.nest("/api/auth", handlers::auth::router())
|
2026-04-16 18:06:06 +02:00
|
|
|
// ── V1 API (backward compatibility) ───────────────────────────────
|
|
|
|
|
.nest("/api/v1/users", handlers::auth::v1_router())
|
2026-03-17 20:42:51 +01:00
|
|
|
// ── Roles & User Self-Service ─────────────────────────────────────
|
|
|
|
|
.nest("/api/admin/roles", handlers::roles::router())
|
2026-03-25 22:15:07 +01:00
|
|
|
.nest("/api/admin/permissions", handlers::permissions::router())
|
2026-03-27 21:25:31 +01:00
|
|
|
.nest("/api/admin/external-roles", handlers::external_roles::router())
|
2026-04-26 23:58:43 +02:00
|
|
|
.merge(handlers::modules::persona_types_router())
|
|
|
|
|
.merge(handlers::modules::modules_router())
|
|
|
|
|
.merge(handlers::modules::role_modules_router())
|
2026-04-02 13:09:43 +02:00
|
|
|
.nest("/api/admin/users", handlers::admin::router())
|
2026-03-19 00:30:23 +01:00
|
|
|
.nest("/api/me/roles", handlers::user_roles::router())
|
2026-03-17 20:42:51 +01:00
|
|
|
// ── Notifications ─────────────────────────────────────────────────
|
|
|
|
|
.nest("/api/me/notifications", handlers::notifications::router())
|
2026-04-08 22:40:54 +02:00
|
|
|
.nest("/api/me/settings", handlers::settings::router())
|
2026-03-19 00:30:23 +01:00
|
|
|
// ── Admin: Approvals (jobs/requirements) ─────────────────────────
|
|
|
|
|
.nest("/api/admin/approvals", handlers::approvals::router())
|
2026-04-06 03:39:41 +02:00
|
|
|
.nest("/api/admin/verifications", handlers::verifications::router())
|
2026-04-06 17:20:49 +02:00
|
|
|
// ── Me: Profile Status + Verification Status ──────────────────────
|
2026-06-10 16:17:10 +02:00
|
|
|
.nest("/api/me", handlers::profile::me_router())
|
2026-04-06 17:20:49 +02:00
|
|
|
// ── Profile (save + submit-for-verification) ──────────────────────
|
|
|
|
|
.nest("/api/profile", handlers::profile::router())
|
|
|
|
|
// ── Onboarding State (legacy, kept for compatibility) ────────────
|
feat: add Redis for OTP, auth tokens, rate limiting, lead dedup and marketplace cache
- Add crates/cache with client, otp, rate_limit, token, lead, jobs modules
- OTP tokens stored in Redis (15-min TTL, single-use GETDEL on verify)
- Refresh tokens stored in Redis (30-day TTL) — removed DB storage
- Password reset tokens stored in Redis (1-hour TTL, single-use)
- Rate limiting: register (10/hr), login (10/15min), OTP resend (3/hr), lead (5/hr), job post (20/hr)
- Lead request deduplication: 24-hour Redis lock per professional+requirement pair
- Marketplace listings cached in Redis (5-min TTL per profession+page+limit)
- Add ProfessionState{pool, redis} to contracts crate, replacing bare PgPool in all 9 profession apps
- All profession handlers and main.rs updated to use ProfessionState
- REDIS_URL env var (default: redis://127.0.0.1:6379) used across all services
- Fix profession model struct name mangling in 6 handlers (MakeupArtistRepository etc.)
- Add custom_data JSONB migration for all 9 profession profile tables
- Add onboarding_state model and repository (save_progress, complete, is_complete)
- Add onboarding handler accepting roleKey:String (not role_id:UUID) for frontend compat
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 22:58:42 +01:00
|
|
|
.nest("/api/onboarding", handlers::onboarding::onboarding_router())
|
2026-03-17 20:42:51 +01:00
|
|
|
// ── Admin: Onboarding + Dashboard Config ──────────────────────────
|
|
|
|
|
.nest("/api/admin/onboarding-config", handlers::config::onboarding_router())
|
|
|
|
|
.nest("/api/admin/dashboard-config", handlers::config::dashboard_router())
|
2026-03-25 23:55:44 +01:00
|
|
|
.nest("/api/admin/dashboard", handlers::dashboard::router())
|
2026-03-27 21:25:31 +01:00
|
|
|
.nest("/api/admin/runtime-configs", handlers::config::admin_runtime_router())
|
2026-04-06 18:23:04 +02:00
|
|
|
// ── Admin: Activity Logs (Audit) ───────────────────────────────────
|
|
|
|
|
.nest("/api/admin/activity-logs", handlers::activity_logs::router())
|
2026-03-17 20:42:51 +01:00
|
|
|
// ── Public Config ─────────────────────────────────────────────────
|
|
|
|
|
.nest("/api/config/onboarding", handlers::config::onboarding_router())
|
|
|
|
|
.nest("/api/config/dashboard", handlers::config::dashboard_router())
|
|
|
|
|
.nest("/api/runtime-config", handlers::config::runtime_router())
|
2026-04-02 13:36:12 +02:00
|
|
|
// ── Knowledge Base (public) ───────────────────────────────────────
|
|
|
|
|
.nest("/api/kb", handlers::kb::public_router())
|
|
|
|
|
// ── Knowledge Base (admin) ────────────────────────────────────────
|
|
|
|
|
.nest("/api/admin/kb", handlers::kb::admin_router())
|
|
|
|
|
// ── Support Tickets (user-facing) ─────────────────────────────────
|
|
|
|
|
.nest("/api/support/tickets", handlers::support::user_router())
|
|
|
|
|
// ── Support Tickets (admin) ───────────────────────────────────────
|
|
|
|
|
.nest("/api/admin/support-cases", handlers::support::admin_router())
|
2026-07-19 16:34:00 +05:30
|
|
|
// ── Reference number lookup (AI assistant) ────────────────────────
|
|
|
|
|
.nest("/api/support", handlers::support::reference_router())
|
2026-06-10 16:17:10 +02:00
|
|
|
// ── Reviews (public + admin) ─────────────────────────────────────
|
|
|
|
|
.nest("/api/reviews", handlers::reviews::public_router())
|
Add reviews, coupons, discounts, pricing packages, and reports handlers
- handlers/reviews.rs: admin CRUD for /api/admin/reviews (list, create, patch status, delete)
- handlers/coupons.rs: admin CRUD for /api/admin/coupons and /api/admin/discounts
- handlers/pricing.rs: admin CRUD for /api/admin/tracecoin-packages + /api/admin/reports/{users,revenue}
- handlers/dashboard.rs: replace all hardcoded fake data with real DB queries (registrations per day, revenue per week, live KPIs including pending approvals and total revenue)
- Migrations: extend reviews table (nullable FKs + admin fields), add coupons.title/role_keys, create discounts table
- gateway: route new admin paths to users service
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 18:09:50 +02:00
|
|
|
.nest("/api/admin/reviews", handlers::reviews::admin_router())
|
|
|
|
|
// ── Coupons & Discounts (admin) ───────────────────────────────────
|
|
|
|
|
.nest("/api/admin/coupons", handlers::coupons::coupons_router())
|
|
|
|
|
.nest("/api/admin/discounts", handlers::coupons::discounts_router())
|
2026-06-26 21:07:36 +02:00
|
|
|
.nest("/api/admin/payment-gateway-config", handlers::payment_gateway::router())
|
2026-04-02 18:11:44 +02:00
|
|
|
// ── Tracecoin Packages (public) ───────────────────────────────────
|
|
|
|
|
.nest("/api/packages", handlers::pricing::public_packages_router())
|
Add reviews, coupons, discounts, pricing packages, and reports handlers
- handlers/reviews.rs: admin CRUD for /api/admin/reviews (list, create, patch status, delete)
- handlers/coupons.rs: admin CRUD for /api/admin/coupons and /api/admin/discounts
- handlers/pricing.rs: admin CRUD for /api/admin/tracecoin-packages + /api/admin/reports/{users,revenue}
- handlers/dashboard.rs: replace all hardcoded fake data with real DB queries (registrations per day, revenue per week, live KPIs including pending approvals and total revenue)
- Migrations: extend reviews table (nullable FKs + admin fields), add coupons.title/role_keys, create discounts table
- gateway: route new admin paths to users service
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 18:09:50 +02:00
|
|
|
// ── Tracecoin Packages & Reports (admin) ──────────────────────────
|
|
|
|
|
.nest("/api/admin/tracecoin-packages", handlers::pricing::packages_router())
|
|
|
|
|
.nest("/api/admin/reports", handlers::pricing::reports_router())
|
2026-04-10 04:49:39 +02:00
|
|
|
// ── Email Management (admin) ──────────────────────────────────────
|
|
|
|
|
.nest("/api/admin/email", handlers::admin_email::router())
|
2026-06-14 20:27:57 +02:00
|
|
|
// ── AI Management (admin) ────────────────────────────────────────
|
2026-06-15 06:18:52 +05:30
|
|
|
.nest("/api/admin/ai", handlers::admin_ai::admin_ai_router())
|
2026-04-15 18:19:07 +02:00
|
|
|
// ── AI Assistant ──────────────────────────────────────────────────
|
feat: Complete Ask Ash AI Credits implementation on high-performance branch (Tasks 1-10)
- Task 1: Admin endpoints for wallet management
- Task 2: AI Credits admin UI (pricing.tsx, credit.tsx)
- Task 3: Ollama security (NetworkPolicy, prompt validation, audit)
- Task 4: LiteLLM integration (litellm.rs, migrated AI feature handlers)
- Task 5: Refund architecture (ai_refunds table, endpoints)
- Task 6: Coupons, promotions, referrals (order creation with coupon)
- Task 7: Subscription lifecycle (plan upgrades/downgrades, cron jobs)
- Task 8: Credit expiration enforcement (daily cron task)
- Task 9: Token cost engine (ai_model_cost_config, margin view)
- Task 10: Observability (metrics tables, aggregation function)
Cherry-picked from main branch commit 3c0f45f
2026-07-06 01:49:16 +05:30
|
|
|
.nest("/api/ai", handlers::ai::ai_router())
|
|
|
|
|
// ── Ask Ash AI Credits (Phase 1) ────────────────────────────────────
|
|
|
|
|
.nest("/api/ai-credits", handlers::ai_credits::router())
|
2026-07-16 20:29:00 +05:30
|
|
|
|
|
|
|
|
.nest("/internal/users", handlers::internal::router())
|
feat: Complete Ask Ash AI Credits implementation on high-performance branch (Tasks 1-10)
- Task 1: Admin endpoints for wallet management
- Task 2: AI Credits admin UI (pricing.tsx, credit.tsx)
- Task 3: Ollama security (NetworkPolicy, prompt validation, audit)
- Task 4: LiteLLM integration (litellm.rs, migrated AI feature handlers)
- Task 5: Refund architecture (ai_refunds table, endpoints)
- Task 6: Coupons, promotions, referrals (order creation with coupon)
- Task 7: Subscription lifecycle (plan upgrades/downgrades, cron jobs)
- Task 8: Credit expiration enforcement (daily cron task)
- Task 9: Token cost engine (ai_model_cost_config, margin view)
- Task 10: Observability (metrics tables, aggregation function)
Cherry-picked from main branch commit 3c0f45f
2026-07-06 01:49:16 +05:30
|
|
|
.nest("/api/admin/ai-credits", handlers::ai_credits::admin_router())
|
feat: add Redis for OTP, auth tokens, rate limiting, lead dedup and marketplace cache
- Add crates/cache with client, otp, rate_limit, token, lead, jobs modules
- OTP tokens stored in Redis (15-min TTL, single-use GETDEL on verify)
- Refresh tokens stored in Redis (30-day TTL) — removed DB storage
- Password reset tokens stored in Redis (1-hour TTL, single-use)
- Rate limiting: register (10/hr), login (10/15min), OTP resend (3/hr), lead (5/hr), job post (20/hr)
- Lead request deduplication: 24-hour Redis lock per professional+requirement pair
- Marketplace listings cached in Redis (5-min TTL per profession+page+limit)
- Add ProfessionState{pool, redis} to contracts crate, replacing bare PgPool in all 9 profession apps
- All profession handlers and main.rs updated to use ProfessionState
- REDIS_URL env var (default: redis://127.0.0.1:6379) used across all services
- Fix profession model struct name mangling in 6 handlers (MakeupArtistRepository etc.)
- Add custom_data JSONB migration for all 9 profession profile tables
- Add onboarding_state model and repository (save_progress, complete, is_complete)
- Add onboarding handler accepting roleKey:String (not role_id:UUID) for frontend compat
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 22:58:42 +01:00
|
|
|
.route("/health", get(|| async { "Users OK" }))
|
2026-03-17 20:42:51 +01:00
|
|
|
.with_state(state);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let port: u16 = std::env::var("PORT")
|
2026-04-09 22:18:30 +02:00
|
|
|
.unwrap_or_else(|_| "9101".to_string())
|
2026-03-17 20:42:51 +01:00
|
|
|
.parse()
|
|
|
|
|
.expect("PORT must be a valid u16");
|
|
|
|
|
let addr = SocketAddr::from(([0, 0, 0, 0], port));
|
|
|
|
|
|
|
|
|
|
tracing::info!("Users service listening on {}", addr);
|
|
|
|
|
|
|
|
|
|
let listener = tokio::net::TcpListener::bind(&addr).await.unwrap();
|
2026-06-15 09:23:44 +05:30
|
|
|
let _app = axum::serve(listener, app).await.unwrap();
|
2026-03-17 20:42:51 +01:00
|
|
|
}
|