Tutorial - 45 min

Zbuduj swoją pierwszą aplikację

Pod koniec tego tutoriala będziesz mieć mały CRM z trzema tabelami (company, contact, deal), stroną listy i szczegółów dla każdej, Business Event, który auto-stempluje updated_at deala, oraz Script Module, który przelicza sumę wartości otwartych deali firmy za każdym razem, gdy deal się zmieni. Każda koncepcja z Core concepts pojawia się co najmniej raz.

Zakłada, że skończyłeś Pierwsze kroki i masz otwarte środowisko Archestack w innej karcie. Całkowity czas: około 45 minut, jeśli czytasz uważnie, 25 jeśli przeglądasz.

Stosowane tutaj konwencje: nazwy tabel i kolumn są snake_case (platforma sugeruje tę konwencję w polu "Table name" w Schema Designer). Przykłady kodu używają prawdziwego API Db, zobacz Reference -> Script-callable APIs dla pełnej powierzchni.

Krok 1 - Zaprojektuj schemę (10 min)

Otwórz Schema Designer i dodaj trzy tabele.

Dla każdej tabeli: kliknij Add Table na pasku narzędzi, wpisz nazwę w polu "Table name" okna dialogowego, kliknij Create. Nowa tabela pojawi się na kanwie z auto-wygenerowanym kluczem głównym id SERIAL (zablokowanym). Prawy panel otworzy się na karcie Columns, dodaj dodatkowe kolumny z ramki "Add column" z przerywanym obramowaniem na dole. Kliknij każdą kolumnę, aby ją rozwinąć i dostosować przełączniki (PK / NULL / UQ), Length i wartość Default.

Tabela: company

  • id - SERIAL, PK (auto)
  • name - VARCHAR(200), required
  • industry - VARCHAR(80), nullable
  • open_deal_value - DECIMAL, default 0 - utrzymywana w synchronizacji przez skrypt w Kroku 5
  • created_at - TIMESTAMPTZ, default now()

Tabela: contact

  • id - SERIAL, PK (auto)
  • first_name, last_name - VARCHAR(100), required
  • email - VARCHAR(200), required, UQ on
  • company_id - INTEGER, required - klucz obcy, konfigurowany dalej

Tabela: deal

  • id - SERIAL, PK (auto)
  • company_id - INTEGER, required - klucz obcy, konfigurowany dalej
  • title - VARCHAR(200), required
  • stage - VARCHAR(40), required, default 'New' - wartości: New, Qualified, Proposal, Won, Lost
  • amount - DECIMAL, required, default 0
  • created_at, updated_at - TIMESTAMPTZ, default now()

Klucze obce

Klucze obce żyją w karcie Relations prawego panelu. Wybierz tabelę contact, przełącz na Relations, przewiń do sekcji "Add relationship":

  1. FK column (na tej tabeli) = company_id
  2. Relation type = One-to-Many
  3. References -> table = company
  4. References -> column = id
  5. Kliknij Add Relationship.

Powtórz dla tabeli deal (jej company_id -> company.id).

Kanwa Schema Designer z kilkoma tabelami połączonymi liniami FK. Pasek narzędzi u góry ma karty Canvas/JSON, rozwijaną listę Packages, wyszukiwarkę Find table, kontrolki zoom, a po prawej: + (Add Table), Add Group, Add Text, Save, JSON/code, Deploy (zielona rakieta).
Jak wygląda kanwa, gdy masz kilka tabel z relacjami. Pasek narzędzi (góra) ma karty Canvas / JSON, filtr Packages, wyszukiwarkę Find-table, kontrolki zoom, a po prawej ikony-przyciski + (Add Table), Add Group, Add Text, Save, JSON i zieloną rakietę Deploy. Kolumny FK pokazują ikonę chain-link obok swojego typu, a relacje renderują się jako kolorowe linie między tabelami. (Pokazany przykład używa innych tabel niż ten tutorial, twój układ company / contact / deal będzie wyglądał w tym samym kształcie z dwiema liniami FK wskazującymi na company.)

Deploy

Kliknij Deploy na pasku narzędzi Schema Designer. Lądujesz na stronie konfiguracji wdrożenia. Przełącz się na kartę Generated SQL, powinieneś zobaczyć trzy instrukcje CREATE TABLE plus ograniczenia FK. Kliknij Deploy w prawym górnym rogu.

