fix stripe for production
Build & Push / Pipeline Tests (push) Successful in 1m51s
Test / Type Check (all packages) (push) Successful in 52s
Test / API Unit Tests (push) Successful in 1m10s
Test / Homepage Unit Tests (push) Successful in 48s
Test / Carplace Unit Tests (push) Successful in 44s
Test / Admin Unit Tests (push) Successful in 44s
Test / Dashboard Unit Tests (push) Successful in 44s
Test / API Integration Tests (push) Successful in 1m7s
Build & Push / Build & Push Docker Image (push) Failing after 41s
Build & Push / Pipeline Tests (push) Successful in 1m51s
Test / Type Check (all packages) (push) Successful in 52s
Test / API Unit Tests (push) Successful in 1m10s
Test / Homepage Unit Tests (push) Successful in 48s
Test / Carplace Unit Tests (push) Successful in 44s
Test / Admin Unit Tests (push) Successful in 44s
Test / Dashboard Unit Tests (push) Successful in 44s
Test / API Integration Tests (push) Successful in 1m7s
Build & Push / Build & Push Docker Image (push) Failing after 41s
This commit is contained in:
+3
-3
@@ -36,8 +36,8 @@ CORS_ORIGINS=http://localhost:3000,http://localhost:3001,http://localhost:3002,h
|
||||
# Stripe subscription checkout
|
||||
# STRIPE_API_KEY must be a Stripe secret/restricted key (sk_ or rk_).
|
||||
# STRIPE_WEBHOOK_SECRET must be a Stripe webhook signing secret (whsec_).
|
||||
STRIPE_API_KEY=sk_test_51TvTsb9SpDRZn9yJyBAlUSXcTp9zpwQfhJYNKxfyYaZbqT6NN8W4pXu0zOUvpunrDPdtC0I6OZPzq0B5RRI1Ybub00OcYvj28K
|
||||
STRIPE_WEBHOOK_SECRET=whsec_c5e0a6b2dd5e2f6ac804b428fe46f04e3af9b55c562f4124de20c52866f3c211
|
||||
STRIPE_API_KEY=placeholder
|
||||
STRIPE_WEBHOOK_SECRET=placeholder
|
||||
# Email — Resend (primary) with SMTP fallback
|
||||
# Get your API key at https://resend.com/api-keys
|
||||
RESEND_API_KEY=re_PLACEHOLDER
|
||||
@@ -48,7 +48,7 @@ MAIL_HOST=smtp.gmail.com
|
||||
MAIL_PORT=587
|
||||
MAIL_SCHEME=smtp
|
||||
MAIL_USERNAME=rentaldrivego@gmail.com
|
||||
MAIL_PASSWORD=kfahihfzbcvkczew
|
||||
MAIL_PASSWORD=placeholder
|
||||
MAIL_FROM_ADDRESS=rentaldrivego@gmail.com
|
||||
MAIL_FROM_NAME=RentalDriveGo
|
||||
MAIL_REPLY_TO_ADDRESS=rentaldrivego@gmail.com
|
||||
|
||||
@@ -80,7 +80,7 @@ MAIL_HOST=smtp.gmail.com
|
||||
MAIL_PORT=587
|
||||
MAIL_SCHEME=smtp
|
||||
MAIL_USERNAME=rentaldrivego@gmail.com
|
||||
MAIL_PASSWORD=kfahihfzbcvkczew
|
||||
MAIL_PASSWORD=placeholder
|
||||
MAIL_FROM_ADDRESS=rentaldrivego@gmail.com
|
||||
MAIL_FROM_NAME=RentalDriveGo
|
||||
MAIL_REPLY_TO_ADDRESS=rentaldrivego@gmail.com
|
||||
@@ -89,8 +89,8 @@ MAIL_REPLY_TO_NAME=RentalDriveGo
|
||||
# Stripe subscription checkout
|
||||
# STRIPE_API_KEY must be a Stripe secret/restricted key (sk_ or rk_).
|
||||
# STRIPE_WEBHOOK_SECRET must be a Stripe webhook signing secret (whsec_).
|
||||
STRIPE_API_KEY=sk_test_51TvTsb9SpDRZn9yJyBAlUSXcTp9zpwQfhJYNKxfyYaZbqT6NN8W4pXu0zOUvpunrDPdtC0I6OZPzq0B5RRI1Ybub00OcYvj28K
|
||||
STRIPE_WEBHOOK_SECRET=whsec_c5e0a6b2dd5e2f6ac804b428fe46f04e3af9b55c562f4124de20c52866f3c211
|
||||
STRIPE_API_KEY=placeholder
|
||||
STRIPE_WEBHOOK_SECRET=placeholder
|
||||
|
||||
# ── Firebase push notifications (optional) ────────────────────────────────────
|
||||
# FIREBASE_PROJECT_ID=your-firebase-project-id
|
||||
|
||||
@@ -49,6 +49,11 @@ PAYPAL_BASE_URL=https://api-m.paypal.com
|
||||
# Use https://api-m.sandbox.paypal.com for sandbox
|
||||
NEXT_PUBLIC_PAYPAL_CLIENT_ID=your-paypal-client-id
|
||||
|
||||
# ─── Stripe (subscription checkout) ────────────────────────────
|
||||
# Prefer a restricted API key (rk_) with the minimum Billing/Checkout permissions.
|
||||
STRIPE_API_KEY=placeholder
|
||||
STRIPE_WEBHOOK_SECRET=placeholder
|
||||
|
||||
# ─── Cloudinary (Vehicle + brand photos) ──────────────────────
|
||||
CLOUDINARY_CLOUD_NAME=your-cloud-name
|
||||
CLOUDINARY_API_KEY=your-api-key
|
||||
|
||||
@@ -199,7 +199,7 @@ describe('menu.service', () => {
|
||||
expect(result.items.find((item) => item.label === 'Reports')?.reasons.join(' ')).toContain('STARTER does not include this menu item')
|
||||
})
|
||||
|
||||
it('returns the approved seven-item STARTER owner sidebar in order', async () => {
|
||||
it('returns the approved STARTER owner sidebar in order', async () => {
|
||||
vi.mocked(prisma.employee.findUniqueOrThrow).mockResolvedValue({
|
||||
id: 'employee_1',
|
||||
role: 'OWNER',
|
||||
@@ -367,6 +367,7 @@ describe('menu.service', () => {
|
||||
expect(result.items.map((menuItem) => menuItem.systemKey)).toEqual([
|
||||
'dashboard',
|
||||
'reservations',
|
||||
'contracts',
|
||||
'fleet',
|
||||
'customers',
|
||||
'reports',
|
||||
|
||||
@@ -73,11 +73,12 @@ const ROLE_RANK: Record<EmployeeRole, number> = { OWNER: 3, MANAGER: 2, AGENT: 1
|
||||
const BASELINE_EMPLOYEE_MENU_ITEMS = [
|
||||
{ systemKey: 'dashboard', label: 'Dashboard', routeOrUrl: '/', icon: 'LayoutDashboard', displayOrder: 10, minRole: 'AGENT' },
|
||||
{ systemKey: 'reservations', label: 'Reservations', routeOrUrl: '/reservations', icon: 'Calendar', displayOrder: 20, minRole: 'AGENT' },
|
||||
{ systemKey: 'fleet', label: 'Fleet', routeOrUrl: '/fleet', icon: 'Car', displayOrder: 30, minRole: 'AGENT' },
|
||||
{ systemKey: 'customers', label: 'Customers', routeOrUrl: '/customers', icon: 'Users', displayOrder: 40, minRole: 'AGENT' },
|
||||
{ systemKey: 'reports', label: 'Reports', routeOrUrl: '/reports', icon: 'BarChart2', displayOrder: 50, minRole: 'MANAGER' },
|
||||
{ systemKey: 'billing', label: 'Billing', routeOrUrl: '/billing', icon: 'CreditCard', displayOrder: 60, minRole: 'MANAGER' },
|
||||
{ systemKey: 'settings', label: 'Settings', routeOrUrl: '/settings', icon: 'Settings', displayOrder: 70, minRole: 'OWNER' },
|
||||
{ systemKey: 'contracts', label: 'Contracts', routeOrUrl: '/contracts', icon: 'FileText', displayOrder: 30, minRole: 'AGENT' },
|
||||
{ systemKey: 'fleet', label: 'Fleet', routeOrUrl: '/fleet', icon: 'Car', displayOrder: 40, minRole: 'AGENT' },
|
||||
{ systemKey: 'customers', label: 'Customers', routeOrUrl: '/customers', icon: 'Users', displayOrder: 50, minRole: 'AGENT' },
|
||||
{ systemKey: 'reports', label: 'Reports', routeOrUrl: '/reports', icon: 'BarChart2', displayOrder: 60, minRole: 'MANAGER' },
|
||||
{ systemKey: 'billing', label: 'Billing', routeOrUrl: '/billing', icon: 'CreditCard', displayOrder: 70, minRole: 'MANAGER' },
|
||||
{ systemKey: 'settings', label: 'Settings', routeOrUrl: '/settings', icon: 'Settings', displayOrder: 80, minRole: 'OWNER' },
|
||||
] as const
|
||||
const MENU_RECOVERY_ROUTES = new Set(['/subscription', '/subscription/success', '/subscription/cancel'])
|
||||
|
||||
|
||||
@@ -84,3 +84,8 @@ MAIL_FROM_ADDRESS=rentaldrivego@gmail.com
|
||||
MAIL_FROM_NAME=RentalDriveGo
|
||||
MAIL_REPLY_TO_ADDRESS=rentaldrivego@gmail.com
|
||||
MAIL_REPLY_TO_NAME=RentalDriveGo
|
||||
|
||||
# Stripe subscription checkout
|
||||
# Prefer a restricted API key (rk_) with the minimum Billing/Checkout permissions.
|
||||
STRIPE_API_KEY=placeholder
|
||||
STRIPE_WEBHOOK_SECRET=placeholder
|
||||
|
||||
@@ -187,7 +187,7 @@ EOF
|
||||
}
|
||||
|
||||
validate_prod_env_file() {
|
||||
local acme_email api_domain public_site_domain cors_origins postgres_password redis_password jwt_secret
|
||||
local acme_email api_domain public_site_domain cors_origins postgres_password redis_password jwt_secret stripe_api_key stripe_webhook_secret
|
||||
|
||||
acme_email="$(read_env_value ACME_EMAIL)"
|
||||
api_domain="$(read_env_value API_DOMAIN)"
|
||||
@@ -196,6 +196,8 @@ validate_prod_env_file() {
|
||||
postgres_password="$(read_env_value POSTGRES_PASSWORD)"
|
||||
redis_password="$(read_env_value REDIS_PASSWORD)"
|
||||
jwt_secret="$(read_env_value JWT_SECRET)"
|
||||
stripe_api_key="$(read_env_value STRIPE_API_KEY)"
|
||||
stripe_webhook_secret="$(read_env_value STRIPE_WEBHOOK_SECRET)"
|
||||
|
||||
if [[ -z "${acme_email}" || "${acme_email}" != *@* || "${acme_email}" == *example.com* ]]; then
|
||||
echo "Invalid ACME_EMAIL in ${ENV_FILE}. Set ACME_EMAIL=${DEFAULT_ACME_EMAIL} for Let's Encrypt." >&2
|
||||
@@ -226,6 +228,25 @@ validate_prod_env_file() {
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -z "${stripe_api_key}" || "${stripe_api_key}" == placeholder || "${stripe_api_key}" == replace-with-* || "${stripe_api_key}" == *changeme* || "${stripe_api_key}" == *change-me* ]]; then
|
||||
echo "Invalid STRIPE_API_KEY in ${ENV_FILE}. Set a real Stripe secret or restricted API key for production billing." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${stripe_api_key}" != sk_* && "${stripe_api_key}" != rk_* ]]; then
|
||||
echo "Invalid STRIPE_API_KEY in ${ENV_FILE}. It must start with sk_ or rk_." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${stripe_webhook_secret}" || "${stripe_webhook_secret}" == placeholder || "${stripe_webhook_secret}" == replace-with-* || "${stripe_webhook_secret}" == *changeme* || "${stripe_webhook_secret}" == *change-me* ]]; then
|
||||
echo "Invalid STRIPE_WEBHOOK_SECRET in ${ENV_FILE}. Set the Stripe webhook signing secret for /api/v1/subscriptions/webhooks/stripe." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${stripe_webhook_secret}" != whsec_* ]]; then
|
||||
echo "Invalid STRIPE_WEBHOOK_SECRET in ${ENV_FILE}. It must start with whsec_." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -181,7 +181,7 @@ EOF
|
||||
}
|
||||
|
||||
validate_prod_env_file() {
|
||||
local acme_email api_domain public_site_domain cors_origins portainer_domain postgres_password redis_password jwt_secret
|
||||
local acme_email api_domain public_site_domain cors_origins portainer_domain postgres_password redis_password jwt_secret stripe_api_key stripe_webhook_secret
|
||||
|
||||
acme_email="$(read_env_value ACME_EMAIL)"
|
||||
api_domain="$(read_env_value API_DOMAIN)"
|
||||
@@ -191,6 +191,8 @@ validate_prod_env_file() {
|
||||
postgres_password="$(read_env_value POSTGRES_PASSWORD)"
|
||||
redis_password="$(read_env_value REDIS_PASSWORD)"
|
||||
jwt_secret="$(read_env_value JWT_SECRET)"
|
||||
stripe_api_key="$(read_env_value STRIPE_API_KEY)"
|
||||
stripe_webhook_secret="$(read_env_value STRIPE_WEBHOOK_SECRET)"
|
||||
|
||||
if [[ -z "${acme_email}" || "${acme_email}" != *@* || "${acme_email}" == *example.com* ]]; then
|
||||
echo "Invalid ACME_EMAIL in ${ENV_FILE}. Set it to a real contact email for Let's Encrypt, not example.com." >&2
|
||||
@@ -221,6 +223,25 @@ validate_prod_env_file() {
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -z "${stripe_api_key}" || "${stripe_api_key}" == placeholder || "${stripe_api_key}" == replace-with-* || "${stripe_api_key}" == *changeme* || "${stripe_api_key}" == *change-me* ]]; then
|
||||
echo "Invalid STRIPE_API_KEY in ${ENV_FILE}. Set a real Stripe secret or restricted API key for production billing." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${stripe_api_key}" != sk_* && "${stripe_api_key}" != rk_* ]]; then
|
||||
echo "Invalid STRIPE_API_KEY in ${ENV_FILE}. It must start with sk_ or rk_." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${stripe_webhook_secret}" || "${stripe_webhook_secret}" == placeholder || "${stripe_webhook_secret}" == replace-with-* || "${stripe_webhook_secret}" == *changeme* || "${stripe_webhook_secret}" == *change-me* ]]; then
|
||||
echo "Invalid STRIPE_WEBHOOK_SECRET in ${ENV_FILE}. Set the Stripe webhook signing secret for /api/v1/subscriptions/webhooks/stripe." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "${stripe_webhook_secret}" != whsec_* ]]; then
|
||||
echo "Invalid STRIPE_WEBHOOK_SECRET in ${ENV_FILE}. It must start with whsec_." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n "${portainer_domain}" && "${portainer_domain}" == *example.com* ]]; then
|
||||
echo "Invalid PORTAINER_DOMAIN in ${ENV_FILE}. Set a real hostname or disable the portainer router." >&2
|
||||
|
||||
Reference in New Issue
Block a user