Commit Graph
6 Commits
Author SHA1 Message Date
mjalmoudy94 d532929189 feat(integration): prepaid billing, engine UI, credits console, direct tasks, v2 final
- Prepaid credit system: org wallet, debit on usage, chat gate, admin credit console
- Engine UI: /manager, /tasks, /tasks/[id], /workforce, /dashboard, /traces pages
- Direct task creation (HTTP POST /tasks, MCP tasks_create) at pending_manager_review
- Pause/resume/cancel/answer actions in engine API and UI
- Employee cap (7 per org default), review pipeline guard (active reviewer required)
- Scheduler: wide window prevents org starvation; archived employees excluded from cap
- Tenant isolation: project-id cross-org 404, engine never uses another tenant's sandbox
- Order route fix: manager built with pipeline states + employee profiles
- Contract extension: ModelGrantPort.get_org_policy with DefaultOrgPolicy
- Engine event types in @agy/contracts (task.step, task.gate, run.log, run.tool, team.changed)
- api-engine.ts typed client; api-credit.ts client
- Alembic migration c4d5e6f7a8b9: prepaid credit + engine UI tables
- 859 tests passed, 1 skipped; ruff/mypy/tsc/eslint/vitest all green

Refs: PLAN-v2.md §9 (T1–T43), todo-v2-final.md
2026-10-14 23:19:05 +03:30
mjalmoudy94 5fb85d6eed feat(org): org creation wizard + app profile (v2 phase A1-2) 2026-10-14 10:46:47 +03:30
mjalmoudy94 5095a29df9 feat(org): platform invites, roles, org sharing (v2 phase A1-1)
- New platform_invites table (migration a1b2c3d4e5f1) + PlatformInviteRow
- Owner-only endpoints in admin_users.py: issue/list/revoke platform invites
- invites.py: two-kind resolution (org + platform), email-supplied accept path
- auth.py /me gains needs_onboarding (manager, 0 orgs, not owner)
- organizations.py: transfer-ownership, leave (last owner guard), list/revoke org invites
- contracts + web UI: admin/users invite modal, accept-invite platform variant, onboarding gating
- Tests: test_org_platform_invites.py (18), org-sharing.test.tsx; report under docs/plan/reports

Note: (app)/settings "اشتراک‌گذاری سازمان" section (1.10) remains presentational work;
endpoints are done and tested.
2026-10-14 09:14:09 +03:30
mjalmoudy94 8eb631aedf ساختار مالکیت پلتفرم: یک مالک، مدیرانِ ساختهٔ مالک، سازمان‌های مدیریت‌شده
- users.is_platform_owner → users.platform_role (owner|manager|user) با مهاجرت
  d4e5f6a7b8c9 و backfill. ایندکس یکتای جزئی uq_single_platform_owner تضمین
  می‌کند دقیقاً یک مالک وجود داشته باشد — در سطح دیتابیس، نه فقط در کد.
- ثبت‌نام عمومی حذف شد (POST /auth/signup). حساب‌ها فقط با POST /admin/users
  (فقط مالک، با رمز موقت یک‌بارمصرف) یا با پذیرش لینک دعوت ساخته می‌شوند.
  در مسیر دعوت، اگر حساب وجود نداشته باشد خودِ دعوت‌شده رمز تعیین می‌کند؛ اگر
  وجود داشته باشد لینک هرگز جای reset رمز را نمی‌گیرد.
- ساخت سازمان فقط برای مالک و مدیران؛ کاربر عادی با دعوت عضو می‌شود.
- تنزل یا حذف مدیر، سازمان‌هایش را به مالک سامانه منتقل می‌کند (مالکیت + عضویت،
  با audit). حساب مالک از API تغییرناپذیر است؛ جابه‌جایی صندلی فقط با
  POST /admin/transfer-ownership و در یک تراکنش انجام می‌شود.
