Admins can create coupon codes that discount specific services (app
runtimes, optional services, managed products, custom-domain addon, or
all) and restrict them to specific users or make them public, with total
and per-user usage caps and an active date window.
Coupons apply in deploy, renewal, and upgrade flows: cost-breakdown lines
are tagged with a service key, the eligible portion is discounted and
capped to the payable amount, the invoice records discountAmount/
discountCode, and the redemption is recorded once when the invoice is
fully paid (covering wallet, gateway, and mixed payments).
- Discount + DiscountRedemption entities; invoice discount columns
- DiscountService (CRUD, validation, redemption) + admin/validate API
- Idempotent schema bootstrap on init so production (synchronize off)
provisions the tables/columns without a migration runner
- Admin discounts UI, coupon entry in deploy/renewal, invoice discount line
- fa/en strings; discount.service unit spec
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The payment method was rendered as the raw enum ("wallet") in the PDF and in the
invoice detail/list views. Map it through the existing methodWallet/methodGateway/
methodMixed dictionary keys everywhere.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Invoice PDF now shows the customer's full name and a phone row (sourced from
the auth store for the user page, invoice.user for admin) instead of just email.
- Left-align all meta values into a single clean column (unicode-bidi:plaintext
so Persian names stay RTL while phone/dates read LTR).
- Move the totals box to the left side of the page.
- Rasterize as JPEG (q0.9) instead of PNG to keep the file small (~130KB).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Render the prepaid resource credit "remaining" and "expires" text in
Persian with Jalali calendar when locale is fa: localized digits and
day/hour/minute units for time left, and weekday + Jalali date + time
for the expiry. Parts are assembled explicitly so order is stable
regardless of the runtime's ICU pattern data.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Translate persisted English invoice line labels/descriptions/reasons to
Persian at display time (new lib/invoice-labels.ts), covering both new and
historical invoices without a data migration.
- Generate a styled, RTL Persian invoice PDF on the client (lib/invoice-pdf.ts)
with the Abrban logo, line-item table and totals, via html2canvas + jsPDF.
- Wire both the user and admin invoice pages to the translator and new download.
- Add invoices.pdf dictionary keys (fa/en).
- Remove the now-dead ASCII-only backend PDF endpoints and generateInvoicePdf.
- Add frontend/.npmrc (npmmirror registry + high timeouts) for Iran-network installs.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the admin-only "cluster assignment" UI from the resources &
config step of the deploy wizard and the related backend override.
App placement is now always decided automatically by the allocator.
- frontend: remove cluster/pool selection block, review-step cluster
row, clusterMode state, public cluster/pool queries, and clusterId/
poolId from CreateApplicationDto
- backend: drop clusterId/poolId override from the create DTO and
simplify ApplicationsService.create to always auto-allocate; widen
selectClusterForApplication param to keep the fallback path working
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
JwtStrategy read `role` straight from the JWT payload, so a role change
or deactivation stayed ineffective until the 1h access token expired:
after a promotion the menus showed (via /users/me) but admin endpoints
returned 403 because RolesGuard still saw the old token role; after a
demotion the old admin kept API access. Load the user from the DB in
validate() and use the current role; reject inactive users.
Frontend: poll /users/me in the dashboard layout (+ on window focus) so
the sidebar reflects role changes without a hard reload, and redirect
away from pages the new role can no longer reach.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Surface the domain the app is actually reachable on right now (verified
custom domain, else the platform subdomain) as a single "Application
Domain" field. Clicking it copies the address to the clipboard and shows
a "Copied" toast. Centralizes the active-domain logic so the page header
and the verified-custom-domain block stay in sync, and always loads
domain-info so the platform host is correct even without a custom domain.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make .table-wrapper overflow-x-auto so wide rows (long name + email)
stay reachable — the actions column (deactivate/reset password) was
clipped before. Render the Select option list in a body-level portal
with fixed positioning so it is never clipped by the scroll container.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Let super admins act as a user from the user detail dashboard for
support/debugging ("full with guardrails", audit-only).
Backend: AuthService.impersonate issues a short-lived token for the
target carrying an `act` claim (acting admin); refresh preserves it and
JwtStrategy surfaces `impersonatedBy`. Guardrails: cannot impersonate an
admin or a deactivated account; new ImpersonationGuard blocks sensitive
self-service (change own password/phone) while impersonating. New
AuditLog entity records impersonation start/stop (admin, target, ip,
time); admin endpoints POST users/:id/impersonate + .../impersonation/
stop and GET users/:id/audit.
Frontend: lib/impersonation swaps admin/impersonation tokens in
localStorage; persistent banner with exit; "Login as user" button and an
"Admin access log" tab on the detail page; logout clears impersonation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a read-only User Detail dashboard for super admins, reachable by
clicking a user name in the admin users list.
Backend: new `admin` module aggregating existing domain services
(no new entities). ADMIN-only endpoints under /api/v1/admin:
overview (profile, account status, wallet balance, revenue, summary
counts), wallet transactions, applications (incl. deleted/docked with
restore eligibility), build/deploy errors, tickets with conversation,
and a composite activity timeline. Adds BillingService.getRevenueSummary
and guards against a wallet get-or-create race in the overview reads.
Frontend: tabbed detail page (overview/applications/activity/errors/
tickets) with lazy per-tab queries; user names in the admin list link to
it (admin only); fa/en i18n keys and response types.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Admin user management now creates accounts with a required mobile
number and an optional contact email, matching mobile-only auth.
Admin-created accounts are pre-verified (phoneVerified) so the user
can sign in by password immediately. The user list and search now
include phone.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Register and login by mobile number; email is now an optional
contact field only (never used to authenticate)
- After registration, the phone is verified via a 6-digit SMS code
- Login supports both password and one-time-code (OTP) methods
- Phone OTP delivered via Kavenegar (verify/lookup); API key in env
- Account page: edit name/optional email, change password, and
change mobile number with OTP re-verification
- Codes are hashed, expire in 5m, capped at 5 attempts, rate-limited
- Seed gives the admin a verified phone so mobile login still works
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Let users size the database workload from the deploy wizard the same way
Redis/RabbitMQ are configured: a resource card (CPU request/limit, memory
request/limit, storage) on the Resources step, stored in
optionalServiceResources.database.
- entity/DTO: add `database` to optionalServiceResources
- k8s: resolveDatabaseResources() applies user-selected resources on both
the Helm and K8s-API deploy paths (was hardcoded 100m/256Mi→500m/512Mi)
- billing: bill database CPU/RAM as a separate line on top of the app's
resources; merge it through the upgrade path too
- wizard: db resource card on the Resources step, disk moved into the card,
cost preview + review summary include the database resources
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The login/register backdrop (fluffy white cloud blobs + sun glow) read
as cheap. Replace it with a calmer, more premium take that stays in the
landing's blue/glass language: a deep brand gradient, a faint
infrastructure grid masked toward the edges, soft brand-blue glows and a
vignette. Remove the icon chip above the title on both pages.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the default react-toastify look with project-styled toast cards
(icon chip, rounded shell, RTL-aware container, type-colored progress
bar) via a new notify helper and globals.css overrides.
Add a central error layer (src/lib/errors.ts): classify any caught error
by HTTP status / network condition, log the full technical detail
(including the raw backend message) to the console only, and surface a
friendly, localized message to the user. Raw backend messages are no
longer shown. All ~190 toast call sites across 22 files move to notify,
routing backend errors through notify.error(err, fallback); dead
apiErrorMessage/formatApiError helpers removed. Adds an `errors` section
to the fa/en dictionaries.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace every native <select> across the dashboard, admin pages, and
shared components with the custom Select used by the optional-service
version pickers, for consistent styling and mobile-safe anchoring. Add
a disabled prop to Select to cover the former read-only native cases.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Form controls smaller than 16px made iOS Safari auto-zoom on focus,
shifting page content upward. Enforce a 16px minimum font-size on
inputs/selects/textareas at mobile widths. Also replace the three tiny,
inconsistently-styled (colored-border, text-xs) version pickers in the
deploy wizard's optional-services cards with a shared .select-compact
style so they match the rest of the form.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The mobile drawer rendered the nav at full height below a fixed header,
so lower items (and the admin section) overflowed off-screen with no way
to scroll. Lay the drawer out as a flex column with a fixed header, a
scrollable nav area (min-h-0 + overflow-y-auto) and a pinned user footer.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the final dashboard page (admin all-apps) onto a
dashboard.adminApps dictionary: status-count cards, search, table/cards,
lifecycle & migration statuses, plan/expiry, and the migrate modal —
completing full fa-IR/en-US coverage across the entire app.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the multi-step deploy wizard (app type/runtime, source, versions &
database, optional services, resources & cluster assignment, custom
domain + DNS, env vars, cost/payment, review and the provisioning
overlay) onto a dashboard.deployWizard dictionary, with localized runtime
descriptions, billing cycles, stage labels and RTL-aware controls.
This completes full fa-IR/en-US localization of the dashboard.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the largest dashboard page (app detail) onto a dashboard.appDetail
dictionary: header actions, status/lifecycle banners, configuration,
deployment history, source upload, custom-domain + DNS guide, resources
& scaling, storage, rollback/snapshots, DB restore, service credentials,
renewal and upgrade modals — with localized statuses, locale-aware dates
and RTL-aware layout.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the service detail view (header actions, renewal banner, config,
deployment history, DB/Redis/RabbitMQ connection panels, renew modal)
onto a dashboard.serviceDetail dictionary with localized product-type and
deploy-status labels, locale-aware dates and RTL-aware layout.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add components.dbConfig / components.snapshots and dashboard.servicesNew
dictionaries; move the managed-database config (engine, credentials, dump
upload, storage), the snapshots panel and the three-step new-service
wizard onto them. validateDbDumpStorage now takes a localized template.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the cluster management page (resource panel, tools install/uninstall
flow, statuses/health) and the billing-plans page (pricing matrices,
deploy defaults, add-ons, data-retention settings) onto the dictionaries
with locale-aware dates and RTL-aware tables.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a components dictionary (delete/deleting overlays, confirm-modal
defaults, build-progress phases, deployment bar, resource-upgrade modal)
and move the logs, admin users, and admin cluster-pools pages onto the
dictionaries — filters, tables, forms, statuses, toasts and confirm
dialogs — with locale-aware dates and RTL-aware layout.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Localize the confirm modal, delete button, deleting overlays/modal, the
build-progress modal, deployment progress bar/manager and the resource
upgrade modal via a shared components dictionary. Build-phase labels now
resolve from the dictionary; deleting overlays take name/kind and build
their own localized message (callers updated).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move both invoice views onto a shared invoices dictionary — statuses,
filters, payment/line-item/transaction labels, manual status controls and
toasts — with locale-aware Link, dates and RTL-aware table/search layout.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the wallet page and all four ticket views (user list, ticket detail,
staff queue, admin overview) onto the i18n dictionaries — statuses,
priorities, departments, forms, stats, toasts and empty states — using
locale-aware Link/router and locale-aware date formatting.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Move the apps and managed-services list pages onto the i18n dictionaries
(titles, table headers, lifecycle/expiry labels, delete confirmations,
toast messages) and the locale-aware Link, reusing the shared status and
lifecycle/expiry copy. Add RTL-aware table alignment and icon spacing.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Convert the dashboard layout (sidebar nav, header, role badges, wallet,
sign-out, language switcher) and the dashboard home page to the i18n
dictionaries, including a shared deployment-status label map. Switch their
links/router to the locale-aware helpers and add RTL-aware spacing.
Remaining dashboard page bodies and shared components still render English
copy and will be localized in follow-up commits.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce path-prefixed locale routing under app/[lang] with a middleware
that detects locale from cookie/Accept-Language (default fa-IR) and
redirects. Add fa-IR (source of truth) and en-US dictionaries, a server
getDictionary, a client I18nProvider/useT, locale-aware Link + router
helpers, and a language switcher. The root [lang] layout sets html
lang/dir and the per-locale font (Peyda for fa, Inter for en).
Landing sections and the login/register/auth shell now read all copy from
the dictionaries; dashboard localization follows in a later commit.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Vendor the Peyda woff weights (Thin–Black) under public/fonts/peyda and
load them via next/font/local in a shared fonts module, exposed through
the --font-peyda CSS variable and the font-peyda Tailwind utility. Drops
the runtime Google Fonts fetch on the landing and auth pages.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wrap both auth pages in a shared cinematic sky shell (calm blue sky, drifting
clouds, sun glow, frosted dark-glass panel) in Persian/RTL with the Abrban
brand, while leaving the existing auth store logic and dashboard routing intact.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Replace the root redirect with a scroll-driven three.js scene that flies from
overcast clouds through rain and a thunderstorm into a clear blue sunny sky,
fronted by Persian/RTL marketing sections. The dashboard at /dashboard is
untouched.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Introduce a catalog-driven Tools Management section under Clusters so
admins can install/uninstall infrastructure tools per cluster: cert-manager
(Helm/jetstack), ClusterIssuer (email + HTTP01 form, depends on cert-manager),
and central Elasticsearch. Cluster creation no longer auto-installs Elastic
or the cloudhost-node-cluster-dns DaemonSet; build bootstrap stays automatic.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Build hosts as <userPrefix>-<deploymentNumber>-preview.<rootDomain> from FRONTEND_URL, wire them through ingress/TLS, and open them from the preview API.
Co-authored-by: Cursor <cursoragent@cursor.com>
Auto port-forward using the registered cluster kubeconfig, default to loopback outside Kubernetes, route log APIs by app cluster, and document platform env settings.
Co-authored-by: Cursor <cursoragent@cursor.com>
Assign unpredictable subdomains on create when no custom domain is set, and update deploy UI CNAME hints to reference the app Platform Domain after creation.
Co-authored-by: Cursor <cursoragent@cursor.com>
Remove external registry Ingress (repo.3fase.ir) and route Kaniko push and app pulls through the internal ClusterIP registry. Add RegistryService, ensure StorageClass and pull secrets on deploy, make Elasticsearch install/repair more resilient, and add per-cluster Deploy Elastic controls in admin UI.
Co-authored-by: Cursor <cursoragent@cursor.com>
Track in-progress deploys in the client store so the progress modal opens on click without waiting for the applications list refetch. Show deleting state as a blurred glass overlay on table rows and service cards instead of replacing row content.
Co-authored-by: Cursor <cursoragent@cursor.com>
Auto-reconnect Elasticsearch port-forward after cluster or API restarts, poll log status in the UI, and apply storage changes through billing upgrade for all workloads. Add Redis/RabbitMQ PVC resize, Helm ES credentials for Fluent Bit, and fix deploy progress overlay behavior.
Co-authored-by: Cursor <cursoragent@cursor.com>
Show minutes and local expiry for resource credits; add shared delete hook with row/card loading overlays, detail-page deleting modal, and disabled controls to prevent double-delete.
Co-authored-by: Cursor <cursoragent@cursor.com>
Introduce product types for managed PostgreSQL, Redis, and RabbitMQ with a dedicated dashboard, Helm-only deploy pipeline, external access, snapshots with progress, and prorated resource or storage upgrades matching application billing rules. PVCs use an expandable StorageClass with automatic migration when legacy disks cannot resize in place.
Co-authored-by: Cursor <cursoragent@cursor.com>
Deployments can continue in the background via a dashboard progress bar; tables use truncation and admin migration status for cleaner layout.
Co-authored-by: Cursor <cursoragent@cursor.com>