138 Commits

Author SHA1 Message Date
keyhan 22359be40e fix(platform): apply production hardening from audit plan
Close billing, tenancy, migration, build, and CI/CD gaps identified in the
audit: wallet/gateway guards, full-UUID namespaces, idempotent migrations with
base schema, stateful service stability, safer Dockerfiles/git builds, and
platform chart hardening (Redis auth, RollingUpdate, backups, Swagger off).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 19:35:07 +03:30
keyhan 6ba77eebcf ci: pull node base image from Harbor instead of docker.io
Build and Deploy Platform / build-and-deploy (push) Failing after 47s
Kaniko builds failed with context deadline exceeded pulling node:24-alpine
from index.docker.io through the egress proxy. Seed node:24-alpine into
abrban/ and pass BASE_IMAGE build-arg so builds use the internal registry.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 18:32:41 +03:30
keyhan 5ed2ef0958 Add GitOps stack for abrban.com with Gitea Actions CI/CD.
Build and Deploy Platform / build-push-deploy (push) Has been cancelled
Harbor in-cluster builds via Kaniko, ArgoCD auto-sync, and production Helm values for abrban.com domains.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 01:27:20 +03:30
keyhan 8d1855b89c Detect and validate app runtime from uploaded archives.
Reject zip uploads when the selected runtime does not match archive contents, and re-validate before Kaniko builds to fail fast instead of producing the wrong Dockerfile.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-30 00:27:03 +03:30
keyhan 837f0fa63f Harden platform security, reliability, and CI after full audit.
Close deployment IDOR and gate stub payment endpoints, add production
secret validation, health probes, Redis-backed build progress, GitHub
Actions CI, expanded tests, billing/k8s refactors, and ops runbooks.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 20:59:49 +03:30
keyhan 9c16b462f4 revert(build): remove app build pipeline revamp (Nixpacks/MinIO/Trivy/registry GC)
Reverts commits 3eff38f and c379a23 and restores the previous Kaniko-only
build pipeline (runtime detection + per-runtime Dockerfile generation,
disk-based source upload).

Removed: Nixpacks Dockerfile generation, MinIO source storage (common/storage),
Bull build queue + Redis build state (common/redis, deployment.processor),
Trivy image scan (scan.service, deployment.vulnerabilitySummary), and daily
registry garbage collection (registry-gc). Nothing outside the build/deploy
path depended on these. Backend tsc + 105/106 tests green (the pre-existing
helm.service chartPath failure is unrelated); frontend tsc green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 19:21:30 +03:30
keyhan bd14eb2daa feat(blog): real bilingual blog with covers, list & article pages
- Add blog content module (posts.ts): 4 platform-focused articles (deploy,
  managed databases, custom domain + SSL, replicas & cost) in fa/en with
  tag, date, reading time, excerpt and structured body.
- Self-contained gradient cover art (BlogCover) — no external images, themed
  per topic with the brand cloud motif.
- Landing blog section now shows the 3 latest posts with covers, linking to
  article pages; "view all" links to /blog.
- Dedicated /blog list page and /blog/[slug] article page over the shared
  cloud-sky shell (BlogShell), with a not-found state.
- Remove the now-redundant "Learn" header nav item (blog covers getting
  started) and drop its orphan section anchor.
- i18n: blog minRead/notFound/backToBlog strings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 13:35:02 +03:30
keyhan f89c3de826 feat(landing): glass header nav with side drawer + blog section
- Header: full glassmorphism navigation (services, pricing, estimator, learn,
  blog). Desktop shows an inline glass pill; mobile opens a side drawer that
  slides in from the inline-start edge (right in RTL, left in LTR) over a
  blurred backdrop.
- Nav links smooth-scroll via the shared Lenis instance (exposed through
  scroll-store: setLenis/scrollToId), with an 80px offset under the header.
- "Learn" links to the existing how-it-works steps (id="learn"); add a
  lightweight Blog teaser section (id="blog", "coming soon" cards).
- i18n: fa/en strings for nav and blog.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 11:36:27 +03:30
keyhan 985a23751e fix(landing): merge the final scene's two suns into one
The closing sky drew two suns: the 3D sun mesh (corona + GodRays) at a
fixed world point, and a disc/halo painted by the sky shader aimed at a
fixed direction. As the camera flew forward, parallax split them apart —
the mesh rode high while the painted halo stayed low.

