Revize projektu: prava, vykon, runtime, portal a ARES

Prava a bezpecnost: spravce firmy uz nemuze nastavit priznak spravce
platformy ani clenstvi v cizi firme; pozvanky, konektory a automatizace
kontroluji sve pravo; cizi firma v query je 404; zivy stream posila
udalosti jen firmam, kterych se tykaji; akce nad ticketem maji kontrolu
prava za firmu ticketu a strop viditelnosti; tokeny se nelogujou; limit
pokusu na prihlaseni, kontakt a pozvanky; bezpecnostni hlavicky;
zachyceni chyb v async handlerech; timing-safe porovnani tokenu.

Vykon: audit neskenuje celou kolekci pri kazdem zapisu a konecne maze
firemni zaznamy; ticket se uklada jednou misto trikrat; zapisy do
Postgresu jsou serializovane podle ID; prava se pocitaji jednou na
request; widgety nacitaji tickety jednou; strankovani seznamu; worker
je pool misto kol; na webu udalost ze streamu neodmontuje stranku,
dotazy maji spolecny debounce a cache, ciselniky drzi typovany sklad.

Runtime: opakuji se jen chyby oznacene retryable; smycka nenarazi na
strop 50 kroku (novy strop 1000 akci); podminka nad datem funguje;
vystup MCP nastroje neprepisuje spoustec; sandbox skriptu firmy nejde
opustit; MCP session id se drzi mezi volanimi; incident z kroku patri
firme; jedno rozhodnuti o rezimu uloziste; snapshot neprepise soubor
po chybe cteni.

Refaktory: sdilene typy API v src/shared (web nic nekopiruje, osm
rozjetych tvaru sjednoceno); spolecny modul net/guard pro volani ven;
formularova vrstva ui/form; rozdeleni Connectors a FlowCanvas; jeden
helper pro firmu z query, validaci a CRUD udalosti; pomucky ctx.util
pro skripty konektoru; i18n verejneho webu vcetne anglictiny.

Nova funkce: zalozeni firmy z registru ARES v Nastaveni (IC nebo nazev,
dotazeni IC, DIC, sidla a pravni formy, vyber soucasnych statutarnich
zastupcu a prokury, ucty spravce firmy s nahradnim e-mailem
IC-poradi@placeholder.cz).

Dokumentace: zaznam v 99-zmeny.md a aktualizace 15 dalsich dokumentu.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
JiriUhlir
2026-09-09 10:26:07 +02:00
co-authored by Claude Fable 5.1
parent 0c405ea55a
commit 104ae36783
215 changed files with 13226 additions and 8320 deletions
+19 -35
View File
@@ -6,32 +6,10 @@
* `platformAdmin` - to je nase pravo, ne zakaznicke.
*/
/**
* Clenstvi ve firme.
*
* `roleIds` je seznam, ne jedna role. Duvod: `'admin' | 'agent'` na ucetni,
* skladnika a vedouciho nestacilo a pridavat dalsi hodnoty do unionu je slepa
* ulicka, kazdy klient chce jine. Role jsou proto zaznamy, viz `data/permissions.ts`.
*
* Odkaz smi byt ID role, nebo klic systemove role (`admin`, `agent`), aby slo
* zapsat oboji a stara data dal fungovala.
*/
export interface Membership {
tenantId: string;
roleIds: string[];
/**
* Vidi vsechny tickety firmy, ne jen svoje a svych sekci.
*
* Je to **postaveni uctu ve firme**, ne vlastnost resitele, proto to visi
* tady a ne na `Person`: clovek muze byt ve dvou firmach jednou reditel
* a jednou brigadnik.
*
* `undefined` u zaznamu ulozenych driv. Co pak plati, resi `visibilityFor`
* v data/access.ts - nemuze to byt tise `false`, jinak by pri nasazeni
* kazdemu spravci zmizela vetsina ticketu.
*/
seesAllTenant?: boolean;
}
import type { Membership, PublicUser } from './shared/users.js';
/** Clenstvi a verejny tvar uctu jsou sdilene s webem, viz src/shared/users.ts. */
export type { Membership, PublicUser };
export interface User {
id: string;
@@ -44,15 +22,6 @@ export interface User {
memberships: Membership[];
}
/** Verze uzivatele bezpecna pro odeslani na klienta. */
export interface PublicUser {
id: string;
email: string;
name: string;
platformAdmin: boolean;
memberships: Membership[];
}
export interface JwtPayload {
sub: string;
email: string;
@@ -66,6 +35,21 @@ export interface JwtPayload {
writes?: boolean;
}
/**
* Prava spocitana jednou za request, viz `middleware/tenant.ts`.
*
* Doplnek k `req.user` z `middleware/auth.ts`. Jen typ, zadny kod - proto
* import typu, ne modulu.
*/
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Express {
interface Request {
access?: import('./data/access.js').Access;
}
}
}
export function toPublicUser(user: User): PublicUser {
const { passwordHash: _passwordHash, ...rest } = user;
return rest;