API runs via systemd on port 3000, Docker deployment not needed yet.
Health check now targets the actual running API.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add ARG DATABASE_URL to Dockerfile so prisma generate works at build time
- Fix env file path (/opt/zhixi/env/ not /etc/zhixi/)
- Fix MySQL container name (mysql, not mysql-zhixi)
- Use correct DB name (zhixi_prod)
- Prevent duplicate mysql/redis containers from docker compose
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Root cause: deploy.yml used runs-on: ubuntu-latest, which matched
the 4C4G web runner instead of the 8C32G prod runner. The web runner
doesn't have access to /opt/zhixi/, systemd, or Docker.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Root cause: git clone http://localhost:3000 failed because port 3000
is NestJS, not Gitea. Use internal network URL instead.
Also add sudo to privileged commands and set -e to fail fast.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Service file is now minimal (no startup script dependency).
CI step verifies reranker importability via systemd-run on host.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Multi-line Python in ExecStartPre is invalid systemd syntax.
Extract pip install + reranker self-test into startup.sh.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Runner container lacks Python 3.11, so pip install and self-test
now run as ExecStartPre in zhixi-worker.service on the host.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
RateLimitService could not be injected into feature modules due to
NestJS DI module isolation. Replaced with a global Guard that uses
@RateLimit() decorator metadata to apply per-endpoint limits.
- RateLimitGuard: checks Redis counters, throws 429 on exceed
- Decorators: LoginRateLimit, FeedbackRateLimit, AiAnalysisRateLimit,
FileUploadRateLimit
- Applied to: auth (login), feedback, ai-analysis, files endpoints
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
B12: AI analysis now async — POST /ai-analysis queues job, returns immediately.
Worker supports both active-recall and feynman-evaluation types.
B13: DocumentImportWorker fully implemented — all processing moved from
service to worker. Service only queues and returns.
B14: NotificationWorker already complete (no changes needed).
B15: All 3 workers now fully functional.
New endpoint: GET /ai-analysis/jobs/:id for job status polling.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
B7 Feynman evaluation: POST /ai-analysis/feynman
B8 Knowledge import: replaces DocumentImport setTimeout mock with AI
B9 Review card generation: POST /reviews/generate-cards
B10 Learning trend analysis: GET /activity/trend
4 workflows, 4 prompts, 4 schemas, all registered in AiModule.
AiAnalysisRepository made generic to handle varied result shapes.
DocumentImportService now calls KnowledgeImportWorkflow + saves to DB.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
ioredis with lazyConnect: true requires explicit .connect() — without it
the client never connects and isHealthy() always returns false.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Split AuthService into AppleAuthService, TokenService, AuthService
- Add dev-login endpoint (dev-only, disabled in production)
- AppleLoginDto: authorizationCode optional, add userIdentifier/email/fullName/nonce
- Login/refresh responses now include user object
- logout: single-token revoke + JwtAuthGuard protection
- users.repository: switch from in-memory Map to Prisma persistence
- JWT payload includes role, guards attach full user info to request
- Dual JWT secret support (JWT_ACCESS_SECRET / JWT_REFRESH_SECRET)
- Replace jwks-rsa+jsonwebtoken with jose library
- Prisma User model: add role field
- Independent DTO files with @Transform for empty string safety
- Add 5 iOS login flow documentation files