Co zobaczysz, jeśli się uda: wiersz wdrożenia w Database Deployments -> Overview przechodzi z "Executing" do "Succeeded" w ciągu kilku sekund. Trzy tabele pojawiają się na liście tabel Object Browser.

Jeśli deploy zawiedzie na ograniczeniach FK: Generated SQL emituje tabele w kolejności, w której zostały zapisane. Otwórz kartę SQL i zmień kolejność tak, aby company była tworzona przed contact i deal, a następnie wdróż ponownie. Lub kliknij Regenerate po ręcznym przestawieniu tabel na kanwie Schema Designer.

Krok 2 - Skomponuj Business Entities (10 min)

Każda strona potrzebuje Business Entity, z którym się zwiąże. Otwórz Business Entities i kliknij Create dla każdej. Naciśnij Run Preview po każdym zapisie, aby potwierdzić, że kolumny wracają poprawnie.

BE: company

Entity Name company, Master Table company, Label Column name. Zapisz.

Kliknij Add Join dwa razy, aby dodać dwa agregowane joiny:

  • Join do contact: From column company.id, To column contact.company_id. Włącz Aggregate Mode. Wybierz kolumnę id, ustaw Aggregate Function = COUNT, nazwij ją contact_count.
  • Join do deal: From column company.id, To column deal.company_id. Aggregate Mode włączony. Wybierz kolumnę id, funkcja COUNT, nazwij ją open_deal_count. (W Kroku 5 odfiltrujemy do "otwartych" deali przez Business Event; na razie liczy to wszystkie deale.)

BE: contact

Entity Name contact, Master Table contact, Label Column email. Dodaj Join do company przez contact.company_id -> company.id, wystaw kolumnę name jako company_name. (Nie włączaj tutaj Aggregate Mode, to normalny join.)

BE: deal

Entity Name deal, Master Table deal, Label Column title. Dodaj Join do company przez deal.company_id -> company.id, wystaw kolumnę name jako company_name.

Zweryfikuj: na każdym BE kliknij Run Preview. Zobaczysz pustą siatkę (jeszcze bez danych) z nagłówkami kolumn, które zdefiniowałeś. Jeśli brakuje nagłówka kolumny join, prawdopodobnie zapomniałeś zaznaczyć kolumnę w pickerze kolumn join. Otwórz ponownie join, zaznacz kolumnę, zapisz, uruchom preview ponownie.

Krok 3 - Zbuduj strony (10 min)

Otwórz Page Editor. Dla każdego Business Entity kliknij Create:

  1. Companies - Page Name Companies, Page Route /companies, Business Entity company. Karta Visual auto-generuje listę i formularz szczegółów. W formularzu szczegółów kliknij Add Tab dwa razy, aby dodać karty Contacts i Deals. W każdej karcie dodaj sekcję RelatedGrid powiązaną z BE contact / deal z filtrem join ustawionym na company.id = id aktualnego rekordu.
  2. Contacts - Page Name Contacts, Page Route /contacts, Business Entity contact. Pole company_id w auto-wygenerowanym formularzu szczegółów pojawi się jako liczba, zmień jego Type na Select i ustaw autocomplete Entity na company, aby użytkownicy wybierali firmę po nazwie.
  3. Deals - Page Name Deals, Page Route /deals, Business Entity deal. To samo traktowanie dla company_id (Type Select, Entity company). Dla stage na razie zostaw Type jako Text, wartości można wymusić przez event Validate później, jeśli chcesz.

Dla każdej strony przełącz Switch Published w nagłówku u góry na ON. Strony pojawią się w pasku bocznym pod sekcją APPLICATION (pogrupowane według kategorii). Dodaj Company, potem Contact powiązany z tą Company, potem Deal, potwierdź, że relacje renderują się poprawnie. Strona Companies powinna teraz pokazywać 1 w contact_count.

