The backend returns { data: User[], total: number } but the frontend
was treating usersData directly as User[], causing filteredUsers.map
to throw 'not a function' when the page loaded.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
billing/page.tsx, billing/plans/page.tsx, billing/invoices/page.tsx
were hardcoded in English. Added zh/billing.json and en/billing.json
covering overview, plans, and invoices sections. Registered billing
namespace in i18n config.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Platform admins operate across all tenants and don't belong to any
specific tenant — showing 'Tenant: Not selected' was misleading.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Ports the APK/IPA upgrade management UI from rwadurian/mobile-upgrade
into it0-web-admin, adapted exclusively for IT0 App's version-service.
New files:
- src/domain/entities/app-version.ts
Domain entity matching version-service response schema:
platform returned as ANDROID/IOS (normalized to lowercase),
fileSize as number (bigint), no versionCode/fileSha256 fields.
- src/infrastructure/repositories/api-app-version.repository.ts
CRUD via existing apiClient (→ /api/proxy/api/v1/versions).
Upload/parse use dedicated Next.js routes (/api/app-versions/*)
because the existing proxy uses request.text() which corrupts binary.
- src/app/api/app-versions/upload/route.ts
Multipart FormData upload proxy → API_BASE_URL/api/v1/versions/upload
maxDuration=300s for large APK files (up to 500 MB).
- src/app/api/app-versions/parse/route.ts
Multipart proxy → API_BASE_URL/api/v1/versions/parse
Forwards APK/IPA file to version-service for auto-parsing.
- src/app/(admin)/app-versions/page.tsx
Admin page: react-query list, platform filter (all/android/ios),
upload button, loading skeleton, delete/toggle with confirm.
Single-app (IT0 only) — no multi-app switcher from mobile-upgrade.
- src/presentation/components/app-versions/version-card.tsx
Version card with enable/disable/edit/delete/download actions.
Uses dark-theme CSS variables (bg-card, text-muted-foreground, etc.)
- src/presentation/components/app-versions/upload-modal.tsx
Upload modal: auto-detects platform from .apk/.ipa extension,
auto-parses version info via /parse endpoint, sonner toasts.
- src/presentation/components/app-versions/edit-modal.tsx
Edit modal: update changelog, force-update flag, enabled state,
min OS version. Loads version data on open via getVersionById.
Modified:
- sidebar.tsx: added Smartphone icon + appVersions nav item → /app-versions
- locales/zh/sidebar.json: "appVersions": "App 版本管理"
- locales/en/sidebar.json: "appVersions": "App Versions"
Backend: IT0 version-service at /api/v1/versions (no auth guard required)
Flutter: it0_app/lib/core/updater/version_checker.dart calls
GET /api/app/version/check (public) for client-side update check.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend APIs return arrays directly, not { data, total } wrappers.
Changed 21 interface declarations to type aliases matching actual
API response format.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
All pages expected API responses in { data: [], total } format but
backend APIs return plain arrays. Changed data?.data ?? [] to data ?? []
across 22 page components.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When API returns 401, clear stored tokens and redirect to /login
instead of showing an error message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The web-admin frontend was calling incorrect API paths that didn't match
the actual backend service routes through Kong gateway, causing all
requests to fail with 404 or route-mismatch errors.
URL corrections:
- servers: /api/v1/servers → /api/v1/inventory/servers
- runbooks: /api/v1/runbooks → /api/v1/ops/runbooks
- risk-rules: /api/v1/security/risk-rules → /api/v1/agent/risk-rules
- credentials: /api/v1/security/credentials → /api/v1/inventory/credentials
- roles: /api/v1/security/roles → /api/v1/auth/roles
- permissions: /api/v1/security/permissions → /api/v1/auth/permissions
- tenants: /api/v1/tenants → /api/v1/admin/tenants
- communication: /api/v1/communication → /api/v1/comm
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Web Admin:
- Update browser title to "iAgent Admin Console"
- Translation: en appTitle "iAgent", zh appTitle "我智能体"
- Sidebar: en "iAgent Admin", zh "我智能体"
- Settings placeholder: "iAgent Platform" / "我智能体平台"
- Update alt tags on logo images
Flutter:
- MaterialApp title: "iAgent"
- Chat: "Ask iAgent..." / "Start a conversation with iAgent"
- Terminal: "iAgent Remote Terminal"
- Agent call: "iAgent Calling" / "iAgent"
Logo SVG: text changed from "AI AGENT" to "iAgent"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Next.js standalone mode does not include the public/ directory automatically.
The favicon and logo SVGs were returning 404 because they were not copied
to the production image.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add logo.svg (green robot character) to project root
- Web admin: replace text "IT" badge with SVG logo in sidebar
- Web admin: add logo image to login, register, invite pages
- Web admin: add SVG favicon and apple-touch-icon metadata
- Flutter: add flutter_svg dependency, replace text "IT0" with logo on login page
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add react-i18next with browser language auto-detection and localStorage persistence
- Create Zustand locale store with UI language selector in Settings > General
- Add 17 translation namespace files for both English and Chinese (34 JSON files)
- Convert all 37 pages (auth, admin, settings) to use useTranslation hooks
- Convert sidebar and topbar layout components to i18n
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend:
- Enhanced register endpoint to accept companyName for self-service
tenant creation with schema provisioning and admin user setup
- Added TenantInvite entity with token-based invitation system
- Added invite CRUD endpoints to TenantController (create/list/revoke)
- Added public endpoints for invite validation and acceptance
Frontend:
- Created registration page with optional organization name field
- Created invitation acceptance page at /invite/[token]
- Added invite management UI to tenant detail page
- Updated login page with link to registration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add lucide icons to all navigation items
- Collapsible sidebar with icon-only mode and tooltips
- Narrower sidebar (w-60 vs w-64), compact top bar (h-12 vs h-14)
- Better search bar UX in top bar with keyboard shortcut hint
- Refined dark theme with better contrast and separation
- Custom thin scrollbar styling
- Backdrop blur for sidebar and top bar
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add UsersController to auth-service for user CRUD (GET/POST/PUT/DELETE /api/v1/auth/users)
- Add Kong route /api/v1/admin -> auth-service for tenant management
- Remove AuthGuard from TenantController (Kong handles JWT)
- Fix frontend agent-config API paths from /api/v1/agent/config to /api/v1/agent-config
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Frontend alert-rules paths changed from /monitoring/alert-rules to
/monitor/alerts/rules to match backend routes
- Removed Kong ACL plugin on audit-routes (JWT auth is sufficient)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add kid claim to auth-service JWT for Kong validation
- Add Kong consumer with JWT credential (shared secret via env)
- Add agent-config route to Kong for /api/v1/agent-config
- Kong Dockerfile uses entrypoint script to inject JWT_SECRET at runtime
- Fix frontend login path (/auth/login → /api/v1/auth/login)
- Extract tenantId from JWT on login and store as current_tenant
- Add auth guard in admin layout (redirect to /login if no token)
- Pass JWT_SECRET env var to Kong container in docker-compose
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Next.js replaces process.env.X with build-time values via
DefinePlugin, even in server-side route handlers. Without
the env var set during build, it always falls back to
localhost:8000 which doesn't work inside Docker.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The module-level const was being inlined at build time by Next.js
standalone bundler, causing the proxy to always use localhost:8000
instead of the Docker runtime env var api-gateway:8000.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Docker Hub is unreachable from server, so node:20 can't be pulled.
Reverting to node:18-alpine (already cached) and using
--experimental-global-webcrypto to enable globalThis.crypto.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
crypto.randomUUID() is used throughout services but crypto is not
a global in Node.js 18. Node.js 20 provides globalThis.crypto.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Server is on HK network, no need for China mirrors. Added
build-essential for compiling native Python packages (kokoro, etc).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The public directory doesn't exist in the project, causing
Docker build to fail with "not found" error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
web-admin npm ci was timing out on the server. Added npmmirror.com
for npm and tsinghua mirror for pip to resolve network issues.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add shared Dockerfile.service for all 7 NestJS microservices using
multi-stage build with pnpm workspace support
- Add Dockerfile for web-admin (Next.js standalone output)
- Add .dockerignore files for root and web-admin
- Fix docker-compose.yml: use monorepo root as build context with
SERVICE_NAME build arg instead of per-service Dockerfiles
- Fix postgres/redis missing network config (services couldn't reach them)
- Use .env variables for DB credentials instead of hardcoded values
- Add JWT_REFRESH_SECRET and REDIS_URL to services that were missing them
- Add DB init script volume mount for postgres
- Remove deprecated version: '3.8' from all compose files
- Add output: 'standalone' to next.config.js for optimized Docker builds
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>