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), requiredindustry- VARCHAR(80), nullableopen_deal_value- DECIMAL, default0- utrzymywana w synchronizacji przez skrypt w Kroku 5created_at- TIMESTAMPTZ, defaultnow()
Tabela: contact
id- SERIAL, PK (auto)first_name,last_name- VARCHAR(100), requiredemail- VARCHAR(200), required, UQ oncompany_id- INTEGER, required - klucz obcy, konfigurowany dalej
Tabela: deal
id- SERIAL, PK (auto)company_id- INTEGER, required - klucz obcy, konfigurowany dalejtitle- VARCHAR(200), requiredstage- VARCHAR(40), required, default'New'- wartości: New, Qualified, Proposal, Won, Lostamount- DECIMAL, required, default0created_at,updated_at- TIMESTAMPTZ, defaultnow()
Klucze obce
Klucze obce żyją w karcie Relations prawego panelu. Wybierz tabelę
contact, przełącz na Relations, przewiń do sekcji "Add relationship":
- FK column (na tej tabeli) =
company_id - Relation type =
One-to-Many - References -> table =
company - References -> column =
id - Kliknij Add Relationship.
Powtórz dla tabeli deal (jej company_id -> company.id).
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, abycompanybyła tworzona przedcontactideal, 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 columncompany.id, To columncontact.company_id. Włącz Aggregate Mode. Wybierz kolumnęid, ustaw Aggregate Function =COUNT, nazwij jącontact_count. -
Join do
deal: From columncompany.id, To columndeal.company_id. Aggregate Mode włączony. Wybierz kolumnęid, funkcjaCOUNT, 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:
- Companies - Page Name
Companies, Page Route/companies, Business Entitycompany. 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. - Contacts - Page Name
Contacts, Page Route/contacts, Business Entitycontact. Polecompany_idw auto-wygenerowanym formularzu szczegółów pojawi się jako liczba, zmień jego Type na Select i ustaw autocomplete Entity nacompany, aby użytkownicy wybierali firmę po nazwie. - Deals - Page Name
Deals, Page Route/deals, Business Entitydeal. To samo traktowanie dlacompany_id(TypeSelect, Entitycompany). Dlastagena razie zostaw Type jakoText, wartości można wymusić przez eventValidatepóź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.
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.
Dlacreated_at/updated_at/created_by/updated_bynigdy 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.
- Otwórz Business Events -> Create.
- Rule Name:
Normalize deal.title. Przełącz Enabled na ON. - Business Entity:
deal. Triggers: zaznacz Before Update. - Bez warunków, odpalaj przy każdym update.
-
Dodaj akcję: wybierz Execute Script. Ciało skryptu akcji:
string title = Entity.title; Entity.title = title?.Trim(); -
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.titlezostało ustawione. (Nie dzieje się żaden prawdziwy zapis, symulacja uruchamia się w cofniętej transakcji.) - 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
awaitna.ToListAsync(), skrypt kompiluje się, aleopenDealskończy zTask, nie z wierszami. Błąd w panelu Test wspomni o "cannot be enumerated".- Użycie
Db.QueryzamiastDb.From, nie ma metodyQuery. Trzymaj sięDb.From(table)dla łańcuchowanych zapytań iDb.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
- Otwórz Business Events -> Create.
- Rule Name:
Recalc company.open_deal_value on deal change. Enabled ON. - Business Entity:
deal. Triggers: zaznacz After Create, After Update i Before Delete. - Bez warunków, odpalaj przy każdej zmianie.
-
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 }); - Zapisz. Edytuj
amountjakiegoś 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.
- Otwórz Packages -> Create. Nazwij to
MiniCRM v1. - 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ą.
- Odznacz cokolwiek chciałbyś pominąć, zwykle dla takiego tutoriala zachowałbyś wszystko.
- 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ę.