Skip to content

IAM — մուտք, կազմակերպություններ, դերեր և իրավունքներ ​

Սա այն մոդուլն է, որտեղից սկսվում է ցանկացած սեսիա. հաստատել, թե ով ես դու, ապա ընտրել (կամ հայտնվել) կազմակերպության մեջ։ Ամեն ինչ ստորև հենվում է apps/core-api/src/modules/auth-ի և .../organizations, .../roles-ի վրա։

Ինչպես անել... ​

Խմբավորված է նույն կերպ, ինչ տեխնիկական բաժինները ստորև — յուրաքանչյուր էջի օգնության պատկերակը տանում է հենց իր խումբը, ոչ թե այս ամբողջ ցանկը։

Նույնականացում ​

Ստեղծել հաշիվ — /auth/sign-up → մուտքագրիր email և գաղտնաբառ → Ստեղծել հաշիվ → ստուգիր փոստարկղդ, այնտեղ հաստատման հղումով նամակ կլինի։ Տես դաշտերի ուղեցույցը։

Մուտք գործել առանց գաղտնաբառի — /auth/sign-in-ում սեղմիր Մուտք գործել մուտքի հղումով կամ Մուտք գործել կոդով գաղտնաբառի փոխարեն, մուտքագրիր էլ. փոստը, ստուգիր փոստարկղը։ Տես դաշտերի ուղեցույցը։

Մուտք գործել Google-ով — Շարունակել Google-ով /auth/sign-in-ում։

Վերականգնել մոռացված գաղտնաբառը — Մոռացե՞լ եք գաղտնաբառը /auth/sign-in-ում → մուտքագրիր էլ. փոստը → հետևիր նամակի հղմանը։ Տես դաշտերի ուղեցույցը։

Ստեղծել հաշիվ — դաշտերի ուղեցույց ​
  • Email — եթե այն արդեն գրանցված է, ուղղակիորեն կասես ուղարկելիս։
  • Գաղտնաբառ — 8–128 նիշ։ Այլ պահանջ չկա (պարտադիր մեծատառ, թիվ կամ նշան պետք չէ)։
  • Ուղարկելուց հետո հաստատման նամակ է ուղարկվում, և հայտնվում է Կրկին ուղարկել հաստատման նամակը հղում — կարող ես սեղմել մինչև 3 անգամ րոպեում։ Գրանցումն ինքնաբերաբար ստեղծում է նաև անհատական աշխատավայր քեզ համար (տես Ի՞նչ է P4P-ն)։
Մուտք գործել առանց գաղտնաբառի — դաշտերի ուղեցույց ​

Թե՛ մուտքի հղումը, թե՛ միանվագ կոդը ամբողջովին փոխարինում են գաղտնաբառի ձևը։ Ընտրիր մեկ եղանակ այս այցելության համար։

  • Մուտքի հղում — մուտքագրիր email → Ուղարկել հղումը։ Միշտ կտեսնես «Եթե այդպիսի հաշիվ գոյություն ունի, մուտքի հղումն ուղարկվել է», անկախ նրանից՝ հաշիվը կա, թե ոչ — սա պահպանում է գաղտնիությունը երկու դեպքում էլ։ Հղումը վավեր է 15 րոպե։
  • Միանվագ կոդ — մուտքագրիր email → Ուղարկել կոդը → հայտնվում է 6-նիշանոց կոդի դաշտ։ Կոդը վավեր է 10 րոպե, և նորի հայցումն անմիջապես անվավեր է դարձնում նախորդը։
  • Երկու եղանակներն էլ սահմանափակված են րոպեում 3 ուղարկումով, ցուցադրվում է որպես հետհաշվարկ կրկին ուղարկելու կոճակի վրա։
Վերականգնել մոռացված գաղտնաբառը — դաշտերի ուղեցույց ​
  • Հայցում (/auth/forgot-password) — մուտքագրիր email → Ուղարկել վերականգնման հղումը։ Նույն գաղտնիությունը պահպանող հաստատումը, ինչ վերևում, անկախ նրանից՝ հասցեն ունի հաշիվ, թե ոչ։
  • Նոր գաղտնաբառ (նամակի հղումով) — մուտքագրիր և հաստատիր նոր գաղտնաբառը (8–128 նիշ, երկուսը պետք է համընկնեն)։ Եթե հղումը բացակայում է, փչացած է կամ արդեն օգտագործված, կտեսնես սխալ և կկարողանաս հայցել նոր հղում։

Գլխավոր ​

Բացել քո աշխատանքային տիրույթը — /dashboard → տիրույթի քարտը Իմ աշխատանքային տիրույթները բաժնում։ Սա այն էջն է, որտեղ հայտնվում ես մուտք գործելուց հետո, և ավատարի մենյուի «տուն» հղումը վերադարձնում է հենց այստեղ։

Գտնել տիրույթը երկար ցանկում — ցանկի վերևի Փնտրել աշխատանքային տիրույթներ… դաշտը։ Այն զտում է ըստ անվան՝ մուտքագրելուն զուգահեռ. վերևի հաշվիչը միշտ ցույց է տալիս, թե քանի տիրույթի ես իրականում անդամ, ոչ թե որքանն է մնացել որոնումից հետո։

Անցնել Հարթակի կառավարում կամ Թիմի կառավարում — վերևի քարտերը։ Տեսնում ես միայն նրանք, որոնց հասանելիություն ունես. Հարթակի կառավարում-ը պահանջում է platform:admin:access, Թիմի կառավարում-ը՝ workspace:staffing:read, իսկ կադրերի ֆոնդում կապված հայտ ունեցող կապալառուն դրանց փոխարեն ստանում է Պրոֆիլ ֆոնդում քարտը։

Հայտնվել տիրույթում, որը չի երևում — ինքդ քեզ ավելացնել հնարավոր չէ։ Խնդրիր տիրույթի սեփականատիրոջը հրավիրել քեզ. ցանկի ներքևի հուշումն էլ նույնն է ասում։

Անձնական էջ ​

Խմբագրել պրոֆիլը — /account/profile → թարմացրու լուսանկարը, անունը, հեռախոսը, ժամային գոտին, կենսագրությունը, տեղադրությունը, ծննդյան ամսաթիվը, հմտությունները և հետաքրքրությունների ոլորտները։

Ընտրել լեզուն — /account/profile → Լեզու → ընտրիր ցանկից։ Պահպանվում է անմիջապես — առանձին Պահպանել կոճակ այս դաշտի համար չկա։ Սա տարբերվում է ավատարի մենյուի արագ լեզվի անջատիչից, որը փոխում է միայն այն, ինչ տեսնում ես ընթացիկ սեսիայում. այս դաշտը քո մշտական լռելյայն լեզուն է, ներառյալ այն լեզուն, որով ուղարկվում են ծանուցումների նամակները։

Հրավերի ընդունում ​

Բացիր հրավերի նամակի հղումը (/invitations/[token])։ Հաջորդը կախված է նրանից՝ մուտք ես գործել, թե ոչ, և ինչ հաշվով — համակարգն ինքն է սա որոշում հրավերված email-ից, առանց քեզ հարցնելու։

Արդեն մուտք ես գործել հրավերված հասցեով — մեկ սեղմում Accept invitation-ի վրա, և պատրաստ է։

Մուտք ես գործել այլ հաշվով — էջը թույլ չի տա ընդունել. ցույց կտա, թե ում է ուղարկվել հրավերը, և կառաջարկի Sign out։ Դուրս գալուց հետո կրկին բացիր հրավերի հղումը՝ ընդունելու համար։

Մուտք չես գործել, և այդ email-ով արդեն կա P4P հաշիվ — սեղմիր Accept invitation, ապա մուտք գործիր հենց այնտեղ՝ գաղտնաբառով, մուտքի հղումով կամ կոդով, ինչպես հարմար է, առանց մուտքի առանձին էջ անցնելու։ Եթե այդ հաշիվը ստեղծվել է միայն Google-ով (առանց գաղտնաբառի), գաղտնաբառի դաշտի փոխարեն կառաջարկվի գաղտնաբառի վերականգնման հղում — նոր գաղտնաբառը սահմանելուց հետո կրկին բացիր հրավերի հղումը՝ ավարտելու համար։

Մուտք չես գործել, և այդ email-ով հաշիվ դեռ չկա — կարճ ձև (անուն + գաղտնաբառ) ստեղծում է հաշիվը և անմիջապես միացնում կազմակերպությանը։ Եթե ենթադրությունը սխալ էր (հասցեն իրականում արդեն գրանցված է), հղումը կփոխարկի քեզ մուտքի ձևին։

Google-ով մուտքը հասանելի է երկուսում էլ — դրանից հետո կվերադառնաս հենց այս հրավերի հղումին, արդեն մուտք գործած։

Կազմակերպության ստեղծում ​

Դրա համար կոճակ դեռ չկա։ Դա տեղի է ունենում ինքնաբերաբար գրանցվելիս — ստեղծվում է քո անձնական աշխատավայրը — մանրամասների համար տես Կազմակերպության ստեղծում ստորև։

Տիրույթի գլխավոր էջ ​

Հասկանալ, թե ով ես այս տիրույթում — /org/[slug]/dashboard, այն էջը, որը բացվում է տիրույթի քարտով։ Անվան տակ այն տպում է Ձեր դերը՝ … — այն դերերը, որ ունես այնտեղ, ուղիղ քո անդամակցությունից։

Անցնել Անդամներ, Դերեր կամ Պրոդուկտներ — երեք քարտերը, յուրաքանչյուրն իր կենդանի հաշվիչներով (ընդամենը անդամներ և նրանցից քանիսն են Առանց դերի. ընդամենը դերեր և քանիսն են անհատական. ընդամենը պրոդուկտներ և քանիսն են ակտիվ)։ Այն քարտը, որի համար իրավունք չկա, մնում է տեսանելի, բայց խամրած և չսեղմվող — իմաստն այն է, որ երևա՝ բաժինը գոյություն ունի, ոչ թե մնա կռահելու։

Կարդալ «—» հաշվիչը — այդ ցուցանիշը չի բեռնվել կամ դու այդ բաժինը կարդալու իրավունք չունես. իրական սխալը ցույց կտա հենց բաժնի էջը։ …-ը նշանակում է, որ այն դեռ բեռնվում է։

Կազմակերպության կարգավորումներ ​

Փոխել կազմակերպության անունը/նկարագրությունը/կայքը — «Կարգավորումներ» → խմբագրիր դաշտերը → Պահպանել փոփոխությունները։ Տես դաշտերի ուղեցույցը։