Aim the sky shader's uSunDir at the real camera→sun direction each frame
so the halo locks onto the mesh (one sun), and lower SUN_POS.y 34→13 so
that single sun sits at the lower, near-horizon spot.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 00:48:49 +03:30
keyhan f7974dd382 feat(landing,billing): public pricing, global discount, services bar & estimator
Backend
- Add platform-wide global discount (platform_settings: global_discount_percent),
  applied centrally in PricingCatalogService.computeTotalsFromDb so it reaches
  every real charge (previews, deploys, renewals, upgrades, invoices). Admin
  GET/PATCH /billing/settings/global-discount.
- Add unauthenticated PublicPricingController (catalog + calculate) for the
  public landing page, returning gross/net and the discount percentage.
- Bill application replicas by the user-selected footprint: app CPU/RAM/storage
  now all scale by replica count; the single-replica database stays unscaled.

Frontend
- Landing: Services bar (PaaS active, DBaaS, KaaS/LaaS "coming soon" with
  expandable runtime/database menus), transparent Pricing section (per-resource
  rate cards with cycle toggle + discount strikethrough), and a cost Estimator
  ("estimate your package").
- Optional services and the database are priced like runtimes: the estimator
  lets users pick their CPU/RAM/storage (and DB type) so the cost scales by need.
- Admin billing: global-discount editor.
- i18n: fa/en strings for services, pricing, estimator and global discount.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 23:44:30 +03:30
keyhan a58142cc4a feat(auth): glassmorphism card + clearer register CTA
Give the login/register card a proper glassmorphism look (new .auth-glass:
more transparent so the clouds blur through, bright glassy edge, soft layered
shadow) while keeping a slate tint so the white form text stays legible.

Make the "no account? register" CTA stand out over the bright sky: a dark
frosted glass pill with an arrow, and dark slate prompt text with a soft white
halo instead of the washed-out white.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 18:32:21 +03:30
keyhan 7275c29460 feat(auth): bring the landing's cloud sky into login/register
Replace AuthShell's deep-blue grid backdrop with AuthSky — the same bright
pale-blue gradient (weather stop 0) and the same vendored cloud puff
(/cloud.png) as the landing, as lightweight drifting CSS sprites so no
three.js lands on the auth routes. The form keeps the shared frosted-glass
panel, so login/register now read as one world with the public landing.
Cloud drift respects prefers-reduced-motion.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 18:32:21 +03:30
keyhan 3eff38f8d2 feat(build): revamp app build pipeline (queue, Nixpacks, MinIO, Trivy, registry GC)
Rework the application build/deploy pipeline for scalability, reproducibility,
and security:

- Build queue: deploys run through a bounded-concurrency Bull queue
  (BUILD_CONCURRENCY, default 3) so concurrent user deploys can't flood the
  cluster with Kaniko jobs. Build state (progress / cancel / session) moves from
  in-memory Maps to Redis, so cancel + live logs work across backend replicas.
- Nixpacks + BYO Dockerfile: code runtimes build via Nixpacks (or the user's own
  Dockerfile when present); the hand-written per-runtime Dockerfile generators
  and runtime auto-detection are removed. WordPress keeps its templated path.
  Build-time mirror env (NIXPACKS_BUILD_ENV) supports the Iran network.
- Source upload to MinIO: archives stream to in-cluster MinIO; build pods pull
  via a presigned URL. Removes the PVC + helper pod + kubectl cp upload path.
- Report-only Trivy scan after build; per-severity summary stored on the
  deployment and shown as a badge in the dashboard. Never gates a deploy.
- Registry GC: a Redis-locked daily job keeps the newest N image tags per app
  (REGISTRY_KEEP_VERSIONS, default 3) and reclaims disk via garbage-collect.
- Hardening: git tokens are delivered via a per-build Secret + git credential
  store instead of being embedded in the clone URL / Job manifest; build timeout
  is configurable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 22:58:58 +03:30
