Commit Graph
3 Commits
Author SHA1 Message Date
JiriUhlirandClaude Opus 5 e7cf499a0b Cely navrh rozsireni: role, firmy, typy ticketu, akce, widgety, audit
Implementace vsech bodu z documentation/09-navrh-rozsireni.md. Vsechno lezi
v obecnem ulozisti, ktere umi Postgres i JSON soubor.

Zaklad, aby se nepsalo osmkrat totez:
- src/data/store/: jedno rozhrani EntityStore, dve implementace (local se
  souborem nebo pameti, postgres nad tabulkou records). Vyber je na jednom
  miste v store/index.ts
- src/data/store/cached.ts: synchronni kopie v pameti pro entity ctene pri
  kazdem requestu (uzivatel v autorizaci, firmy pri vypoctu prav). Bez toho by
  se autorizacni middleware musel predelat na async
- src/routes/crud.ts: fabrika na CRUD routy. Kazda entita by jinak znamenala
  stejnych sto radku a sedmkrat by se opravila spatne
- src/data/bootstrap.ts: jedno misto, kde je seznam entit a jejich vychozi sady
- migrace 002_records.sql: jedna tabulka s JSONB. Tvary se jeste hybou a nikdo
  se nad nimi nedotazuje po polich. Az se to usadi, entita se povysi na vlastni
  tabulku, presne jako uz maji konektory

Prava a role (bod 5):
- role jsou zaznamy, pravo je retezec, katalog prav je zdroj pravdy. Union
  'admin' | 'agent' na ucetni a skladnika nestacil a pridavat hodnoty je slepa
  ulicka, kazdy klient chce jine
- Membership.roleIds misto role. Systemove role admin a agent zustavaji, takze
  se zadny ucet nemusel predelavat
- accessFor vraci prava i zalozky. Klient si nic nedovozuje

Zalozky a limity za firmu (bod 6):
- TenantFeatures: moduly, limity, zpristupnene sluzby. Dve vrstvy s jinym
  vlastnikem, ktere se nesmi michat: co ma firma zaplacene nastavujeme my,
  kdo z jejich lidi to smi nastavuje jejich admin. Efektivni viditelnost je
  prunik, takze vypnuty modul neexistuje ani pro admina te firmy
- navigace ze serveru, ne konstanta na klientovi

Firmy, uzivatele, resitele a skupiny: CRUD vcetne clenstvi a hesel. Heslo se
z API nikdy nevraci, ani jako hash. Skupiny resitelu kvuli tomu, ze prehazovat
praci na jmeno nestaci - clovek chce rict "tohle je pro ucetni".

Typy ticketu a akce (body 1, 2, 3):
- typ ticketu s vlastnimi polemi, plus tagy. Akce se vazou na typ nebo tag,
  ale za tagem nestoji zadna pole, takze akce na tagu umi jen vestavena pole
- Ticket dostal typeId, fields, tags a assigneeGroupId
- definice akce s telem jako operace, strom nebo skript. Pravo vznika spolu
  s akci jako action:<id>, admin pak zaskrtava akce, ne prava
- CTA na ticketu filtruje server podle typu, tagu, podminek a prav. Kdyby to
  pocital klient, pocitalo by se to na dvou mistech
- vestavene akce (typ, tagy, skupina) jdou pres tutez fabriku, takze maji
  svoje pravo a projdou auditem
- spusteni zapise do logu ticketu hned, jeste nez se neco stane

Vlastni widgety (bod 4):
- rozdeleni na render a source, groupBy, filtr je tentyz, ktery umi seznam
  ticketu. Uzivatel nepise dotazy
- jeden batch endpoint na cely prehled. Widget, ktery selze, vraci chybu na sve
  pozici a nezhasne prehled

Audit a impersonace (bod 6c):
- audit zapisuje i odepreni, jinak by pokusy o cizi firmu nikde nezustaly
- impersonace: jen spravce platformy, nikdy na jineho spravce platformy,
  30 minut bez obnoveni, vychozi jen cteni. Zapis pod rezimem cteni vraci 403
  na urovni middleware, ne az v handleru

Overeno bez databaze: vsech devet ulozist se nacte, role se zaloz1 a prezije
restart, agent dostane 403 na spravu roli a uzsi navigaci, neznama prava se
odmitnou, heslo se nevraci, typ a tagy ticketu se ulozi, CTA se objevi, widget
data pocitaji vcetne seskupeni, impersonace odmitne zapis i prepnuti na admina,
audit obsahuje actedBy. Degradace pri nedostupne databazi taky overena: migrace
selzou, jede se do souboru a rekne se proc.

Neovereno: migrace 002_records.sql proti zive databazi. Kontejner uz nebyl
k dispozici, generickou vrstvu drzi tentyz pool a migrator jako konektory.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 07:06:38 +02:00
JiriUhlirandClaude Opus 5 2a3d75c85e Firmy a prava: tenance napric portalem
Portal nemel zadnou tenanci. Kterykoliv prihlaseny uzivatel videl vsechny
tickety vsech firem i cely seznam resitelu, requireRole se nikde nevolal.

Tenant je hranice viditelnosti, tenantId na ticketu, resiteli i automatizaci.
Uzivatel muze patrit do vic firem, v kazde s jinou roli. Pristup napric firmami
je zvlast jako platformAdmin.

Tri pohledy na tickety: all, tenant, mine. Admin mezi nimi prepina vcetne
vyberu firmy. O pravech rozhoduje jedine data/access.ts, klient si nic
nedovozuje a bere je z GET /api/dashboard/access.

Filtr na firmu je v ulozistich povinny argument, takze zapomenuty filtr
neznamena vse, ale nezkompiluje se. Cizi firma vraci 403 nebo 404, nikdy
tise zuzeny vysledek.

Prirazeni jen v ramci firmy. Prehazovat praci mezi lidmi smi jen admin,
agent si smi vzit ticket na sebe.

Zmena prihlasovani: ucet klient@firma.cz zanikl, demo ucty jsou nove.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 12:59:30 +02:00
JiriUhlir 7b045a9f20 Nahrazeni sablony kompletnim webem a klientskym portalem
Web a portal Automia v jednom containeru. Express obsluhuje API
i zbuildovanou React aplikaci z dist/public.

Obsah:
- verejny web: homepage, sluzby, o nas, kontakt, 404
- prihlaseni pres JWT, demo ucty
- portal: prehled s grafem, tickety, incidenty, automatizace, konektory
- builder automatizaci: strom akci, vetveni podminkou
- katalog 25 konektoru v 8 kategoriich
- webhook s registrovanou adresou, token generuje server
- zivy dashboard pres SSE vcetne simulace provozu
- Swagger UI na /docs a OpenAPI na /openapi.json

Soulad s AGENTS.md:
- ROOT_PATH z prostredi, prefix proxy nikde nehardcodovan
- mount na koren i na prefix, funguje s handle_path i bez nej
- base tag a window.__BASE_PATH__ vkladane do index.html za behu
- OpenAPI servers obsahuje prefix, Try it out vola spravnou adresu
- povinne /health a /docs, port 3000, naslouchani na 0.0.0.0
- secrets jen z environment variables, nikdy v logu

Dokumentace ve slozce documentation/.
2026-07-31 17:00:37 +02:00