- افزودن POST /auth/change-password برای تبدیل رمز موقت به رمز خصوصی.
- فرانت: صفحهٔ /admin/users، صفحهٔ /account، بازنویسی /accept-invite، حذف /signup،
  گارد /onboarding برای کاربر عادی، و نشان نقش پلتفرم در پوستهٔ اپ.
- PRAGMA foreign_keys=ON برای SQLite تا ON DELETE CASCADE در dev و prod یکسان
  رفتار کند (پیش‌تر حذف کاربر، عضویت‌هایش را یتیم می‌گذاشت).
- تست: ۳۰۰ تست بک‌اند (شامل tests/test_platform_hierarchy.py با ۲۲ تست) و ۶۴ تست
  فرانت‌اند؛ ruff، mypy، tsc، eslint و build تمیز.
2026-10-13 21:58:41 +03:30
mjalmoudy94 e56f105db3 رفع فلو دعوت عضو: لینک کلیک‌پذیر و صفحهٔ پذیرش دعوت
لینک دعوت هم کلیک‌پذیر نبود و هم کار نمی‌کرد؛ چهار نقص هم‌زمان:

- `invite_url` نسبی بود (`/accept-invite?token=…`) و host نداشت → حالا از
  `settings.app_url` آدرس مطلق ساخته می‌شود.
- صفحهٔ `/accept-invite` در اپ Next وجود نداشت → ۴۰۴.
- هیچ اندپوینت پذیرش دعوت در بک‌اند نبود؛ `InviteRepository.mark_accepted`
  نوشته شده بود ولی هرگز صدا زده نمی‌شد، پس توکن مصرف نمی‌شد.
- در تنظیمات، لینک به‌صورت متن ساده در `<p>` رندر می‌شد.

بک‌اند:
- روتر `app/interfaces/http/routers/invites.py`:
  `GET /api/invites/{token}` (پیش‌نمایش) و `POST /api/invites/accept`.
  عمداً زیر `/organizations/{org_id}` نیست: دعوت‌شونده هنوز عضو نیست و
  `get_org_context` ردش می‌کند، پس خود توکن مجوز است. accept ایدمپوتنت است.
- `AuditAction.MEMBER_JOIN = "member.join"`.
- رفع باگ نهفته: `Invite.is_expired()` بین `expires_at` خوانده‌شده از SQLite
  (naive) و `utcnow()` (aware) خطای مقایسه می‌داد. طبق قرارداد موجود پروژه
  (`_aware` در `adapters/agy.py`)، در `repositories/identity.py` تابع `_aware`
  اضافه و روی `expires_at`/`accepted_at` اعمال شد.

فرانت:
- صفحهٔ `app/accept-invite/page.tsx` با پیش‌نمایش سازمان/نقش و پذیرش؛ پس از
  پذیرش `setActiveOrganization` می‌کند تا در همان سازمان لند کند.
- قراردادهای `InvitePreview`/`AcceptInviteResult` و کلاینت
  `previewInvite`/`acceptInvite`.
- `login`/`signup` پارامتر `?next=` را می‌فهمند (فقط same-origin) تا توکن دعوت
  در مسیر احراز هویت گم نشود.
- `settings`: لینک به `<a>` واقعی + دکمهٔ «کپی لینک».

تست: `tests/test_invites.py` (۶) و `src/test/accept-invite.test.tsx` (۵).
بک‌اند ۲۵۲ سبز + ruff/mypy تمیز؛ فرانت ۶۱ سبز + tsc/eslint تمیز.
2026-10-13 17:47:26 +03:30
mjalmoudy94 717e53a7ce نسخهٔ وب مستقل — پلتفرم نیروی کار هوش مصنوعی
مخزن اختصاصی برنامهٔ وب؛ محتوای پوشهٔ web در ریشهٔ مخزن قرار گرفت.
تاریخچهٔ پروژهٔ ربات (agy-bot) در این مخزن وجود ندارد و هیچ وابستگی runtime به آن نیست.
2026-10-13 00:39:28 +03:30