Files
smart-org/docs/plan/reports/agent-1-phase-2.md
T

71 lines
5.5 KiB
Markdown

# Agent 1 · Phase 2 — Org creation wizard + app profile (v2 A1-2)
**Status:** done. Backend + frontend + tests all green.
**Branch:** `dev` (Gitea auto-deploys `dev`).
**Checks:** `ruff` clean on new `.py`; `test_org_wizard.py` 16/16 pass; web `tsc --noEmit` clean; `next lint` clean; `org-wizard.test.tsx` 6/6 pass; `org-sharing.test.tsx` 5/5 pass.
---
## Endpoints added (method + path + role)
| Method | Path | Who |
|---|---|---|
| GET | `/api/setup/catalog` | any authenticated user |
| GET | `/api/setup/draft` | any authenticated user (row is user-scoped) |
| PUT | `/api/setup/draft` | any authenticated user (204, no secrets persisted) |
| POST | `/api/setup/check-git` | any authenticated user (URL format + SSRF check server-side) |
| POST | `/api/setup/check-deploy` | any authenticated user (TOFU fingerprint on success) |
| POST | `/api/setup/complete` | any authenticated user; **403** for role `user`, **409** if the caller already owns an app |
| GET | `/api/organizations/{org}/app/profile` | org member |
| PATCH | `/api/organizations/{org}/app/profile` | `CAN_MANAGE_PROJECTS` (owner/admin/manager) |
| PUT | `/api/organizations/{org}/app/deploy-target` | `CAN_MANAGE_PROJECTS` |
| PUT | `/api/organizations/{org}/app/git` | `CAN_MANAGE_PROJECTS` (credential rotation only — git source is fixed after creation) |
Audit action `organization.wizard_complete` (`ORG_WIZARD_COMPLETE`) is written on complete.
## Tables / migrations
- New `org_setup_drafts` table via migration `d5e6f7a8b9c0_org_setup_drafts.py`
(`down_revision="a1b2c3d4e5f1"`, the Phase 1 head). Columns: `id, user_id (FK users CASCADE), step, data_json, created_at, updated_at`, index `ix_org_setup_drafts_user_id`.
- App-profile columns on `projects` (`app_type, language, framework, runtime_version, package_manager, setup/build/test/start_command, app_port, healthcheck_path, git_source, external_repo_url, wizard_completed_at`) — added in the v2 foundation (TODO-0), not this phase.
- `UNIQUE(organization_id)` on `projects` enforces 1 org = 1 app; the service returns a friendly **409** Persian message (`این سازمان قبلاً یک اپلیکیشن دارد.`) instead of a raw constraint error.
## Files
Backend
- `app/domain/projects/catalog.py` — pure-Python catalog (2.1): `APP_TYPES`, `GIT_SOURCES`, `LANGUAGES` → frameworks → `ProfileDefaults`; `defaults_for(...)`.
- `app/infrastructure/db/models_org.py` — `OrgSetupDraftRow`.
- `alembic/versions/d5e6f7a8b9c0_org_setup_drafts.py` — migration.
- `app/application/services/org_setup_service.py` — `OrgSetupService` (`catalog, get_draft, save_draft, check_git, check_deploy, complete, get_profile, update_profile, update_deploy_target, update_git_credentials`) + `WizardPayload`.
- `app/interfaces/http/routers/app_setup.py` — all routes above (was a stub, pre-registered in `rpc_app.py`).
- `app/domain/audit/models.py` — `ORG_WIZARD_COMPLETE`.
- `tests/test_org_wizard.py` — 16 tests.
Frontend
- `packages/contracts/src/index.ts` — `CatalogPayload`, `CatalogLanguage/Framework/Defaults`, `WizardCompleteResult`, `AppProfile`, `DeployTargetSummary`, and request bodies (`SetupDraft`, `CheckGitBody`, `CheckDeployBody`, `WizardCompleteBody`, `DeployTargetPutBody`, `GitCredentialsPutBody`, `AppProfileUpdate`).
- `apps/web/src/lib/api-org.ts` — `setupApi` (wizard) + `appProfileApi` (org-scoped profile/deploy/git).
- `apps/web/src/app/onboarding/page.tsx` — rebuilt as a 5-step wizard (stepper, back/next, draft auto-save + resume, secrets stripped from the draft).
- `apps/web/src/app/(app)/settings/page.tsx` — new "اپلیکیشن" tab (`AppTab`): profile editing, git credential rotation, deploy-target edit + test.
- `apps/web/src/test/org-wizard.test.tsx` — 6 tests (catalog load, slug auto-suggest, step navigation, **secrets never in draft payload**, manager-with-org redirect, plain-user waiting screen).
## Contract consumption (frozen — unchanged)
- `RepoWorkspacePort.test_remote` (Agent 3) — external git check.
- `DeployTargetTester.test_connection` (Agent 3) — production deploy check.
- `WorkforceBootstrapPort.bootstrap_team` (Agent 2) — called after commit.
- `DeliveryHooks.on_app_created` (Agent 3) — called after commit; each hook called once, failure logged, never rolls back the org.
## Manual QA steps
1. As the owner, invite a manager (Phase 1 flow); log in as that manager → redirected to `/onboarding`.
2. Step through: org name/slug → app type/language/framework (advanced accordion prefilled) → git (platform or own repo, "بررسی اتصال") → optional production deploy ("تست اتصال") → review → create.
3. Success screen → "برو به مدیر AI" → `/manager`. `GET /api/auth/me` now returns `needs_onboarding: false`; exactly one `projects` row exists with a full profile.
4. In the new org, open Settings → "اپلیکیشن": edit commands/port/healthcheck, rotate git credentials, set + test a deploy target. Secrets never appear in responses (only `has_secret` / masked values).
5. Confirm a second `POST /setup/complete` returns **409**.
## Known limitations / open items
- No `GET` for the deploy target exists yet (the service `update_deploy_target` only writes). The settings tab therefore shows post-save feedback from the `PUT` response (`has_secret`, `last_test_ok`, `last_test_message`) rather than a pre-filled form. A read endpoint can be added later without touching the contract.
- Default model grants (Phase 3) are **not** copied on `complete` yet — `complete` passes `deploy_target`/git through; grant copy lands in Phase 3.3.
- CHANGE REQUESTs: none blocking this phase.