keyhan 49726f1dfd feat(billing): add percentage discount coupons
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>
2026-06-20 11:48:45 +03:30
keyhan b232129ee2 fix(invoices): localize payment method (wallet/gateway/mixed) to Persian
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>
2026-06-20 00:51:23 +03:30
keyhan 7438b44120 feat(invoices): show customer name/phone, align meta column, totals left, JPEG
- 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>
2026-06-20 00:41:17 +03:30
keyhan bc224a2291 fix(dashboard): Persian Jalali formatting for resource credit dates
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>
2026-06-20 00:15:43 +03:30
keyhan 49f1ab07bd fix(invoices): render invoice PDF with html-to-image for correct Persian
html2canvas re-implements text layout and mangled Persian RTL output (joined
words, broken spacing, reordered emails). Switch the rasterizer to html-to-image,
which renders through an SVG foreignObject using the browser's native text
engine, so Persian shaping/spacing/bidi and oklch() colors all come out right.
Peyda is embedded as base64 @font-face via fontEmbedCSS so html-to-image skips
its slow document-wide font scan. Drop the now-unused html2canvas dependency.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 21:08:14 +03:30
keyhan 1529bf0d46 fix(invoices): render PDF in isolated iframe to avoid oklch crash
html2canvas 1.x cannot parse Tailwind v4's oklch() colors, so generating the
invoice PDF from the live document threw and the download silently failed.
Render the invoice template inside a sandboxed iframe that loads only the Peyda
@font-face and no app stylesheets, so the captured tree is free of oklch.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 20:10:10 +03:30
keyhan 4d64fda227 feat(invoices): Persian line items + elegant client-side PDF download
- 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>
2026-06-19 19:59:22 +03:30
keyhan 78ed95b29b feat(landing): restructure footer with enamad seal, contact info, and logo
- Remove login/register/dashboard nav links from the footer
- Add Enamad trust seal on the left
- Center the contact block (title, phone, email) in the middle
- Move the logo to the right side
- Place the copyright line at the bottom, centered
- Update copyright text and add contact strings (fa/en)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 19:55:37 +03:30
keyhan dbc169206f feat(deploy): remove cluster allocation section from app creation
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>
2026-06-19 11:58:30 +03:30
keyhan 8dc351ab21 fix(auth): enforce live role + active status from DB on every request
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>
2026-06-18 18:55:24 +03:30
keyhan 04b2f040e0 feat(frontend): show active app domain with click-to-copy
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>
2026-06-18 14:31:45 +03:30
keyhan a3a7e17cca fix(frontend): horizontal-scroll table wrapper + portal Select dropdown
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>
2026-06-18 13:29:08 +03:30
keyhan 585fdbc9b7 fix(frontend): always default first-time visitors to Persian
Drop Accept-Language detection from the locale middleware. A first
visit (no NEXT_LOCALE cookie) now always serves the default locale
(fa-IR) instead of guessing from the browser. The user's last explicit
choice, persisted in the cookie by the language switcher, remains the
sole signal on subsequent visits.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 13:27:29 +03:30
keyhan bb6049a067 fix(frontend): make wallet page full-width to match other dashboard pages
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 12:50:27 +03:30
keyhan c73340e4a2 fix(frontend): match favicon to logo (white cloud on blue gradient)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-18 12:07:28 +03:30
keyhan fd38f5659f feat(admin): login-as-user impersonation with audit log
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>
2026-06-18 00:49:02 +03:30
keyhan 7958d2fa72 feat(admin): super-admin user detail dashboard
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>
2026-06-17 23:52:21 +03:30
keyhan 1d6678d050 feat(frontend): add app favicon and apple-touch icon
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 20:13:12 +03:30
keyhan a3b7e9055c feat(admin): create users by mobile number instead of email
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>
2026-06-17 12:34:43 +03:30
keyhan 37f64435f6 fix(auth): only the back-to-home link returns to the landing page
The brand logo on the auth pages now points to the login page instead
of the landing; reaching the public landing is done solely via the
explicit "back to home" link.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 01:18:27 +03:30
keyhan 95d0b162c5 feat(panel): serve authenticated app on dedicated panel subdomain
Separate the marketing landing site from the authenticated app by host.
Next.js middleware reads PANEL_HOST/LANDING_HOST at runtime and redirects
authenticated routes (/dashboard, /login, /register) from the landing host
to the panel host, and the landing root on the panel host to /dashboard.
Disabled (single-origin) when PANEL_HOST is unset, so local dev is unchanged.