Սահմանել կազմակերպության լռելյայն լեզուն — «Կարգավորումներ» → Լռելյայն լեզու → ընտրիր ցանկից։ Պահպանվում է անմիջապես։ Փոխել կարող է միայն OWNER-ը — սա այն լեզուն է, որը ստանում է յուրաքանչյուր անդամ առանց սեփական անձնական ընտրության, ներառյալ ծանուցումների նամակների համար։

Փոխել կազմակերպության կարգավորումները — դաշտերի ուղեցույց ​

Առանց կազմակերպությունը կառավարելու իրավունքի, ամբողջ այս էջը ցույց է տալիս նույն երեք արժեքները որպես տեքստ — խմբագրելի դաշտեր ընդհանրապես չկան։

  • Տիրույթի URL — ցուցադրվում է տեղեկատվության համար; սահմանվում է մեկ անգամ ստեղծելիս և հետո չի փոխվում։
  • Անուն — պարտադիր, 2–100 նիշ։
  • Նկարագրություն — ոչ պարտադիր, մինչև 2000 նիշ։
  • Կայք — ոչ պարտադիր; եթե ինչ-որ բան մուտքագրես, պետք է լինի ամբողջական URL (օրինակ՝ https://example.com)։
  • Երկու բան, որոնք կարող ես սպասել այստեղ, բայց չես գտնի. սեփականատիրոջ փոփոխությունը (դա Փոխանցել սեփականությունը-ն է ստորև Անդամներ ցանկում, միայն OWNER-ի համար) և կազմակերպության արխիվացումը (դեռ հասանելի չէ ինտերֆեյսում)։

Անդամներ ​

Հրավիրել ինչ-որ մեկին քո կազմակերպություն — «Անդամներ» → Հրավիրել անդամի → մուտքագրիր էլ. փոստը, ընտրիր Դեր → Ուղարկել հրավերը։ Տես դաշտերի ուղեցույցը։

Հեռացնել անդամի կամ փոխանցել սեփականությունը — «Անդամներ» ցանկ → տողի գործողությունների մենյու → Փոխանցել սեփականությունը (կարող է միայն ընթացիկ OWNER-ը) կամ հեռացում։

Բացել անդամի էջը կամ նրա հաշիվը — «Անդամներ» ցանկում սեղմիր անվան վրա՝ այս տիրույթում անդամի էջը (դերեր, պաշտոն) բացելու համար։ Սեղմիր նրա տակի էլ. փոստի վրա՝ մարդու հաշվի էջը (Հարթակի կառավարում → Օգտատերեր) բացելու համար․ այդ հղումը կա միայն այն դեպքում, երբ քեզ մոտ կա platform:users:read իրավունքը, իսկ քո սեփական տողում այն բացում է քո պրոֆիլը։ Ամենուր, որտեղ ցուցադրվում է մարդ, անունը և էլ. փոստը աշխատում են նույն կերպ։

Անդամին տալ դեր կամ փոխել նրա պաշտոնը — բացիր այդ անդամի սեփական էջը → Դերեր կամ Պաշտոնը այս աշխատանքային տիրույթում → Պահպանել։ Տես դաշտերի ուղեցույցը։

Հրավիրել անդամ — դաշտերի ուղեցույց ​
  • Email — սխալ հասցեն, կամ արդեն անդամ/հրավիրված հասցեն, բռնվում է միայն ուղարկելիս։
  • Դեր — պարտադիր; լռելյայն MEMBER, ուստի դաշտը երբեք դատարկ չի մնում։ OWNER-ն այստեղ երբեք չի առաջարկվում — ինչ-որ մեկին սեփականատեր դարձնելու միակ ձևը Փոխանցել սեփականությունը-ն է։
  • Հրավերներ կարող ես ուղարկել մինչև 3 անգամ րոպեում։
Անդամի դերեր և պաշտոն — դաշտերի ուղեցույց ​
  • Պաշտոնը այս աշխատանքային տիրույթում — ոչ պարտադիր, մինչև 100 նիշ։ Քո սեփականը միշտ կարող ես խմբագրել; ուրիշինի համար պետք է առանձին իրավունք։ Այն կապված է հենց այս տիրույթին — տարբեր տիրույթներում նույն մարդը կարող է ունենալ տարբեր պաշտոն։
  • Դերեր — նշիր ցանկացած քանակ, ներառյալ զրո։ OWNER-ը նույնպես երբեք չի երևում այս ցանկում — այն տեղափոխվում է միայն Փոխանցել սեփականությունը-ով։
  • Յուրաքանչյուր վահանակի Պահպանել կոճակն ակտիվանում է միայն երբ դրանում ինչ-որ բան իրապես փոխվել է։

Դերեր ​

Ստեղծել կազմակերպության համար սեփական դեր — «Դերեր» → Ստեղծել դեր → անվանիր, ընտրիր իրավունքներ։ Տես դաշտերի ուղեցույցը։

Խմբագրել, կրկնօրինակել կամ ջնջել դերը — դերի ⋯ → Խմբագրել, Կրկնօրինակել կամ Ջնջել։ Երեք ներկառուցված դերերը (Owner/Admin/Member) հնարավոր չէ վերանվանել կամ ջնջել, ուստի Խմբագրել-ը նրանց համար չի առաջարկվում — բայց Կրկնօրինակել-ը և Դիտել իրավունքները-ը դեռ աշխատում են։

Ստեղծել/խմբագրել կազմակերպության դեր — դաշտերի ուղեցույց ​

Առանձին էջ է, ոչ պատուհան, որպեսզի իրավունքների ցանկը ունենա շնչելու տեղ։

  • Անուն — պարտադիր, մինչև 100 նիշ, նվազագույնը 2։ Պետք է եզակի լինի միայն քո կազմակերպության ներսում — մեկ այլ կազմակերպությունում կարող է լինել ճիշտ նույն անունով դեր։
  • Նկարագրություն — ոչ պարտադիր, մինչև 2000 նիշ։
  • Իրավունքներ — օգտագործիր որոնման դաշտը կամ բացիր մեկ խումբը մեկ առ մեկ (Անդամներ, Դերեր, Կազմակերպություն, AI, Ֆայլեր և այլն)։ Զրո ընտրված իրավունքով դեր վավեր է։ Յուրաքանչյուր դեր, ներառյալ երեք ներկառուցվածները, ունի Դիտել իրավունքները — արագ, միայն-կարդալու հայացք, առանց ամբողջ խմբագրիչը բացելու։
  • Պահպանել/Ստեղծել-ը ակտիվանում է միայն երբ ինչ-որ բան իրապես փոխվել է։
  • Ջնջել — դեր, որը դեռ նշանակված է որևէ մեկին (ակտիվ անդամի կամ սպասող հրավերի), հնարավոր չէ ջնջել — նախ վերանշանակիր նրանց այլ դերի։

Պրոդուկտներ ​

Տեսնել, թե ինչ ունի տիրույթը — /org/[slug]/products։ Քարտ ունի P4P-ի ներկայումս առաջարկվող յուրաքանչյուր պրոդուկտ. քարտի նշանը այս տիրույթի կարգավիճակն է այդ պրոդուկտի համար՝ Ակտիվ, Փորձնական, Կասեցված, Ժամկետանց, Չեղարկված կամ Չկա բաժանորդագրություն։

Բաժանորդագրվել պրոդուկտին — ոչ այստեղից։ Այս էջը միայն կարդալու համար է, այդ թվում՝ սեփականատիրոջ համար. բաժանորդագրությունները տրվում են Հարթակի կառավարում → Պրոդուկտներ և բաժանորդագրություններ բաժնից։ Դիմիր հարթակի ադմինիստրատորին։

Ընդհանուր փաստաթղթեր ​

Վերբեռնել ընդհանուր փաստաթուղթ — «Ընդհանուր փաստաթղթեր» → Փաստաթղթեր ներդիր → Վերբեռնել փաստաթուղթ։

Դիտել ընդհանուր փաստաթուղթը ներբեռնելուց առաջ — տողի ⋯ մենյուն → Դիտել՝ բացում է այն դիտման պատուհանում Ներբեռնել կոճակով, ոչ թե բրաուզերի դատարկ ներդիրում։ Պատկերները, PDF-ը, աուդիոն ու վիդեոն ցուցադրվում են ինչպես կան, .md-ն՝ ձևաչափված, .csv-ն՝ աղյուսակով, .txt/.log-ը՝ պարզ տեքստով։ Office ձևաչափերը (.docx / .xlsx / .pptx և հին .doc / .xls / .ppt) դիտում չունեն — մենյուում միայն Ներբեռնել։ 2 ՄԲ-ից մեծ տեքստ/CSV/Markdown-ը կամ բրաուզերի չվերծանվող վիդեոն (երբեմն .mov) նույնպես առաջարկում են միայն Ներբեռնել։

Ջնջել կամ վերականգնել ընդհանուր փաստաթուղթը — տողի ⋯ մենյուն → Ջնջել (տեղափոխում է Աղբարկղ, պահվում է 30 օր); Աղբարկղ ներդիրից՝ Վերականգնել կամ Ջնջել վերջնականապես։

Միացված հավելվածներ ​

Միացնել AI հաճախորդը քո P4P հաշվին — սա սկսվում է ոչ թե այստեղ, այլ հենց հաճախորդում, և նա կհարցնի այն մեկ բանը, որը կարելի է վերցնել միայն P4P-ից՝ սերվերի հասցեն։ Այն ցուցադրված է պատճենելու կոճակով Միացված հավելվածներ էջում (https://api.<P4P-ի դոմեյնը>/mcp/external — էջը ցույց է տալիս հենց այն միջավայրի հասցեն, որում գտնվում ես)։

ChatGPT-ում նախ միացրու Կարգավորումներ → Անվտանգություն և մուտք → Մշակողի ռեժիմ. առանց դրա սեփական կոնեկտորներն ընդհանրապես չեն երևում։ Կողքին այն նշված է որպես «բարձր ռիսկ» — դա ընդհանուր զգուշացում է ցանկացած երրորդ կողմի կոնեկտորի մասին, ոչ թե P4P-ի։ Ապա Կարգավորումներ → Պլագիններ → Դիտել պլագինները → «+» կոճակը որոնման դաշտի կողքին → տեղադրիր հասցեն, աութենտիֆիկացիան թող OAuth, ստեղծիր։ Պետք է Plus կամ Pro — անվճար հաշվում սեփական կոնեկտորներն անհասանելի են։ Claude Desktop-ում ավելի պարզ է՝ Settings → Connectors, ավելացրու սեփականը նույն հասցեով, նախապես ոչինչ միացնել պետք չէ։

Այնուհետև հաճախորդը քեզ կբերի Թույլատրել էկրան, որտեղ թվարկված է ճիշտ այն, ինչ խնդրում է։ Թույլատրել-ը վերադարձնում է հաճախորդ՝ արդեն միացված, Մերժել-ը՝ առանց տրված իրավունքների։

Տեսնել, թե ինչ է միացված — /account/api-tokens (հաշվի մենյուում Միացված հավելվածներ). յուրաքանչյուր հավելվածի համար մեկ տող՝ իր իրավունքներով, միացման և վերջին օգտագործման ամսաթվերով։ Երբեք չի օգտագործվել-ը հենց դա էլ նշանակում է։

Տեսնել, թե ինչ է արել հավելվածը — սլաքը իր տողում։ Գործիքի յուրաքանչյուր կանչ գրանցվում է իր իսկ թոքենի վրա, ուստի այստեղ երևում է՝ երբ, որ գործիքը և ինչու կանչը չհաջողվեց։ Հենց սա է պատասխանը «ի՞նչ է արել ChatGPT-ն իմ հաշվի հետ» հարցին, որը «վերջին օգտագործումը» երբեք չէր տալիս։

Կտրել հավելվածը — տողի աղբարկղի պատկերակը → Չեղարկել։ Այն անմիջապես դադարում է աշխատել, և դա հետարկել հնարավոր չէ. կրկին միանալու համար պետք է նորից անցնել թույլտվության էկրանով։

Հասկանալ, թե ինչ ես թույլատրում — հավելվածը երբեք չի ստանա ավելին, քան ունես դու ինքդ։ Թույլտվության էկրանին յուրաքանչյուր խնդրված իրավունքի տակ մարդկային լեզվով գրված է, թե ինչ է այն նշանակում։

Ծանուցումներ ​

Հաշվի անվտանգությունը միակ խումբն է, որը հնարավոր չէ անջատել, և միակը, որտեղ յուրաքանչյուր իրադարձություն մնում է առանձին գրառում, այլ ոչ թե միաձուլվում է նախորդի հետ. երկու այդպիսի իրադարձություն անընդմեջ հենց այն դեպքն է, երբ ամենակարևորն է տեսնել երկուսն էլ։ Ամբողջական բացատրությունը՝ Ծանուցումներ։

Հաշիվ ​

Մուտք նոր սարքից — ձեզ հայտնում են, թե ինչպիսի սարքից է դա եղել։ Դիտարկիչի պարզ տարբերակի թարմացումը նոր սարք չի համարվում. մի քանի շաբաթը մեկ գործող նախազգուշացումը ձեզ կսովորեցներ անտեսել այն, որն իսկապես կարևոր է։ Նոր ստեղծված հաշիվ առաջին մուտքը լռում է նույն պատճառով։

Գաղտնաբառի փոփոխություն — ձեզ հայտնում են, և բոլոր ակտիվ սեսիաները դադարեցվում են։ Նամակն ուղարկվում է, նույնիսկ եթե դա անողը ձեռքին ունի վավեր վերականգնման հղում — հենց այս դեպքն էլ արժե ծածկել. սխալ ձեռքեր ընկած հղումն այլապես ձեզ համար անտեսանելի է։

Ադմինիստրատորը մուտք գործեց ձեր հաշիվ — ձեզ հայտնում են՝ նրա նշած պատճառով։ Ուրիշի հաշվի տակ աշխատանքն այնուամենայնիվ գրանցվում է աուդիտի մատյանում, բայց մատյանը այն է, ինչ պետք է գնալ և կարդալ. ծանուցումը դա տեսանելի է դարձնում նրան, ում հետ տեղի է ունեցել։

Նույնականացում (/auth/*) ​

Պարզ ասած՝ սա այն ամենն է, ինչ գտնվում է «Sign In» / «Sign Up» էկրանի տակ — հաշվի ստեղծում, մուտք հինգ տարբեր եղանակով (գաղտնաբառ, email-ով ուղարկված հղում, email-ով ուղարկված միանվագ կոդ, Google, կամ մոռացված գաղտնաբառի վերականգնում), և ելք։ Ստորև տեխնիկական մասը կարող ես չկարդալ, եթե չես վրիպազերծում այս հոսքերից որևէ մեկը։

Այս բոլոր route-երը նշված են @Public()-ով auth.controller.ts-ում (սեսիա պետք չէ դրանց հասնելու համար), իսկ գրառման վրա «ծանր» route-երը (register, login, magic-link, password-reset/request, otp/send) նաև կրում են @UseGuards(ThrottlerGuard) — եթե դրանց դեմ script ես գործարկում կրկնակի, սպասիր rate limit (տես docs/TESTING.md, նախքան որևէ բան script անելը)։

  • Sign up / Sign in (/auth/[mode].vue, mode = sign-in | sign-up) — մեկ էջ, երկու ռեժիմ, փոխարկվում է route-ի պարամետրով։ Sign-up-ը հարվածում է POST /auth/register-ին, որը ստեղծում է User
    • PERSONAL կազմակերպություն նրա համար (տես Ի՞նչ է P4P-ն — յուրաքանչյուր օգտատեր ունի անհատական աշխատավայր) և dev-ում Mailpit-ի միջոցով ուղարկում է հաստատման նամակ։ Sign-in-ը հարվածում է POST /auth/login-ին, պաշտպանված է LocalAuthGuard-ով (email+գաղտնաբառ)։
  • Verify email (/auth/verify-email) — ընդունում է token-ը հաստատման նամակից (POST /auth/verify-email)։ POST /auth/resend-verification-ը կանգնած է «նորից ուղարկել» գործողության հետևում, եթե հղումը ժամկետանց է։
  • Forgot / Reset password (/auth/forgot-password, /auth/reset-password) — POST /auth/password-reset/request (միշտ վերադարձնում է հաջողություն, անկախ նրանից՝ email-ը գոյություն ունի, թե ոչ — «ստուգիր փոստդ» պատասխանը մի՛ ընկալիր որպես հաշվի գոյության հաստատում), ապա POST /auth/password-reset/confirm՝ նամակից ստացված token-ով։
  • Magic link (/auth/magic-link) — մուտք առանց գաղտնաբառի. POST /auth/magic-link-ը ուղարկում է նամակը, POST /auth/magic-link/verify-ը ընդունում է token-ը և սկսում սեսիա — նույն token-ի ձևով, ինչ գաղտնաբառով մուտքի դեպքում։
  • Email OTP — POST /auth/otp/send / POST /auth/otp/verify։ Առանձին էջ չկա — հասանելի է անջատիչի միջոցով («Մուտք գործել կոդով») հենց /auth/sign-in-ի վրա (LoginForm.vue-ի signInMethod վիճակը), Magic Link-ի նմանատիպ անջատիչի կողքին։
  • Google OAuth (/auth/callback, /auth/error) — GET /auth/google-ը սկսում է OAuth-ձեռքսեղմումը (GoogleAuthGuard), GET /auth/google/callback-ը ավարտում է այն և ուղղորդում դեպի /auth/callback (հաջողություն) կամ /auth/error (ձախողում՝ ժամկետանց/մերժված համաձայնություն, հաշվի կոնֆլիկտներ և այլն)։
  • Logout (/auth/logout) — POST /auth/logout-ը հետ է կանչում refresh token-ը. access token-ները կարճ կյանքով են (15 րոպե), այնպես որ դրանց համար սերվերային հետկանչ պետք չէ։
  • Session refresh — POST /auth/refresh — ոչ էջ է, կանչվում է ավտոմատ պորտալի HTTP client-ի կողմից, երբ access token-ը ժամկետանց է դառնում։ Refresh token-ները անթափանց են, 30-օրյա, ռոտացվող, գողության հայտնաբերմամբ (արդեն ռոտացված token-ի կրկնակի օգտագործումը հետ է կանչում ամբողջ շղթան) — տես docs/iam/ADR-001-authentication.md։

Գլխավոր (/dashboard) ​

Պարզ բառերով. այն վայրը, ուր հայտնվում ես մուտք գործելուց հետո։ Էջին երկու բան կա՝ քեզ հասանելի դյուրանցումները (Հարթակի կառավարում, Թիմի կառավարում կամ կապալառուի համար Պրոֆիլ ֆոնդում քարտը) և Իմ աշխատանքային տիրույթները — բոլոր այն կազմակերպությունների ցանկը, որոնց անդամ ես, որոնման դաշտով, երբ ցանկը երկարում է։

Սա միտումնավոր ամփոփիչ էջ չէ։ Հաշվիչները, ակտիվությունը և գրաֆիկները ապրում են հենց բաժինների ներսում. այս էջի ամբողջ գործը քեզ ճիշտ բաժին տանելն է, դրա համար էլ քարտը ողջ փոխգործակցությունն է։

  • Հարթակի կառավարում-ը ստուգում է հենց platform:admin:access-ը, ոչ թե «կա որևէ հարթակային դեր» (խստացվել է 2026-08-14) — հակառակ դեպքում միայն Staffing-ի համար տրված դերը տեսնում և կարող էր բացել հարթակի ողջ կառավարման վահանակը։
  • Թիմի կառավարում-ը ստուգում է workspace:staffing:read։ /team-ի ներսում առանց իրավունքի վայրէջք կատարելու էջ չկա, ուստի քարտը թաքցվում է, այլ ոչ թե ցուցադրվում՝ մուտքի պահին հետ շպրտելու համար։
  • Պրոֆիլ ֆոնդում-ը հայտնվում է միայն կադրերի ֆոնդում կապված հայտ ունեցողի մոտ, ով միաժամանակ թիմի հասանելիություն չունի — հասանելիության դեպքում կադրերի ֆոնդի լիարժեք էջն արդեն ծածկում է այն ամենը, ինչ ցույց է տալիս այս կրճատ տեսքը։
  • Տիրույթների ցանկը գալիս է GET /me/organizations-ից, ուստի իր հետ բերում է քո անդամակցությունն ու դերերը — անվան տակի դերը երկրորդ հարցում չի պահանջում։ P4P Internal-ը զտվում է ցանկից, եթե այնտեղ workspace:organization:manage չունես. դա տեխնիկական խարիսխ կազմակերպություն է, որի անդամ է յուրաքանչյուր աշխատակից, և մնացածների համար նրա քարտը միայն կհենվեր workspace-access.ts-ին մուտքի պահին։
  • «Ստեղծել աշխատանքային տիրույթ» կոճակ այստեղ չկա։ POST /organizations-ը հատուկ իրավունք չի պահանջում և հոժարությամբ կստեղծեր այն, բայց պորտալում մուտքի կետ արված չէ — տես Կազմակերպության ստեղծում։

Անձնական էջ (/account/profile) ​

User-մակարդակի պրոֆիլի էջը — ցուցադրվող անուն, ավատար (POST/DELETE /me/avatar) և այլ դաշտեր GET/PATCH /me-ում։ Կապված չէ որևէ կազմակերպության հետ. տես Ճարտարապետական մակարդակներ։

Եթե դու ունես որևէ հարթակային անձնակազմի դեր, էջը նաև ցույց է տալիս Իրավունքների ամփոփում վահանակ (2026-08-14) — քո ընթացիկ հարթակային դերերի տված ամեն PlatformPermission-ի իրական միավորումը, խմբավորված ըստ տիրույթի, նույն լռելյայն-փակ ակորդեոնով, ինչ դերի խմբագրիչի սեփական իրավունքների ընտրիչը (տես Դերեր վերևում)։ Կարդացվում է հենց GET /me-ի պատասխանից, միշտ արտացոլում է քո իրապես պահպանված դերերը (ոչ պահպանված չափագրումների կենդանի նախադիտում — այդ տարբերակն ապրում է ադմինիստրատորի կողմում, տես Հարթակի կառավարում → Օգտատերեր), և ամբողջովին թաքցված է մնում, եթե չունես ոչ մի հարթակային դեր։

Լեզու (2026-08-21) — PATCH /me-ի locale դաշտը, որի հետևում կանգնած է User.locale-ը։ Ֆրոնտենդում բաժանված է երկու composable-ի. useLocaleSwitch (միայն սեսիայի համար, ավատարի մենյուի սեփական անջատիչը — երբեք չի պահպանում) և usePersistedLocale (պահպանում և փոխարկում է — օգտագործվում է միայն այս դաշտով)։ Բաժանումը հայտնվեց, քանի որ նախկինում սա նույն կոդի ուղին էր. ավատարի մենյուում «պարզապես նայելու» ընտրությունը աննկատ դառնում էր մարդու մշտական ծանուցումների նամակների լեզուն, քանի որ ավատարի մենյուն ուղիղ գրում էր User.locale-ի մեջ։ resolveEmailLocale()-ը (notifications/emails/messages.ts) այն է, ինչ իրապես կարդում է դա. ծանուցման նամակի լեզուն ստացողի սեփական User.locale-ն է, եթե սահմանված է, հակառակ դեպքում՝ կազմակերպության լռելյայն լեզուն, հակառակ դեպքում՝ en։ Հարթակային SUPER_ADMIN-ը կարող է վերասահմանել ցանկացած կազմակերպության սեփական լռելյայն լեզուն Հարթակի կառավարում → Կազմակերպություններ-ից. այս վերասահմանումներից ոչ մեկը չի հասնում կոնկրետ անդամի սեփական User.locale-ին, որը միշտ առաջինն է հաղթում։

Հրավերի ընդունում (/invitations/[token]) ​

Պարզ ասած՝ էջ, որտեղ գործընկերը հայտնվում է՝ սեղմելով հրավերի նամակի հղումը։ Աշխատում է անկախ նրանից՝ նա արդեն ունի P4P հաշիվ, թե ոչ — եթե չունի, ավտոմատ հայտնվում է email/գաղտնաբառի ձև։

Հանրային էջ (GET /organizations/invitations/:token, POST /organizations/invitations/:token/accept) — աշխատում է թե՛ արդեն մուտք գործած օգտատիրոջ համար, որը միանում է մեկ այլ կազմակերպության, թե՛ բոլորովին նոր մարդու համար, որը մուտքագրում է email/գաղտնաբառ՝ մեկ քայլով հաշիվ ստեղծելու և միանալու համար։ Հրավերները կրում են Role-երի հավաքածու (InvitationRole), որոնք նշանակվում են ընդունելիս MembershipRole-ի միջոցով։

GET .../:token-ը վերադարձնում է accountExists/hasPassword հրավերված email-ի հետ միասին — էջն օգտագործում է հենց դրանք, ոչ թե կռահում, որպեսզի առաջին ռենդերին ուղղակի ընտրի ճիշտ ճյուղը (գրանցման ձև, թե մուտք, թե բացատրություն գաղտնաբառի բացակայության մասին); յուրաքանչյուր ճյուղ մնում է փոխարկելի էջի հղումով, եթե ենթադրությունը սխալ է դուրս գալիս։ Հրավերն ուղղված է կոնկրետ email-ի, ուստի isWrongAccount-ը (profile.email !== invitation.email, երբ արդեն մուտք է գործած) ամբողջովին արգելափակում է ընդունման UI-ն, փոխարենը լուռ չմիացնելու սխալ հաշվին կամ ձախողվելու անհասկանալի «արդեն մասնակից է» սխալով։ Միակ ելքը logout()-ն է, որը տանում է /, ոչ թե հետ այս էջ (հղումը պետք է կրկին բացել)։ Գոյություն ունեցող հաշվի մուտքի ճյուղը ներկառուցված է հենց էջում (գաղտնաբառ, magic link կամ OTP — նույն երեք useAuth() մեթոդները, ինչ /auth/sign-in-ը), ոչ թե վերահղում /auth/sign-in-ին և հետ, քանի որ email-ն արդեն հայտնի է; Google-ով գրանցված հաշիվը (առանց գաղտնաբառի) գաղտնաբառի դաշտի փոխարեն ստանում է գաղտնաբառի վերականգնման կոճակ — բայց այս ուղին մեկ քայլով չի ավարտվում, վերականգնումն ինքնին մուտք չի գործացնում, պետք է վերադառնալ նույն հղումով ավելի ուշ։ Կենդանի e2e-ծածկույթ՝ scripts/e2e/menu/invitation-accept.mjs։

Կազմակերպության ստեղծում ​

POST /organizations-ը պահանջում է միայն նույնականացված օգտատեր — առանց հատուկ իրավունքի։ Ցանկացած մուտք գործած օգտատեր կարող է ստեղծել լրացուցիչ կազմակերպություններ իր ավտոմատ ստեղծված անհատականից բացի (օրինակ՝ ներկայացնելու համար ընկերություն, որը հիմնում է)։ Հաստատված է (2026-08-04, apps/portal-ում որոնում երկու API-ուղիների համար). այսօր պորտալում սրա համար UI ընդհանրապես չկա — ոչ /org/create էջ, ոչ «նոր կազմակերպություն» պատուհան, հասանելի /dashboard-ից։ UI-ից POST /organizations-ին հասնելու միակ եղանակը հիմա անուղղակի է՝ գրանցման կողմնակի էֆեկտ (որը ստեղծում է ավտոմատ PERSONAL կազմակերպություն) կամ Հարթակի կառավարման «New workspace» պատուհանից (հասանելի միայն այնտեղ)։ Ինքնուրույն «ստեղծել ևս մեկ կազմակերպություն» սցենարը պատրաստ է backend-ում, բայց դեռ կապակցված չէ frontend-ին։

Տիրույթի գլխավոր էջ (/org/[slug]/dashboard) ​

Պարզ բառերով. աշխատանքային տիրույթի ներսի առաջին էջը՝ նրա անվանումը, քո դերն այնտեղ և երեք քարտ (Անդամներ, Դերեր, Պրոդուկտներ) կենդանի հաշվիչներով, յուրաքանչյուրը տանում է իր բաժինը։

Հաշվիչները կարդացվում են այն նույն ցուցակային էնդփոյնթներից, որոնք կանչում են հենց բաժինները (/organizations/:id/members, /roles, /subscriptions)՝ զուգահեռ և իրարից անկախ. սխալը կամ իրավունքի բացակայությունը տալիս են — կոնկրետ ցուցանիշի մոտ, այլ ոչ թե արգելափակում էջը։

Մեկ միտումնավոր տարբերություն Հարթակի կառավարման հանգույցից. այնտեղ առանց իրավունքի քարտը թաքցվում է, այստեղ ցուցադրվում է խամրած և չսեղմվող։ Տրամաբանությունն այն է, որ տիրույթի երեք բաժինները փոքր ֆիքսված հավաքածու են, որի գոյության մասին բոլորն էլ գիտեն. Դերերը անդամից թաքցնելը կնշանակի ձևացնել, թե տիրույթում դերեր չկան։ Հարթակային հանգույցի քարտերի ցանկն ավելի երկար է, և այնտեղ անօգուտ կետեր ցույց տալը աղմուկ կլիներ։

Պրոդուկտները ընդհանրապես իրավունք չունեն — տիրույթին ինչ է միացված, տեսնում է նրա ցանկացած անդամ։

Կազմակերպության կարգավորումներ (/org/[slug]/settings) ​

Պարզ ասած՝ Settings էջը կազմակերպության ներսում ունի երկու քարտ՝ մեկը անվան, նկարագրության և կայքի համար, մյուսը՝ լռելյայն լեզվի։ Երկու բան, որոնք կարող ես ակնկալել այստեղ գտնել՝ «դարձնել մեկ ուրիշին սեփականատեր» և «արխիվացնել/վերականգնել այս կազմակերպությունը» — կամ ապրում են այլ տեղում, կամ դեռ գոյություն չունեն ինտերֆեյսում (մանրամասները ստորև)։

  • Պրոֆիլի դաշտեր (անուն, նկարագրություն, կայք) — PATCH /organizations/:id, փակված է workspace:organization:manage իրավունքով, փոխանցելի է ADMIN-ին կամ հատուկ դերի։ Սա և ստորև լեզվի քարտը ամբողջն են, ինչ տալիս է settings.vue-ն. նրանում արխիվացման/ակտիվացման կառավարիչներ չկան։
  • Լռելյայն լեզու (PATCH /organizations/:id/default-locale, ավելացվել է 2026-08-18) — միայն OWNER-ի համար, ստուգվում է assertActorIsOwner()-ով սերվիսում, ոչ թե Permission տողով — նույն ձևը, ինչ ստորև Փոխանցել սեփականությունը-ն. չի փոխանցվում workspace:organization:manage-ով, ուստի ֆրոնտենդի ստուգումը կրկնում է members/index.vue-ի սեփական isOwner ստուգումը, ոչ թե usePermissions()-ը։ Ցանկացած այլ անդամ, ով չունի սեփական անձնական լեզվի ընտրություն, ստանում է այն, ինչ սահմանված է այստեղ (կամ en, եթե այստեղ ոչինչ սահմանված չէ) — ամբողջական առաջնահերթության կարգը տես Լեզու վերևում։ Հարթակային SUPER_ADMIN-ը կարող է նաև վերասահմանել սա կազմակերպությունից դուրս — տես Հարթակի կառավարում → Կազմակերպություններ։
  • Սեփականության փոխանցում — չնայած որ դա կազմակերպության կյանքի ցիկլի գործողություն է, այն չկա Settings էջում։ Դա տողի գործողություն է Անդամներ էջում (workspace.members.actions.transferOwnership, members/index.vue) — «դարձնել այս անդամին սեփականատեր՝ ինձ փոխարեն»։ PATCH /organizations/:id/transfer-ownership, փակված է միայն TenantGuard-ով route-ի մակարդակում, իրական ստուգումով (assertActorIsOwner()) organizations.service.ts-ի ներսում — փոխանցելի չէ workspace:organization:manage-ով. պետք է իրապես ունենալ OWNER դերը։
  • Արխիվացում / ակտիվացում (POST /organizations/:id/archive, PATCH /organizations/:id/activate) — հաստատված է (2026-08-04, որոնում apps/portal-ում երկու ուղիների համար). frontend մուտքի կետ չկա ընդհանրապես։ Երկու route-երն էլ աշխատում են (նույն միայն TenantGuard + assertActorIsOwner() սահմանափակումով, ինչ սեփականության փոխանցումը) և հասանելի են ուղղակի API-կանչով, բայց հիմա պորտալում կոճակ/պատուհան չկա, որը դրանք կանչի — OWNER-ը չի կարող ինքնուրույն արխիվացնել իր կազմակերպությունը UI-ի միջոցով այսօր։ Միակ արխիվացմանը մոտ պորտալի UI-ն Հարթակի կառավարում → Կազմակերպություններ-ի restore գործողությունն է (հակառակ ուղղություն, հասանելի միայն այնտեղ)։
  • Slug-ը անփոփոխելի է և չունի խմբագրման ուղի (նույն տրամաբանությունը, ինչ User.email-ինը)։

Անդամներ (/org/[slug]/members, /org/[slug]/members/[userId]) ​

Պարզ ասած՝ անդամների ցանկը այն տեղն է, որտեղ հրավիրում ես մարդկանց, հեռացնում նրանց կամ փոխանցում սեփականությունը։ Կոնկրետ մարդու դերը կամ job title-ը փոխելու համար պետք է մտնել նրա անհատական էջը — այս երկուսը ցանկի վրա չեն։

  • Ցանկ (GET /organizations/:id/members), «Գործողություններ» բացվող ցանկով յուրաքանչյուր տողում (workspace:members:read հենց ցանկի համար. տեսանելի է ցանկացած համակարգային դերի — մինչև իսկ բազային MEMBER-ի)։
  • Հրավեր (POST /organizations/:id/members/invite) — workspace:invitations:manage։ Throttled (ThrottlerGuard)՝ ի հավելումն TenantGuard/PermissionsGuard-ի։
  • Անդամի հեռացում և սեփականության փոխանցում — երկուսն էլ ապրում են ցանկի էջում (members/index.vue), որպես տողի բացվող ցանկի գործողություններ, իրենց հաստատման պատուհաններով։ Հեռացումը պահանջում է workspace:members:remove; սեփականության փոխանցումը՝ միայն OWNER-ի համար (տես Կազմակերպության կարգավորումներ վերևում — սա կյանքի ցիկլի գործողություն է, թեև ապրում է այս էջում, ոչ թե Settings-ում)։
  • Դերի նշանակում/հանում — անդամի մանրամասների էջում (members/[userId].vue), ոչ թե ցանկում։ POST/DELETE .../members/:userId/roles/:roleId-ը պահանջում է workspace:members:assign_role — առանձնացված job title-ի խմբագրումից (2026-08-14, նախկինում մեկ ընդհանուր portal:members:manage էր), քանի որ քո կազմակերպությանը հատուկ դերը կարող է իմաստալից ձևով ցանկանալ պատվիրակել «կարող է վերանվանել ինչ-որ մեկի պաշտոնը»՝ առանց հանձնելու նաև «կարող է փոխել, թե ինչ իրավունքներ ունեն»։
  • Job title-ի փոփոխություն — նույն մանրամասների էջում։ PATCH .../members/:userId/job-title-ը պահանջում է workspace:members:edit; սեփական job title-ի փոփոխությունը (PATCH .../members/me/job-title) պահանջում է միայն TenantGuard — բարձրացված իրավունք պետք չէ սեփական ցուցադրվող տիտղոսը փոխելու համար։
  • Կազմակերպությունից դուրս գալ (DELETE /organizations/:id/leave) — հաստատված է (2026-08-04, որոնում apps/portal-ում). frontend մուտքի կետ չկա։ Backend route-ը աշխատում է (միայն TenantGuard, ցանկացածը կարող է հեռացնել իրեն, արգելափակված է միակ/վերջին OWNER-ի համար ըստ docs/iam/ADR-007-security-invariants.md-ի), բայց «Կազմակերպությունից դուրս գալ» կոճակ այսօր պորտալում ոչ մի տեղ չկա։ Չշփոթել SetOnLeaveDialog.vue-ի հետ — դա Աշխատակազմ-ի կապ չունեցող ֆունկցիա է (մարդուն HR արձակուրդում նշելը), ոչ թե անդամակցությունից դուրս գալը։

Դերեր (/org/[slug]/roles) ​

Պարզ ասած՝ դերերը իրավունքների անվանված փաթեթներ են (օրինակ՝ «կարող է հրավիրել մարդկանց» կամ «կարող է խմբագրել կազմակերպության անունը»), որոնք նշանակվում են անդամներին։ Երեք դեր ներկառուցված են և չեն կարող վերանվանվել կամ ջնջվել՝ Owner, Admin, Member — և դրանց վրա կարող ես ստեղծել քո սեփականները։ (Չորրորդը՝ Viewer-ը, գոյություն ուներ մինչև 2026-08-19 — տես ստորև։)

roles.controller.ts, տեղադրված է organizations/:id/roles-ի վրա։ Յուրաքանչյուր route պահանջում է @UseGuards(TenantGuard, PermissionsGuard)հենց այս հերթականությամբ — տես նշումը CLAUDE.md/docs/iam/PERMISSIONS_CATALOG.md-ում՝ թե ինչու PermissionsGuard-ը երբեք չի կարող գրանցվել գլոբալ կերպով։

  • Դերերի ցանկ + նշանակելի իրավունքների կատալոգի ցանկ (GET /organizations/:id/roles, GET .../roles/permissions) — workspace:roles:read։
  • Հատուկ դերի ստեղծում (POST) — workspace:roles:create։ Դերի անվան/նկարագրության խմբագրում, և իրավունքի ավելացում/հեռացում դրա վրա (PATCH :roleId, POST/DELETE :roleId/permissions/:permissionId) — workspace:roles:edit։ Ջնջում (DELETE :roleId) — workspace:roles:delete։ Բաժանված երեք իրավունքի 2026-08-14 (նախկինում մեկ ընդհանուր portal:roles:manage էր), որպեսզի դերը կարողանա, օրինակ, պատվիրակել «ստեղծել և ճշգրտել դերեր»՝ առանց հանձնելու նաև «ջնջել դրանք»։ Համակարգային դերերը (OWNER/ADMIN/MEMBER) պաշտպանված են ջնջումից/վերանվանումից DB trigger-ով, ոչ միայն հավելվածի ստուգումով — տես docs/iam/ADR-003-rbac.md։

VIEWER-ը վերացվեց, 2026-08-19։ Այն և MEMBER-ը փաստաթղթավորված էին որպես միտումնավոր նույնական սերմանված իրավունքների հավաքածուում 2026-07-05-ից (երկուսն էլ՝ միայն կարդալու համար, առանց իրական տարբերության, որը արժեր հորինել) — files:upload/files:manage-ը (ավելացված MEMBER-ին ավելի ուշ) եղել է միակ մնացած տարբերությունը, և այն հանվել է MEMBER-ից, փոխանակ դրա համար պահելու երկու դեր։ Role.isSystem: true տողերը DB trigger-ով պաշտպանված են UPDATE/DELETE-ից. առանձին միգրացիա անջատել է այդ trigger-ը մեկ միտումնավոր DELETE-ի ընթացքում, ապա նորից միացրել։ Մի՛ «վերադարձրու» չորրորդ բազային դեր՝ նախապես չկարդալով ամբողջական հիմնավորումը docs/iam/PERMISSIONS_CATALOG.md-ում։

Պրոդուկտներ (/org/[slug]/products) ​

Պարզ բառերով. P4P-ի առաջարկածի կատալոգը՝ յուրաքանչյուր քարտի վրա այս աշխատանքային տիրույթի բաժանորդագրության կարգավիճակով։ Միայն կարդալու համար — այս էջում ոչինչ բաժանորդագրություն չի փոխում։

Տարբերությունը, որ էջն ի սկզբանե շփոթում էր և որն արժե հիշել. GET /products-ն այսպես թե այնպես վերադարձնում է միայն այն պրոդուկտները, որոնք P4P-ն այժմ առաջարկում է (isActive) — այսինքն այդ դրոշակը ոչինչ չի ասում այս տիրույթի մասին։ Նշանը վերցվում է GET /organizations/:id/subscriptions-ից. ACTIVE/TRIAL-ը կարդացվում են որպես «բաժանորդագրված է», մնացած ամեն ինչ (SUSPENDED, EXPIRED, CANCELLED և բաժանորդագրության լիակատար բացակայություն → Չկա բաժանորդագրություն) — ոչ։ Մինչև ուղղումը յուրաքանչյուր քարտ յուրաքանչյուր տիրույթում ցույց էր տալիս Ակտիվ, որովհետև բաժանորդագրություններին ոչ ոք չէր նայում։

Բաժանորդագրությունները տալիս և հետ է վերցնում հարթակի ադմինիստրատորը Հարթակի կառավարում → Պրոդուկտներ և բաժանորդագրություններ բաժնից — պրոդուկտում ինքնուրույն ձևակերպում առայժմ ընդհանրապես չկա։

Ընդհանուր փաստաթղթեր (/team/shared-documents) ​

Պարզ ասած՝ P4P աշխատակիցների ընդհանուր ֆայլերի գրադարան։ Կարճ ժամանակով ապրել է /org/p4p-internal/shared-documents-ում (2026-08-20–2026-08-23)՝ այն հիմնավորմամբ, որ իր բնույթով դա միշտ եղել է հարթակի ընդհանուր ֆայլերի պահեստի հնարավորությունը՝ ուղղված մեկ ֆիքսված կազմակերպության, երբեք ոչինչ staffing-ին հատուկ — բայց այդ URL-ը ամբողջությամբ փոխարինում էր Team Management-ի ամբողջ սայդբարը կազմակերպության shell-ի մեկ-կետանոց սայդբարով, ինչը ընկալվում էր որպես «ինձ ուրիշ տեղ տարան», ոչ թե «այս էջը փոխվեց», և ամենօրյա օգտագործման մեջ արժեր ավելի թանկ, քան երթուղիների ճարտարապետական մաքրությունը։ Տեղափոխվել է հետ։

Կրկին օգտագործում է հարթակի ընդհանուր ֆայլերի պահեստի հնարավորությունը (files:read/files:upload/files:manage) մեկ ֆիքսված, արհեստական կազմակերպության դեմ (system-org-shared-documents, slug p4p-internal) — էջի սեփական սկրիպտն այս կազմակերպության id-ն օգտագործում է կոշտ կերպով, անկախ նրանից, թե որ երթուղով են հասել դրան, քանի որ backend-ը որևէ այլ կազմակերպության համար սեփական Ընդհանուր փաստաթղթերի հասկացություն չունի։ «Ակտիվ»/ «Աղբարկղ» ներդիրներ, 30-օրյա պահպանում փափուկ ջնջման դեպքում։

Հասանելիությունը փակված է middleware/staffing-access.ts-ով, requiresPermission: 'files:read' արժեքով — նույն մեխանիզմով, ինչ /team/*-ի ցանկացած այլ էջ, միայն թե ստուգում է անդամակցությունը ֆիքսված P4P Internal կազմակերպությունում, ոչ թե :slug պարամետրով։ Հասանելի է բոլորին, մինչև MEMBER-մակարդակի files:read-ը. վերբեռնում/ջնջում պահանջում են կազմակերպության սեփական files:upload/files:manage-ը (տես Դերեր վերևում)։ middleware/workspace-access.ts-ի ընդհանուր workspace:organization:manage գեյթին /org/p4p-internal/*-ի մնացած մասի վրա (Դերեր, Անդամներ — տես Անդամներ) այլևս բացառություն պետք չէ այս էջի համար, քանի որ այն ընդհանրապես չի անցնում այդ middleware-ով։

Սովորական ձևը, որով P4P աշխատակիցները գտնում են այն. layouts/team.vue-ի սեփական սայդբարը պահպանում է «Ընդհանուր փաստաթղթեր» կետը (փակված files:read-ով, նույն իրական իրավունքով, ինչ էջն ինքը)։ /team/dashboard-ի սեփական բաժնի քարտը և «Վերբեռնել փաստաթուղթ» quick action-ը երկրորդ ճանապարհն են — տես Աշխատակազմ։ Հին /org/p4p-internal/shared-documents URL-ը դեռ աշխատում է — այժմ պարզապես վերահղում է /team/shared-documents, որպեսզի հին էջանիշը կամ հղումը փակուղի չդառնա։ Այս ամենից ոչ մեկն անցնում է արմատային /dashboard-ի «My Workspaces» ցանկով, որը միտումնավոր թաքցնում է P4P Internal-ը բոլորից, ովքեր չունեն workspace:organization:manage (dashboard.vue-ի սեփական visibleOrganizations-ը՝ ցուցադրելը մնացած բոլորին նախկինում պարզապես կարդացվում էր որպես աշխատատարածքների ցանկի աղբ մարդկանց համար, ովքեր կարող էին հասնել միայն մեկ նեղ էջի դրա ներսում)։

Միացված հավելվածներ (/account/api-tokens, /oauth/authorize) ​

Պարզ բառերով. արտաքին AI հաճախորդներ — ChatGPT, Claude Desktop, ամեն ինչ, որ խոսում է MCP-ով — որոնց թույլ ես տվել քո անունից դիմել քո P4P հաշվին։ Հաշվի մենյուի Միացված հավելվածներ-ը ցանկն է. /oauth/authorize-ը համաձայնության էկրանն է, որով անցնում ես մեկ անգամ՝ յուրաքանչյուր հավելվածի համար։

Սա հակառակ ուղղությունն է AI մոդուլի MCP էջի նկատմամբ. այնտեղ P4P-ի սեփական գործակալները գնում են արտաքին գործիքներ, այստեղ արտաքին հաճախորդը մտնում է P4P-ի ներս։

  • Ի՞նչ է կապակցումն իրականում։ Յուրաքանչյուր տող PersonalAccessToken է. պահվում է հեշավորված, ինչպես refresh-թոքենը, և հաճախորդին ցուցադրվում է ուղիղ մեկ անգամ՝ տրման պահին։ Նախածանց սյունակը միակն է, ինչ երևում է հետո, և պետք է միայն տողերն իրարից տարբերելու համար։
  • Որտեղի՞ց վերցնել հասցեն։ Սերվերը, որին միանում է հաճախորդը, https://api.<դոմեյն>/mcp/external-ն է. այն ցուցադրված է պատճենելու կոճակով հենց Միացված հավելվածներ էջում։ Սա այն միակ բանն է, որը հաճախորդն ինքը չի կարող իմանալ, դրա համար էլ միացումը սկսվում է այնտեղից պատճենելով։
  • Ինչպե՞ս է այն հայտնվում։ Միայն OAuth 2.1 հոսքով (2026-08-06). հաճախորդն ինքն է գրանցվում (POST /oauth/register, RFC 7591, միայն PKCE-ով հանրային հաճախորդներ՝ առանց client secret-ի), քեզ ուղարկում /oauth/authorize և ստացած կոդը փոխանակում թոքենի հետ։ Այս էջից «ստեղծել թոքեն»-ը միտումնավոր հանված է. այն գոյություն ուներ, մինչև ChatGPT-ի կապակցումները ցույց տվեցին, որ չմշակված Bearer-թոքեն ընդունում է հեռու ոչ ամեն հաճախորդ։ Այդ ձևով ստեղծված թոքենները շարունակում են աշխատել, մինչև չեղարկվեն։
  • Հնարավորությունների առաստաղը։ Թոքենի իրավունքները միշտ կարող են լինել միայն քո սեփական հարթակային իրավունքների ենթաբազմությունը հաստատման պահին։ Բացի այդ, իրավունքները գործիքները սահմանափակում են ավելի խիստ, քան համապատասխան HTTP ռութերը՝ platform:staffing:read-ը տալիս է միայն ընթերցում, platform:staffing:manage-ը ավելացնում է առաջադրանքների ստեղծում, կարգավիճակների փոփոխում և մեկնաբանություններ — ամբողջ իմաստն այն է, որ AI-ին տաս քոնից ցածր առաստաղ։
  • Այն ամենը, ինչ այն անում է, գրանցվում է։ Արտաքին MCP գործիքի յուրաքանչյուր կանչ գրվում է աուդիտի մատյան՝ թոքենին կապված, իսկ գործիքների պատասխաններից կտրվում են անձնական կոնտակտային տվյալները, նախքան դրանք կհասնեն մոդելին։
  • Չեղարկումը գործում է անմիջապես և հետարկվող չէ. հավելվածը պետք է զրոյից նորից թույլատրել։

Բեքենդը՝ apps/core-api/src/oauth (թույլտվության սերվեր) և apps/core-api/src/mcp-external (հենց գործիքները), միտումնավոր առանձնացված ներքին src/mcp մոդուլից՝ սեսիոն JWT-ի նկատմամբ վստահության իր մոդելով։ Ամբողջական հիմնավորումը՝ docs/mcp/ADR-001-external-mcp-server.md-ում։

Impersonation ​

Պարզ ասած՝ թույլ է տալիս SUPER_ADMIN-ին ժամանակավորապես տեսնել հարթակը մեկ այլ օգտատիրոջ աչքերով՝ օգնելու վրիպազերծել նրա հաշիվը կամ վերարտադրել խնդիր, որի մասին նա հայտնում է։ Ամեն օգտագործում գրանցվում է։ Impersonate-ը Հարթակի կառավարման օգտատիրոջ սեփական էջում սկսում է այն (2026-08-20 — տես ստորև. մինչ այդ ամսաթիվը իրապես frontend չկար, միայն ուղղակի API-կանչ)։

Միայն SUPER_ADMIN-ի համար (SuperAdminGuard — բառացի դերի ստուգում, ոչ թե փոխանցելի իրավունք, քանի որ impersonation-ը միտումնավոր չի փոխանցվում)։ POST /auth/impersonate-ը սկսում է սեսիա մեկ այլ ակտիվ օգտատիրոջ անունից. POST /auth/impersonate/:sessionId/end-ը ավարտում է այն։ Յուրաքանչյուր սկիզբ/ավարտ/մերժում գրանցվում է audit log-ում (impersonation.started/.ended/.rejected)։

Frontend (ավելացվել է 2026-08-20). Impersonate կոճակ օգտատիրոջ սեփական էջում Հարթակի կառավարում → Օգտատերեր-ում (/platform/users/[id]) — թաքցված է սեփական հաշվի և ցանկացած ոչ-ACTIVE թիրախի համար, քանի որ երկու դեպքում էլ ինչ-որ վավեր բան չկա, որի տեղը մտնել։ Պատճառ նշելը բացում է սեսիան և տեղափոխում /dashboard, որտեղից արդեն իրապես դիտում ես այդ օգտատիրոջ աչքերով (նրա իրական տվյալները, ոչ թե նախադիտում) — գլոբալ ImpersonationBanner-ը (մոնտաժված մեկ անգամ ամբողջ հավելվածի վրայից, վերապրում է ցանկացած էջ կամ layout) անվանում է, թե ում աչքերով ես նայում, և առաջարկում է End impersonation, որը վերադարձնում է այն օգտատիրոջ էջին, որտեղից ամեն ինչ սկսվեց։ Impersonation-ի token-ը միտումնավոր միայն access է, առանց refresh token-ի (կոշտ 1-ժամյա TTL, ինչպես նկարագրված է այս մոդուլի token-ի մոդելում վերևում) — ադմինի իրական token-ները չեն վերագրվում, այլ կողքի են դրվում, այնպես որ սեսիայի ավարտը (կամ պարզապես token-ի ժամկետի լրանալը) վերականգնում է դրանք, փոխարենը ադմինին դուրս մուտքագրված չթողնելով։ Բրաուզերում կենդանի ծածկույթը՝ testImpersonationUi-ն scripts/e2e/menu/impersonation.mjs-ում։

Audit log ​

Պարզ ասած՝ ամբողջ հարթակի անվտանգության համար կարևոր գործողությունների մշտական, կեղծելուց պաշտպանված պատմություն — ով է մուտք գործել, ով է փոխել դեր, ով է արխիվացրել կազմակերպություն։ Ոչ ոք, ներառյալ SUPER_ADMIN-ը, չի կարող խմբագրել կամ ջնջել գրառումը գրանցվելուց հետո։

Այս մոդուլի յուրաքանչյուր իրադարձություն (մուտք, դերի փոփոխություն, կազմակերպության կյանքի ցիկլ, impersonation...) գրանցվում է միայն ավելացվող AuditLog-ում AuditService-ի միջոցով (երբեք ուղղակի Prisma-ով — DB trigger-ը արգելափակում է update/delete-ը)։ Դիտման UI-ն (/platform/audit, platform:audit:read) Հարթակի կառավարման էջ է — տես Հարթակի կառավարում → Audit log։

Այս մոդուլի թեստավորում ​

scripts/e2e/menu/auth.mjs, organizations.mjs և impersonation.mjs (ընդամենը 41 ստուգում) գործարկում են այս մոդուլի հոսքերը սկզբից մինչև վերջ և սահմանում lastVerified-ը վերևում։ impersonation.mjs-ը ստացավ իրական բրաուզերային ծածկույթ 2026-08-21-ին (testImpersonationUi) — 2026-08-20-ին ավելացված կոճակ/երկխոսություն/բաններ/սեսիայի ավարտ հոսքը չուներ ոչ մի ծածկույթ, ոչ unit, ոչ e2e, մինչև այս փուլը. ֆայլի սեփական API-մակարդակի ստուգումները (սեսիայի ուղղակի սկիզբ/ավարտ) չեն փոխվել։ organizations.mjs-ը նաև ծածկում է աշխատանքային վահանակը (/org/[slug]/dashboard, 2026-08-12) — նախկինում այն միայն այցելվում էր որպես միջանկյալ կետ մյուս ներդիրներին հասնելու ճանապարհին, երբեք ինքնուրույն չստուգված. դիտողի սեփական դերի տողը, Members/Roles/Products դյուրանցման քարտերը, և որ թույլատրված քարտը իրականում սեղմումով անցնում է։ apps/portal/pages/org/[slug]/ dashboard.test.ts-ը (5 թեստ) ծածկում է նույն էջի իրավունքների սահմանափակումը՝ Products-ը ընդհանրապես ոչ մի սահմանափակում չունի (տեսանելի է ամեն աշխատատարածքի ամեն անդամի), մինչդեռ Members/Roles-ը մնում են մոխրագույն և ոչ սեղմելի առանց սեփական կարդալու իրավունքի։ Ավտոմատացմամբ չծածկված, արժե ձեռքով ստուգել — տես docs/MANUAL_TESTING.md. Google OAuth, երկու կազմակերպությունների միջև անցում, արխիվացված կազմակերպության վերականգնում, սեփականության փոխանցում, արդեն գոյություն ունեցող օգտատիրոջ կողմից հրավերի ընդունում (ավտոմատացված է միայն բոլորովին նոր օգտատիրոջ սցենարը), և գոյություն ունեցող դերի իրավունքների հավաքածուի խմբագրում (ավտոմատացված է միայն դերի նշանակումը անդամին)։

LoginForm.vue/RegisterForm.vue/pages/auth/[mode].vue (պորտալի թեստային ծածկույթի նախաձեռնության 51-րդ փուլ, 2026-08-12) — վերջին խոշոր էջերի ընտանիքը, որն ընդհանրապես unit-ծածկույթ չուներ, թեև auth.mjs-ն արդեն մանրակրկիտ վարժեցնում է այն կենդանի (տես վերևում)։ Նախ ստուգվեց առկա ծածկույթը՝ այս երկու ձևերի յուրաքանչյուր իրական ճյուղ արդեն կենդանի փորձարկվում է (գրանցում → հաստատում → մուտք, սխալ գաղտնաբառ, գաղտնաբառի վերականգնում, magic link, email OTP) — միակը, որ իսկապես չի կարող ավտոմատացվել ոչ մի դեպքում, Google OAuth-ն է (իրական արտաքին համաձայնության էկրան, նույն դասը, ինչ HR Pool-ի Turnstile-ը), ուստի նոր e2e չավելացվեց։ Փոխարենը՝ unit-ծածկույթ. apps/portal/components/auth/LoginForm.test.ts (12 թեստ)՝ գաղտնաբառով հաջող մուտք /dashboard-ի ուղղորդմամբ, emailNotVerified ճյուղը կրկին ուղարկման հղումով, կրկին ուղարկման հաջողություն/rate-limit, invalidCredentials-ը ցույց է տալիս ընդհանուր հաղորդագրություն (երբեք չբացահայտելով backend-ի սեփական տեքստը), ցանկացած այլ սխալ ընկնում է սերվերից ստացված հաղորդագրության վրա, magic link ուղարկման հաջողություն/rate-limit, OTP ուղարկում→ստուգում→ ուղղորդման ամբողջական ցիկլը և իր սեփական ձախողման ուղին, և որ Google-ի բաժանարարը/կոճակը ռենդերվում են միայն գաղտնաբառի ճյուղում։ apps/portal/components/auth/RegisterForm.test.ts (6 թեստ)՝ հաջող գրանցում կրկին ուղարկման հղումով, գրանցման rate-limit, արդեն գրանցված email-ի սխալը, և կրկին ուղարկման հաջողություն/rate-limit/չբացահայտել-այլ-սխալների-դեպքում ուղիները (նույն «երբեք չհաստատել կամ չհերքել հաշվի գոյությունը» պայմանագիրը, ինչ requestMagicLink/requestOtp-ինը)։ apps/portal/pages/auth/[mode].test.ts (3 թեստ)՝ երկու տեղադրված ձևերի միջև invisible/inert փոխարկումը և ներդիրի ընտրությամբ մյուս ռեժիմին անցումը։ Կրկին ուղարկման թեստերը գրելիս գտնվեց իրական, փոքր UI թերություն, չուղղված (հավելվածի կոդ, այս փուլի շրջանակից դուրս, նույն դասի գտածո, ինչ AlertDialogAction-ի auto-close մրցավազքը այս նախաձեռնության այլ վայրերում)՝ LoginForm.vue-ի onResendVerification()-ը երբեք չի վերականգնում սեփական resent-ը false-ի ֆունկցիայի սկզբում, միայն երբեք է սահմանում true հաջողության դեպքում — քանի որ template-ը ստուգում է v-if="resent"-ը v-else-if="resendError"-ից առաջ, ավելի վաղ հաջող կրկին ուղարկումից ՀԵՏՈ եկող rate-limited փորձը դեռ ցույց է տալիս հին «նամակն ուղարկված է» հաղորդագրությունը՝ rate-limit-ի փոխարեն։ Իրական հասանելիությունը փոքր է (կրկին ուղարկման կոճակն անջատված է ամբողջ cooldown-ի ընթացքում, այնպես որ սրան հասնելու համար պետք է 3+ իրական ուղարկում մեկ րոպեում) — բայց իրական անհամապատասխանություն է, ամրագրված սեփական թեստով, այլ ոչ թե լուռ շրջանցված։

/auth/forgot-password, /auth/reset-password (51-րդ փուլ, 2026-08-12, /auth/* ընտանիքի 2-րդ մասը) — auth.mjs-ի testPasswordReset()-ն արդեն վարժեցնում է ամբողջական կենդանի ցիկլը (հարցում → իրական հղում նամակում → հաստատում → հին գաղտնաբառը մերժվում է → նորը աշխատում է), ուստի այս փուլն էլ միայն unit է։ apps/portal/pages/auth/forgot-password.test.ts (5 թեստ)՝ հաջող հարցումը ցույց է տալիս «ուղարկված» վիճակը աշխատող կրկին ուղարկման հղումով, հարցման rate-limit, ցանկացած այլ սխալ ընկնում է սերվերի հաղորդագրության վրա, կրկին ուղարկումը նպատակադրվում է ՆՈՒՅՆ հասցեին, ինչ սկզբնական հարցումը, և «Վերադառնալ մուտք»-ը ճիշտ է անցնում։ apps/portal/pages/auth/reset-password.test.ts (4 թեստ)՝ ?token=-ի բացակայությունը ցույց է տալիս անվավեր հղման սխալը ցանկացած ձևի փոխարեն, հաջող հաստատումը ցույց է տալիս հաջողության վիճակը մուտքի հղումով, անվավեր/ժամկետանց token-ը ցույց է տալիս սերվերի սեփական հաղորդագրությունը, և հաղորդագրություն չունեցող սխալն ընկնում է ընդհանուր անվավեր-հղում տեքստի վրա։

/auth/magic-link, /auth/verify-email, /auth/callback, /auth/error, /auth/logout (53-րդ փուլ, 2026-08-12) — փակում է ամբողջ /auth/* ընտանիքը (51-53-րդ փուլեր)։ auth.mjs-ի testMagicLink()/testRegisterVerifyLogin()-ն արդեն վարժեցնում են յուրաքանչյուր էջի իրական happy path-ը կենդանի; այս փուլը ծածկում է այն ճյուղերը, որոնց այդ մեկանգամյա կենդանի փորձարկումները չեն հասնում՝ բացակայող/մերժված token-ներ, և returnTo-ի open-redirect պաշտպանությունը (utils/returnTo.ts-ի isSafeReturnTo, ընդհանուր magic-link.vue-ի և callback.vue-ի համար), որը ոչ magic link-ի, ոչ Google OAuth-ի սեփական կենդանի ստուգումը չի ստուգում ոչ մի ուղղությամբ։ apps/portal/pages/auth/magic-link.test.ts (5 թեստ)՝ բացակայող token, վավեր token-ով մուտք և ուղղորդում /dashboard, անվտանգ returnTo-ն ուղղորդում է այնտեղ փոխարենը, անանվտանգը (//evil.example.com) հետ է գլորվում /dashboard՝ փոխանակ հետևելու դրան, և մերժված token։ apps/portal/pages/auth/verify-email.test.ts (4 թեստ)՝ բացակայող token, հաջողություն, սերվերի սեփական մերժման հաղորդագրությունը, և հաղորդագրություն չունեցող սխալի ընդհանուր fallback-ը։ apps/portal/pages/auth/callback.test.ts (4 թեստ)՝ Google OAuth-ի վայրէջքի էջը՝ accessToken/refreshToken-ի բացակայությունը ուղղորդում է /auth/error՝ մուտքի փորձի փոխարեն, իրական token-ները մուտք են գործացնում և ուղղորդում /dashboard, նույն անվտանգ/անանվտանգ returnTo զույգը, ինչ magic-link-ինը։ Ինքը՝ Google OAuth-ը, մնում է ամբողջ ընտանիքի միակ ճյուղը, որն իսկապես չի կարող ստուգվել կենդանի (իրական արտաքին համաձայնության էկրան, նույն դասը, ինչ HR Pool-ի Turnstile-ը) — այս էջը ծածկում է ճիշտ այն, ինչ մնում է դրանից հետո։ apps/portal/pages/auth/error.test.ts (1 թեստ)՝ OAuth-սխալի ստատիկ վայրէջքի էջն ընդհանրապես տրամաբանություն չունի, պարզապես render smoke-թեստ։ apps/portal/pages/auth/logout.test.ts (2 թեստ)՝ useCurrentUser().reset()-ը և վերջնական navigateTo('/')-ը երկուսն էլ գործարկվում են mount-ի ժամանակ, ներառյալ երբ logout հարցումն ինքնին ձախողվում է (ոչ մեկը տեսանելի չէ կենդանի ստուգմանը, որը դիտում է միայն ցանցային հարցման հաջողությունը)։

/account/profile-ը (ընդհանրապես ծածկույթ չուներ՝ ոչ միավոր, ոչ կենդանի, մինչև 2026-08-12-ը) — scripts/e2e/menu/account.mjs (4 ստուգում, փուլային մոտեցում, մեկ /account/* էջ մեկ անգամում՝ notifications.vue/api-tokens.vue-ն յուրաքանչյուրն իր սեփական ապագա փուլն է) խմբագրում է Ցուցադրվող անունը, պահպանում, հաստատում հաջողության toast-ը, ապա նորից բեռնում ԶՐՈՅԻՑ և կարդում դաշտը հետ՝ հաստատելու համար, որ այն իրականում պահպանվել է (ոչ միայն որ toast-ը հայտնվեց), և հետո նույն կերպ վերականգնում է սկզբնական արժեքը, որպեսզի այս վազքը չթողնի ընդհանուր e2e-test-admin հաշվի սեփական անունը փոփոխված վազքերի միջև։ Ուղեկցող միավոր-ծածկույթը, apps/portal/pages/account/profile.test.ts (9 թեստ) — ձևի վերականգնումը իրական պրոֆիլի արժեքներին բեռնման ժամանակ, չսահմանված ժամային գոտին լռելյայն վերցնում է հայտնաբերված գոտին ընդդեմ իրական, արդեն սահմանվածի պահպանման, onSubmit-ի payload-ի կառուցումը (null, ոչ թե ''/undefined, մաքրված դաշտի համար, և interestAreaOther-ը միայն երբ OTHER-ը interestAreas-ի մեջ է), ձախողված պահպանման inline+toast սխալը, հերթագրված avatar փոփոխությունը, որը կանչում է removeAvatar/uploadAvatar պահպանման ժամանակ (վերջինիս անհրաժեշտ եղավ իր սեփական fetch mock-ը՝ այս նախաձեռնության երկրորդ ձեռքով-վերբեռնող էջը Shared Documents-ի XHR տարբերակի կողքին), և «Ավտո» ժամային գոտու տարբերակը, որը լուծվում է իրական հայտնաբերված գոտուն։ Այս նախաձեռնության առաջին էջն է, որին անհրաժեշտ էր ԻՐԱԿԱՆ useCurrentUser()-ը (ոչ թե փոքր ընդհանուր թեստային fake-ը, որն օգտագործում է ամեն /team/* էջ) — դրա updateProfile/uploadAvatar/removeAvatar/loaded վիճակը ընդհանրապես չկան այդ fake-ում։

/account/api-tokens-ը («Կապակցված հավելվածներ» — միայն կարդալ/չեղարկել, ինքնասպասարկման ստեղծումը հեռացվել է, երբ OAuth 2.1-ը փոխարինեց այն, docs/mcp/ADR-001-external-mcp-server.md Որոշում 5) — account.mjs-ը հասավ 6 ստուգման։ Իրական սխալ գտնվեց առաջին կենդանի վազքի ժամանակ (2026-08-12, ուղղվեց նույն օրը, օգտատիրոջ հաստատմամբ). GET /me/personal-access-tokens-ը 500 էր տալիս այս dev ԲԴ-ի վրա — երկու միգրացիա (add_personal_access_tokens, oauth_authorization_server) գոյություն ունեին repository-ում, բայց երբեք իրականում կիրառված չէին այստեղ, այնպես որ PersonalAccessToken/OAuthClient/OAuthAuthorizationCode/OAuthRefreshToken աղյուսակները իրականում գոյություն չունեին։ Ամբողջ OAuth 2.1 authorization server ֆունկցիան երբեք չէր գործարկվել իրական dev ԲԴ-ի դեմ մինչև այս փուլը — ուղղվեց pnpm --filter @p4p/database migrate:dev-ով։ Ֆայլն այժմ smoke-test է անում, որ էջը բեռնում է իրական 200 այժմ աշխատող endpoint-ի դեմ; e2e-test-admin-ի համար դեռ գոյություն չունի իրական OAuth-կապակցված հավելված, որը կենդանի կերպով կարելի լինի ցուցակագրել/չեղարկել, և մեկի ստեղծումը կենդանի կերպով պահանջում է DCR + PKCE + համաձայնության էջի ամբողջ հոսքը (/oauth/authorize) — անհամաչափ ծախս այս փուլի համար, նույն որոշումը, ինչ HR Pool-ի ինքնասպասարկման ստեղծման կենդանի բացթողումը այս նախաձեռնության այլ վայրերում։ Ինքը՝ չեղարկման հոսքը, ծածկված է միավոր-թեստերով. apps/portal/pages/account/api-tokens.test.ts (7 թեստ) — իրական տվյալների render (oauthClientName-ի նախապատվությունը սեփական name-ի փոխարեն), «Երբեք չի օգտագործվել» ընդդեմ իրական ամսաթվի, դատարկ վիճակը, բեռնման սխալը, և հաջողված/ձախողված չեղարկումը։

/oauth/authorize-ը (OAuth 2.1 համաձայնության էկրանը, docs/mcp/ADR-001-external-mcp-server.md Որոշում 5) — ավելի ուշ ստացավ ամբողջական կենդանի գործարկումը, որը 40-րդ փուլն անվանել էր անհամաչափ. scripts/e2e/menu/oauth-authorize.mjs (10 ստուգում, նոր ֆայլ, 2026-08-12) ամբողջ հոսքի ԱՌԱՋԻՆ end-to-end գործարկումն է երբևէ, ցանկացած միջավայրում, որին այս նախաձեռնությունը դիպել է՝ դինամիկ հաճախորդի գրանցում (RFC 7591, առանց հաստատման քայլի, առանց client secret-ի տրամադրման), պորտալի սեփական սեսիա-վավերացված համաձայնության էկրանը (իրական հաճախորդի անուն և պահանջված scope ցուցադրվում է), հաստատում և իրական authorization code ստանալը, PKCE-ստուգված token-ի փոխանակումը (և հաստատում, որ ՍԽԱԼ code_verifier-ն իրականում մերժվում է, ոչ միայն ընդունվում և անտեսվում), ստացված token-ի հայտնվելը որպես իրական «Կապակցված հավելված» /account/api-tokens-ում — փակելով շրջանը 40-րդ փուլի հետ — և այնտեղ դրա չեղարկումը նույն UI հոսքով, որը 40-րդ փուլն արդեն ապացուցել է։ Բոլոր 10 ստուգումներն անցան մաքուր հենց առաջին կենդանի գործարկումից. ֆունկցիան իրականում աշխատում է, հենց որ ուղղվեց դրա միգրացիայի բացը (փուլ 40)։ Մեկ իրական e2e-սկրիպտի նրբություն գտնվեց և ուղղվեց սա գրելիս. Հաստատել-ի սեղմումը գործարկում է իրական window.location.href վերահղում հենց այն պահին, երբ պատասխանը հասնում է, ինչը անվավեր է դարձնում Chrome DevTools Protocol-ի handle-ը այդ նույն պատասխանի վրա նախքան սովորական waitForResponse(...).json()-ը կկարողանա այն կարդալ («No resource with given identifier found») — ուղղվեց հարցում/պատասխան զույգը page.route()-ի միջոցով ընդհատելով, որը կարդում է մարմինը ՆԱԽՔԱՆ էջի սեփական JS-ը երբևէ այն տեսնի, և առանձին ամբողջովին արգելափակելով իրական արտաքին վերահղումը (այս կեղծ հաճախորդի domain-ը գոյություն չունի), այնպես որ էջն իրականում երբեք չի փորձում հեռանալ։ Ուղեկցող միավոր-ծածկույթը, apps/portal/pages/oauth/authorize.test.ts (9 թեստ) — այս նախաձեռնության առաջին փուլն է առանց team-stubs.ts/org-stubs.ts ոճի իրավունքների fake-ի (այս էջին անհրաժեշտ է միայն մերկ useAuth().isAuthenticated, իր սեփական փոքր տեղական mock-ը). վերահղում մուտքի էջին returnTo-ով, երբ դուրս է եկած (նույնիսկ չհասնելով consent-info կանչին), սխալ հարցման սխալը բացակայող պարտադիր query պարամետրի համար, իրական consent info-ի render scope-ի հուշումներով (չմապավորված scope-ը հետ է գնում սեփական scope տողին), «scope-եր չեն պահանջվել» ճշմարիտ-դատարկ վիճակը, բեռնման սխալ, decide(true)-ը, որն ուղարկում է ամբողջական PKCE payload-ը և վերահղում դեպի իրական callback-ը window.location.href-ի միջոցով (անհրաժեշտ եղավ իր սեփական Object.defineProperty mock-ը, նույն տեխնիկան, որ օգտագործեց փուլ 46-ի mcp/index.test.ts-ը՝ այս նախաձեռնության երկրորդ թեստը, որին անհրաժեշտ էր մոկավորել իրական բրաուզերի navigation), decide(false)-ը, որն ուղարկում է approved: false, և ձախողված approve/deny-ը, որը զրոյացնում է deciding դրոշը։