Commit graph

37 commits

Author SHA1 Message Date
bf82ef3364 fix(admin): rupee formatting for avg revenue, per-tier storage bars
- Avg per Family now shows ₹ with en-IN locale instead of $
- Storage table: paid families show progress bar vs 25 GB limit (was "Unlimited")
- Column header changed from "% of free (1 GiB)" to "% of limit"
- Bar label shows "X% of 1 GiB" (free) or "X% of 25 GB" (paid)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-06 15:52:48 +05:30
4d29ef89a0 feat(admin): dunning, admin cancel, CSV, real revenue trend + churn
Subscriptions page:
- Dunning banner: lists 'pending' (grace) subs at top — failing payments to
  chase before they halt/churn
- Per-row admin Cancel button (cancel_at_cycle_end via Razorpay; any family) —
  POST /api/admin/subscriptions {action:"cancel", subscriptionId}
- Export CSV (family/plan/status/dates/rzp id/price), quoted
- Reconcile button now sends {action:"reconcile"}

Revenue page:
- Real monthly revenue chart from subscription.charged events (valued by plan
  price, grouped by IST month) — replaces the fabricated chart
- Churn rate card = cancelled+halted+expired ÷ ever-live subs (red if >10%)

subscriptions API: added revenueTrend + churn to GET; POST routes
reconcile|cancel actions.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 15:32:16 +05:30
756f5d6cfb feat(admin/billing): grant-logic tier change, churn alerts, webhook health
#1 Admin tier change uses real grant logic:
- families PATCH calls grantPremium()/revokeToFree() on tier change instead of
  hardcoded maxMembers:10. Manual/comp upgrades now match real grant (50GB/6/3).
  subscription_status records 'admin_comp'/'admin_downgrade'. Explicit
  maxChildren/maxMembers overrides still honored. Client sends tier only.

#2 Failed-payment / churn Telegram alerts (webhook):
- subscription.pending  -> warn "Payment failing (grace)" — reach out pre-churn
- subscription.halted   -> error "Subscription HALTED (churn)"
- subscription.cancelled-> warn; activated -> "New subscriber"; charged -> silent
  All include family name + sub id.

#3 Webhook freshness in admin health:
- New "Razorpay Webhooks" check: last event age (Xm/Xh/Xd ago). warn if >35d
  silence while subs exist (renewals should keep it fresh). Also added a
  "Razorpay" config-presence check.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 15:28:23 +05:30
fbcfff47bd feat(admin): subscriptions page, real ₹ revenue, family sub dates
Subscriptions monitoring (NEW):
- GET /api/admin/subscriptions: live subs (family+plan+status+dates+rzp id),
  recent webhook events, summary (status counts, MRR/ARR paise). POST = reconcile
- /admin/subscriptions page: summary cards, status chips, subs table, webhook
  log, one-click Reconcile button. Added to sidebar (💳)

Real revenue in INR (was mock $9.99):
- stats API: MRR now SUM(plan price_paise) of active/authenticated/pending subs
- revenue page: all ₹, real MRR/ARR/ARPU, growth potential off real ARPU,
  links to subscriptions page (removed fabricated monthly history)
- dashboard MRR card + revenue overview: $ -> ₹ with en-IN formatting

Family subscription dates:
- families API: joins latest family_subscriptions -> {status, plan, startedAt,
  expiresAt, cancelledAt} (try/catch safe if billing tables absent)
- families page: tier cell shows status + "since" date + renews/ends date
  (amber when cancelled)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-06 15:18:43 +05:30
87e795c837 feat: show user phone in admin users page
Answer to "is phone visible in admin?": it wasn't — added it.

