- Create app/core/redis.py with global get_redis() singleton
- Replace 4 independent Redis connections:
- cache.py: use get_redis() instead of own aioredis.from_url
- dispatcher.py: use get_redis() instead of own connection
- health_checker.py: use get_redis() instead of per-check connection
- rate_limit.py: RedisRateLimitBackend uses get_redis() instead of own connection
- Replace main.py readiness endpoint to use get_redis()
- Add close_redis() in FastAPI lifespan shutdown
- Remove unused aioredis imports from health_checker.py and main.py
- Add .coverage, htmlcov/, test-results/, playwright-report/ to .gitignore
- Add Plan 008 (production readiness) and Plan 009 (production hardening + test infra)
- Implement min_tags/max_tags validation in platform_rules.py
- Support tags as list or comma-separated string
- Add tags field to ContentValidateRequest schemas
- Pass tags through API and service layers
- Configure pytest-cov in pyproject.toml (auto coverage on pytest run)
- Add concurrency groups to ci.yml and pr-check.yml to cancel redundant runs
- Fix pr-check.yml step IDs to kebab-case (invalid with spaces)
- Rename type-check step to style-check (ruff)
- Add sentry.client.config.ts and sentry.server.config.ts
- Add @sentry/nextjs to package.json
- Replace TODO:SENTRY in ErrorBoundary with actual Sentry.captureException
- Add console.error + Sentry reporting in auth.ts authorize and refreshAccessToken
- Enable TypeScript strict checks in production builds only
- Split Dockerfile: runtime stage (no Playwright) + e2e stage (adds Chromium)
- Add healthcheck to backend and frontend in docker-compose.prod.yml
- Fix REDIS_URL default to empty string (no hardcoded password)
- Add RATE_LIMIT_BACKEND=redis to production env example
- Remove deprecated version field from docker-compose.prod.yml
- WeChat Pay V3: real API calls with HMAC-SHA256 signing, AES-GCM callback decryption
- Alipay: real API calls with RSA2 signing, WAP payment support
- Both gateways fallback to MockGateway when unconfigured
- Attribution window configurable via ATTRIBUTION_WINDOW_DAYS env var (default 28)
- 30 platform-specific rule test cases (WeChat/Zhihu/Xiaohongshu/Baijiahao/Toutiao/Douyin)
- Fixed clickbait detection bug (character-level to word-level matching)
- E2E tests for diagnosis-strategy and content-monitoring flows
- CI: e2e-test job, bandit security scan, npm audit, performance baseline
- Fix ONBOARDING_STEPS count (5→6) to match actual flow
- Unify OnboardingState type (remove duplicate from page.tsx)
- Replace raw fetch with fetchWithAuth in health-score.ts
- Extract shared utils (round, getStatusColor, DIMENSION_ICONS) to lib/utils/health-score.ts
- Fix Step5 handleComplete silent failure on error
- Remove console.error from Step2/Step4/Step5
- Remove unused props from Step3Platforms
- Fix TS errors in agents/page.tsx and strategy/page.tsx
- Exclude test files from tsc (handled by vitest)
- Replace postgres:15-alpine with pgvector/pgvector:pg15 (built-in vector extension)
- Remove init-db.sh (pgvector image includes extension, SQL init script instead)
- Add multi-stage Dockerfile for backend (development/runtime targets)
- Add development stage to frontend Dockerfile
- Update .env.example with correct passwords and Docker-internal URLs
- Add POSTGRES_PASSWORD/REDIS_PASSWORD to .env for Docker Compose
- Use named volume for frontend node_modules
- Add backend healthcheck to docker-compose.yml
- Redis: add password authentication (requirepass), update healthcheck
- PostgreSQL: replace hardcoded password with env variable
- Docker Compose: remove obsolete version field, use env vars for credentials
- Add .env.production.example template with strong password placeholders
- Update all .env files with new credentials and ports
- analytics.py: 4 DateTime columns now timezone-aware (99 total, 0 remaining)
- Migration script updated with publish_records, content_metrics, optimization_insights
- Docker Compose: db port 5433, redis port 6380 (avoid conflicts with fischerx)
- .env files: DATABASE_URL and REDIS_URL updated to new ports
- alembic.ini: updated to localhost:5433
- Convert TIMESTAMP WITHOUT TIME ZONE to TIMESTAMP WITH TIME ZONE
- Uses AT TIME ZONE 'UTC' for safe data conversion
- Covers all models: users, brands, queries, citations, agents, etc.
- Includes downgrade path back to TIMESTAMP WITHOUT TIME ZONE
- Extend fetchWithAuth with responseType parameter ('json' | 'blob')
- reports.ts: PDF/CSV export now uses fetchWithAuth blob mode
- reports/page.tsx: remove duplicate API_BASE, use fetchWithAuth for CSV export
- lifecycle/new/page.tsx: replace raw fetch with fetchWithAuth for quick-start POST