Opublikowana strona dla końcowego użytkownika z breadcrumbami (Home / Customers / Record #9), przyciskiem Edit w prawym górnym rogu, wieloma kartami (Details, Vehicles, Address & Contact, Open service orders, Closed Service orders), formularzem Properties z inline ikonami edycji na każdym polu i siatką powiązanych danych (Vehicles) pod formularzem.
Jak wygląda opublikowana strona w runtime. Pokazany przykład to strona Customer z innej domeny (DMS), ale kształt jest dokładnie tym, co wyprodukuje twoja strona company. Uwaga: sekcja APPLICATION paska bocznego pojawia się, gdy tylko opublikujesz, strony są pogrupowane pod nagłówkiem kategorii (tutaj: CUSTOMER PORTAL). Panel szczegółów renderuje breadcrumby, przycisk Edit (prawy górny róg), ikony ołówka na każdym polu do edycji inline, dodatkowe karty u góry (Details / Vehicles / itd.) oraz pod formularzem sekcję powiązanej siatki pobierającą wiersze z innego BE filtrowane przez aktualny rekord. Badge dzwonka ("1") pokazuje, że jest nieprzeczytane niepowodzenie z Event Log.
Jeśli coś wygląda pusto: najczęstszą przyczyną jest zapomnienie o przełączeniu Switcha Published, jeśli jest OFF, nawigacja do /companies w pasku bocznym nic nie pokazuje. Przełącz go na ON i odśwież.

Krok 4 - Wyczyść pole przy zapisie za pomocą Business Event (5 min)

Business Events uruchamiają trochę logiki, gdy tylko rekord jest zapisywany. Najmniejszy użyteczny: przycinanie zbędnych spacji z title deala przy każdym zapisie, tak aby " Acme renewal " trafiło jako "Acme renewal". Zróbmy to.

Dla created_at / updated_at / created_by / updated_by nigdy nie potrzebujesz reguły. Archestack dodaje te cztery kolumny audytowe do każdej tabeli i stempluje je przy każdym insercie i update automatycznie, więc trigger "stempluj updated_at" tylko powielałby pracę, którą platforma już wykonuje.
  1. Otwórz Business Events -> Create.
  2. Rule Name: Normalize deal.title. Przełącz Enabled na ON.
  3. Business Entity: deal. Triggers: zaznacz Before Update.
  4. Bez warunków, odpalaj przy każdym update.
  5. Dodaj akcję: wybierz Execute Script. Ciało skryptu akcji:
    string title = Entity.title;
    Entity.title = title?.Trim();
  6. Kliknij kartę Simulate -> wybierz dowolny istniejący Deal -> kliknij Run Simulation. Panel wyjścia pokazuje, że skrypt uruchomił się pomyślnie i na co Entity.title zostało ustawione. (Nie dzieje się żaden prawdziwy zapis, symulacja uruchamia się w cofniętej transakcji.)
  7. Zapisz. Przetestuj, edytując Deal z wiodącymi lub końcowymi spacjami w tytule, tytuł powinien wracać przycięty przy każdym zapisie.
Dlaczego Before Update + Execute Script zamiast akcji, która "ustawia pole"? Archestack nie ma osobnej akcji "Set field". Sposób, w jaki mutujesz rekord z triggera, to przypisanie do Entity.column_name wewnątrz Execute Script na timingu Before*. Platforma utrwala zmodyfikowane Entity z powrotem jako część zapisu w locie, bez dodatkowego zapytania, bez ryzyka rekurencji.

Krok 5 - Przelicz company.open_deal_value przez Script Module (10 min)

Obliczona suma jak "wartość otwartych deali per firma" jest zbyt dynamiczna, by przechowywana kolumna pozostała dokładna ręcznie. Utrzymamy ją w synchronizacji małym skryptem, który uruchamia się ponownie zawsze, gdy jakikolwiek deal w firmie jest wstawiany, aktualizowany lub usuwany.

Napisz skrypt

Otwórz Script Modules -> Create. Nazwij to RecalcCompanyOpenDealValue.

Przełącz się na kartę Parameters. Kliknij Add. Name company_id, Type int, Required zaznaczone.

Wróć do karty Edit. Ciało:

var openDeals = await Db.From("deal")
    .Where("company_id", "=", company_id)
    .Where("stage", "!=", "Won")
    .Where("stage", "!=", "Lost")
    .ToListAsync();

decimal total = 0;
foreach (var d in openDeals) total += (decimal)(d.amount ?? 0);

await Db.UpdateAsync("company", company_id, new { open_deal_value = total });

return total;

Przełącz się na kartę Test. Wpisz prawdziwe company_id z twojej strony Companies w input parametru, kliknij Run. Wyjście pokazuje wartość zwracaną (sumę) i wskaźnik sukcesu. Przeładuj stronę Companies, open_deal_value na tej firmie jest teraz w synchronizacji.

Typowe potknięcia:
  • Zapomnienie await na .ToListAsync(), skrypt kompiluje się, ale openDeals kończy z Task, nie z wierszami. Błąd w panelu Test wspomni o "cannot be enumerated".
  • Użycie Db.Query zamiast Db.From, nie ma metody Query. Trzymaj się Db.From(table) dla łańcuchowanych zapytań i Db.GetAsync(table, id) dla pojedynczego wiersza po PK.
  • Próba .SumAsync(...), nie istnieje. Pobierz + zsumuj w C#, jak powyżej.

Podłącz to do Business Event

  1. Otwórz Business Events -> Create.
  2. Rule Name: Recalc company.open_deal_value on deal change. Enabled ON.
  3. Business Entity: deal. Triggers: zaznacz After Create, After Update i Before Delete.
  4. Bez warunków, odpalaj przy każdej zmianie.
  5. Dodaj akcję: Execute Script. Ciało:
    var entity = OldEntity != null && OldEntity.company_id != null
        ? OldEntity      // for delete & update, OldEntity has the original company_id
        : Entity;        // for create, only Entity is populated
    
    await Modules.CallAsync("RecalcCompanyOpenDealValue", new Dictionary<string, object?> {
        ["company_id"] = entity.company_id
    });
  6. Zapisz. Edytuj amount jakiegoś Deala i przeładuj stronę Company, suma pozostaje w synchronizacji.
Dlaczego wywołać to przez Modules zamiast inline'ować logikę w skrypcie tego triggera? Dwa powody. Po pierwsze, przeliczenie jest wielokrotnego użytku, możesz wywołać je też ze Scheduled Event (nocne dogonienie) lub bezpośrednio z frontendu. Po drugie, izoluje to logikę w jednym nazwanym miejscu, łatwiej testować, łatwiej znaleźć później.

Krok 6 - Spakuj to jako package (5 min)

Zbudowałeś prawdziwy, działający mini-CRM. Spakuj go, abyś mógł przenieść go do innego środowiska.

  1. Otwórz Packages -> Create. Nazwij to MiniCRM v1.
  2. Dodaj trzy strony. Otwórz panel linked-items, aby zobaczyć kaskadę: package pociągnie BE, do których strony się odwołują, tabele źródłowe, z których te BE czytają, plus dwa Business Events i Script Module, które ich dotykają.
  3. Odznacz cokolwiek chciałbyś pominąć, zwykle dla takiego tutoriala zachowałbyś wszystko.
  4. Kliknij Export -> pobierz ZIP.

Importowanie ZIP do innego środowiska odtwarza wszystko (zakładając, że schema jest wcześniej wdrożona). Tak partnerzy wysyłają konfiguracje specyficzne dla wertykali i tak później promowałbyś pracę z trialu do płatnego środowiska.

Podsumowanie - co właśnie się stało

  • Zaprojektowałeś schemę, wdrożyłeś ją jako prawdziwe tabele PostgreSQL i nigdy nie napisałeś żadnego SQL ręcznie.
  • Wystawiłeś te tabele przez Business Entities, wybierając, co ujawnić, dołączając etykiety dla użyteczności, agregując liczniki powiązanych wierszy.
  • Skomponowałeś trzy strony wyłącznie z konfiguracji, z osadzonymi kartami i wyszukiwaniem.
  • Dodałeś zachowanie przez Business Event (auto-stamping) i bardziej złożone obliczenie przez Script Module, osiem linii C#, które uruchamia się za każdym razem, gdy dane się zmieniają.
  • Spakowałeś całość jako Package, przenośny między środowiskami.

Ta sama pętla skaluje się na dziesiątki tabel i setki stron. Reference pokrywa resztę platformy, branding, synchronizacja danych third-party, scaffolding wspierany AI, ale podstawowa umiejętność to to, czego właśnie się nauczyłeś.

Dokąd dalej

  • Generuj faktury PDF - dodaj szablon faktury do druku do właśnie zbudowanych Deals. Te same dane, nowy kanał wyjściowy.
  • Scheduled Events - rozszerz skrypt przeliczający o nocne dogonienie, które uruchamia się bez akcji użytkownika.
  • AI Builder - skieruj go na "add support for service appointments, date, customer, vehicle, status" i patrz, jak scaffolduje podobną funkcję.