- /api/admin/users: SELECT u.phone, return phone in the DTO
- admin users page: new Phone column (tap-to-call tel: link, "—" when empty),
  searchable by phone, included in CSV export (now properly quoted so
  commas/empty cells don't shift columns)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 21:48:57 +05:30
7332bd1e8b Add admin Storage & Billing monitor
Per-family R2 storage usage (the basis for usage billing), computed from
SUM(size_bytes) over memories + attachments — same basis as the quota system,
so admin numbers match what users are charged on.

- GET /api/admin/storage: per-family bytes/objects (sorted by heaviest),
  totals, over/approaching free-limit counts, est. R2 cost, 30-day upload trend.
- /admin/storage page: summary cards, daily upload chart, per-family table with
  % of free quota bar and paid/over-limit flags.
- Sidebar: added Storage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 09:45:24 +05:30
cbbe8f24ac Make admin engagement feed resilient + self-diagnosing
Analytics showed blank despite real data because one failing sub-query made
the whole route fall back to an empty shape, and the page dropped the error.

- Each sub-query (adoption, families, AI, daily) now runs in its own
  try/catch; failures are collected and returned in `error` while the other
  sections still render (partial data instead of all-or-nothing).
- Cast all MAX() timestamps to timestamptz inside GREATEST() so mixed
  timestamp/timestamptz columns can't error.
- Dedicated COUNT(*) for total families (robust denominator/summary total).
- Analytics page now surfaces the `error` string in a banner instead of
  silently rendering empty.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 00:37:53 +05:30
7a60132bb2 Add admin observability: error tracking, audit viewer, AI metrics, health
Turns the admin panel into a real monitoring tool so production bugs are
visible instead of silent.

- Error & crash tracking: error_events table (migration 0010) + logError()
  helper + /api/errors ingest; global-error.tsx and (app)/error.tsx report
  crashes automatically; /admin/errors viewer (recent + grouped, filters).
- Full audit-log viewer at /admin/audit over the existing audit_log (all
  actions, not just auth) with action/resource/family/user/text filters.
- AI observability at /admin/ai over ai_usage: per-intent latency (avg/p95),
  tokens, cost, daily trend, slowest calls, medical-redirect count.
- System health at /admin/health: DB latency, migration status, recent error
  volume, and integration config presence.
- Sidebar updated with Health / Errors / Audit Log / AI Usage.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 00:27:07 +05:30
94d9b234f8 Fix admin analytics crash — cartesian join + undefended render
The /admin/analytics page calls /api/admin/engagement, whose per-family
query LEFT JOINed feeds × diapers_logs × sleeps × vaccinations × growth ×
chat_sessions before GROUP BY — a cartesian explosion that times out for
any family with real activity, 500ing the route. The page then ran
[...data.families] on the error object and white-screened.

- Pre-aggregate each log table to one row per child (CTEs) before joining,
  eliminating the row explosion; memories aggregated per family.
- Route error fallback now returns the full shape (safe empties) not {error}.
- Page normalizes the response into the full EngagementData shape so a bad
  response renders an empty state instead of crashing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-30 00:03:48 +05:30
dad0611350 SEO overhaul: metadata, robots, sitemap, structured data
- Add metadataBase to root layout so OG/Twitter/canonical URLs resolve
  to absolute https URLs (fixes broken social previews)
- New src/lib/seo.ts with SITE_URL + JSON-LD builders
- New robots.ts (disallow api/admin/private app paths) and sitemap.ts
  (marketing pages + blog posts with real lastmod dates)
- JSON-LD: Organization/WebSite/SoftwareApplication on home,
  Blog+Breadcrumb on blog list, BlogPosting+Breadcrumb on posts
- Per-page canonical + Open Graph on all marketing pages; article OG
  + Twitter cards on blog posts; per-post dynamic OG image
- noindex on (app) and admin layouts; richer PWA manifest
- Fix CSP to allow plausible.io in script-src/connect-src (analytics
  was silently blocked)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-29 11:03:04 +05:30
23a365309b feat: admin orphaned family management + user journey analytics
- Orphaned families (0 members) now visible with amber badge in /admin/families
  with filter tab and explicit "Delete Family + Data" cascade delete button
- Delete confirmation shows exact counts: children, logs, memories
- Delete child button added to /admin/children with count confirmation
- New DELETE /api/admin/families/[id] — full cascade delete (children, feeds,
  diapers_logs, sleeps, vaccinations, growth, memories, chat, etc.)
- New GET/DELETE /api/admin/children/[id] — cascade child delete with counts
- Extended families GET to include logCount + memoryCount per family
- New /api/admin/engagement — feature adoption %, per-family engagement table,
  AI usage stats (30d), daily activity chart using correct table names
- /admin/analytics fully redesigned: adoption funnel bars, per-family engagement
  table (sortable, filterable by activity), AI cost tab with INR breakdown
- Fixes wrong table names in old analytics (activity_logs, growth_records → real tables)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 09:38:34 +05:30
c2695435f2 Fix broken admin actions: delete cascade, error feedback, loading states
Users page:
- Delete was silently failing with FK constraint violations — sessions,
  accounts, support_tickets and family_members all have ON DELETE no action
  refs to users. Now cascades in correct order before deleting the user.
- Added error/success toast notifications so failures are visible
- Delete button shows loading spinner while in-flight; all buttons
  disabled during operation to prevent double-submit
- Always optimistically removes row on success (no full refetch needed)

Families page:
- Replaced browser prompt() for "New Family" with inline form — prompt()
  is blocked in some environments (CSP, iframes, browser settings)
- Fixed role-before-email bug: role dropdown was silently lost when changed
  before typing email, because onChange reset the whole addMember state.
  Now uses per-family form state with stable field updates.
- Remove member button shows loading spinner; disabled during operation
- Tier change button shows loading; disabled during other tier changes
- Added error/success toast notifications for all actions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 08:59:20 +05:30
23010e9d90 Admin panel overhaul: activity monitor, real DB wiring, tier management
- New /admin/activity page: live login events, failed attempts, active
  sessions from audit_log + sessions tables; auto-refresh toggle
- New /api/admin/activity route: queries audit_log + sessions for
  stats (active sessions, logins/failures 24h, signups 7d) and events
- Fix /api/admin/stats: real growth charts (families/users by day),
  real children-by-age, real conversion rate, active sessions count,
  and login/failure counts — was all hardcoded empty arrays before
- Fix /api/admin/analytics: avg logs per family now divides by actual
  family count instead of hardcoded 1
- Dashboard: 6-card grid adding Active Sessions + Failed Logins 24h
  with links to Activity Monitor; bar charts now show hover counts
- Families: inline tier upgrade/downgrade button (Pro ↑ / Free ↓)
  wired to existing PATCH API; member panel polished
- Support: admin reply thread using support_responses table; Cmd+Enter
  to send; conversation view with original message + admin replies;
  auto-moves ticket to in_progress on first reply
- Settings: honest read-only display for env-var-controlled settings
  (pricing, AI config); editable free-tier limits that write to DB
- New /api/admin/families/limits route for bulk free-tier limit update
- Sidebar: added Activity Monitor nav item

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 08:35:01 +05:30
7189fc766c refactor(ui): apply design system components across all pages
Replace raw <input>/<button>/<select> elements with Button, Card, Input,
Select, Modal, Badge, and ConfirmDialog from @/components/ui in all
non-admin and admin pages. Removes ~550 lines of inline Tailwind utility
classes from form elements while keeping all business logic intact.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 10:24:43 +05:30
fc0e75b5ad fix(admin): scope FamilyProvider out of admin routes, ensure cookies on admin fetches
Root causes:
- tia_admin_session is httpOnly so document.cookie could never read it → all
  client-side cookie checks always failed and redirected before any data fetched
- Sub-pages used localStorage.getItem("admin_token") which was never stored,
  and passed Authorization: Bearer null headers the server ignores

Fixes:
- FamilyProvider: use usePathname() hook instead of window.location.pathname
- admin/layout.tsx: rewrite as server component using verifyAdminSession()
  (new lib/admin-auth.ts helper that uses next/headers cookies()) → server-side
  redirect to /admin-login if session invalid; extract sidebar to AdminSidebar.tsx
- admin/page.tsx: remove broken document.cookie guard (layout handles auth now)
- admin-login/page.tsx: replace document.cookie check with GET /api/admin/auth call
- All 7 admin sub-pages: remove localStorage guard, remove Authorization: Bearer
  headers, add credentials: include to every fetch call

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 12:16:10 +05:30
8e7a3fbe35 Clean up debug logs 2026-05-17 11:26:01 +05:30
4212c1f632 Debug login flow 2026-05-17 11:20:53 +05:30
d94a15e38e Fix admin login: redirect path, add logout, remove unused code
- Fix redirect from /admin/login to /admin-login
- Add DELETE endpoint for logout
- Connect logout button to API
- Remove unused admin state/localStorage

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-17 10:54:15 +05:30
5f80ec4570 Fix admin pages to use cookie auth 2026-05-17 01:20:26 +05:30
c65051cf7d Add password management to admin users page
- Add PATCH endpoint to set user passwords
- Add password modal UI in admin panel
- Update CLAUDE.md with latest features

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 15:12:23 +05:30
0349be2067 Fix TypeScript error - add hasPassword to User interface
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 15:06:58 +05:30
752924a323 Add password status column to admin users page
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 15:03:58 +05:30
40c3dcf33f Make dashboard cards clickable
- Families → /admin/families
- Users → /admin/users
- Children → /admin/children
- MRR → /admin/revenue

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 14:25:28 +05:30
2de47056e7 Fix admin panels
- Families: add "New Family" button
- Users: add "Add User" form with family selector
- Add delete user option
- Include member_id for proper removal

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 14:19:22 +05:30
8867e66928 Fix admin-login route - create proper page at /admin-login
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 12:59:01 +05:30
6543d888c8 Fix admin login page
- Create proper /admin-login page
- Fix route conflict

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 11:28:54 +05:30
da8675c045 Add admin member management
- View members per family
- Add new member by email
- Remove member from family
- Simple password auth migration file

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 10:45:38 +05:30
1932d2ae6b Fix login flow to store and use real family_id 2026-05-10 23:37:54 +05:30
1d4acd9c2a Add redirect from /admin/login to /admin-login 2026-05-10 23:28:43 +05:30
e7944cd88f Fix login page to not show sidebar 2026-05-10 23:26:11 +05:30
ec0cd13fc0 Move login to route group to exclude from admin layout 2026-05-10 23:25:32 +05:30
552c3dcb5d Fix sidebar footer positioning with flexbox 2026-05-10 23:22:48 +05:30
782ac937e6 Fix sidebar footer positioning 2026-05-10 23:19:06 +05:30
43ee05d661 Fix TypeScript errors in revenue and support API 2026-05-10 22:47:38 +05:30
0f7e778413 Fix TypeScript error in revenue page 2026-05-10 22:46:05 +05:30
cda25b04ca Add comprehensive admin panel with analytics, families, users, children, revenue, support, settings 2026-05-10 22:43:20 +05:30
d5b07078ae Add Admin System
- Admin login at /admin/login
- Admin dashboard at /admin
- Username: admin, Password: admin123
- Separate from family email login

Family Login: /login (email-based)
Admin Login: /admin/login (username/password)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-10 22:17:21 +05:30