Helm: add ingress.panel.host with a third ingress rule + TLS host routing to
the frontend service, pass LANDING_HOST/PANEL_HOST to the frontend, and append
the panel origin to the backend CORS list (frontend URL stays first so
PLATFORM_DOMAIN resolution is unaffected).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 17:33:19 +03:30
keyhan 37c103fa20 feat(auth): mobile-only register/login with OTP verification
- 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>
2026-06-16 16:40:08 +03:30
keyhan ce6813db99 fix(logs): stop build-log polling once build finishes
The build-logs tab kept polling every 5s and showing the auto-refresh
indicator even after the build reached a terminal state. Gate both on
the build still being in progress, and label a completed build as
"done" instead of the misleading "running" status.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 02:23:01 +03:30
keyhan 1ae51fb273 fix(logs): force LTR alignment in workload log terminals
The pod and build log <pre> blocks inherited the RTL direction of the
surrounding page, right-aligning log text and hurting readability. Pin
them to dir="ltr" with text-left so output reads naturally.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 02:15:34 +03:30
keyhan 643e8c5c61 Merge branch 'feat/live-build-logs-modal' 2026-06-16 02:08:03 +03:30
keyhan 6022739b80 feat(deploy): stream live build logs in build progress modal
Show real-time kaniko/init-container build output inside the build
progress modal during the building/deploying phases, alongside the
existing percentage. The build-logs endpoint now returns live pod logs
while a build is in progress (falling back to the persisted log once
finished), and the modal polls it every 2s with auto-scroll. Minimize
behaviour is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 01:50:14 +03:30
keyhan 901a20eb01 feat(deploy): configurable CPU/RAM/disk for app databases
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>
2026-06-16 01:20:33 +03:30
keyhan 8b77656bb7 chore(deps): upgrade all dependencies to latest stable
Bring backend and frontend to the latest stable releases (no pre-releases),
including major upgrades that required code migration. Both projects pass
typecheck and production builds.

Backend
- NestJS 10 -> 11 (common/core/platform-express/jwt/passport/bull/cli/
  schematics/testing), @nestjs/config 3->4, @nestjs/swagger 7->11,
  @nestjs/typeorm 10->11
- @kubernetes/client-node 0.21 -> 1.4: migrate ~200+ call sites across 6
  services to the v1 single-object argument API, unwrapped responses, err.code,
  setHeaderOptions for patch content-type, applyToHTTPSOptions. Add regression
  spec k8s-client-v1-migration.spec.ts.
- typeorm 0.3 -> 1.0: relations/select string arrays -> object form
- uuid 9->14 (drops @types/uuid), multer 1->2, bcrypt 5->6, helmet 7->8,
  class-validator 0.14->0.15
- TypeScript 5->6, ESLint 8->9, @typescript-eslint 6->8, jest 29->30,
  @types/node 20->24; tsconfig: strictPropertyInitialization:false,
  ignoreDeprecations, rootDir, explicit types[]
- @nestjs/config 4: jwt.strategy uses getOrThrow; @types/express kept at 4
  (Nest 11 runs Express 4)

Frontend
- React 18->19, Next 14->16 (async params via official codemod),
  Tailwind 3->4 (@tailwindcss/postcss, @import + @config, inline custom @apply),
  framer-motion 11->12, zustand 4->5, three 0.169->0.184, @react-three/* majors
- TypeScript 5->6 (tsconfig target es5->ES2017), ESLint 8->9,
  eslint-config-next 14->16

Infra/docs
- Dockerfiles node:20-alpine -> node:24-alpine (require-esm for k8s client)
- Add UPGRADE.md / UPGRADE.en.md; refresh README tech-stack versions

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 18:05:33 +03:30
keyhan 23386b73de Redesign the auth background and drop the icon badge.
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>
2026-06-13 13:13:23 +03:30
keyhan 12996b657b Don't force a login redirect on 401 from auth endpoints.
The response interceptor treated every 401 as an expired session and
redirected to /login. For the login/register/refresh requests themselves
a 401 just means bad credentials, so the redirect reloaded the page and
discarded the error toast. Skip the refresh/redirect path for auth
endpoints so the form can show its error.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 11:45:26 +03:30
keyhan 91a66d5645 Restyle toasts and centralize friendly error handling.
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>
2026-06-13 11:45:26 +03:30
keyhan 97cd5e989a Unify all dropdowns on the custom Select component.
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>
2026-06-12 17:37:04 +03:30
keyhan aa7ff3d26d Fix mobile select zoom and unify optional-service version pickers.
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>
2026-06-12 12:33:41 +03:30
keyhan aa3e62d0ff Make the mobile dashboard sidebar scrollable.
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>
2026-06-12 12:14:40 +03:30
keyhan 81a22cb8fd Stop tracking the TypeScript build cache.
tsconfig.tsbuildinfo is a generated incremental-build cache; ignore it
and drop it from version control.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 11:27:23 +03:30
keyhan d31d93f6b8 Localize the admin all-applications page.
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>
2026-06-12 01:06:33 +03:30
keyhan e43274e9a2 Localize the deploy wizard.
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>
2026-06-12 00:48:45 +03:30