Tapaustutkimus
Dredge: monilähteinen operaatioiden seurantakortti
Laajuus
~7,300
Elixirin rivit (kirjasto)
64
Moduulit
4
Lähdeadapterit
14
Ecto muuttoliikkeet
3
Anthropic asiakastilat
~1,180
Testisarjat
Ongelma
Pienet kehittäjätiimit seuraavat maailmaansa kuuden välilehden kautta samanaikaisesti: GitHub-ilmoitukset, Dependabot-hälytykset, tietokanta, jota heidän on pidettävä silmällä, RSS-tietoturvailmoitukset sekä valtava määrä webhook-ilmoituksia osoitteista Sentry, Datadog ja PagerDuty. Mikään ei ole yhteydessä toisiinsa, mikään ei ole priorisoitu, ja ongelmien luokittelu tapahtuu kontekstin vaihtelun kautta, kunnes jokin asia jää huomaamatta.
Dredge koostaa kaiken yhdeksi reaaliaikaiseksi kanban-tauluksi. Tehtävät virtaavat sisään mistä tahansa liitetystä lähteestä, ohjataan sääntöjen mukaan sarakkeisiin ja näkyvät tärkeysjärjestyksessä – joten tiimi voi priorisoida tehtävät yhdessä paikassa sen sijaan, että sen pitäisi selata kuutta eri välilehteä. Se oli myös, avoimesti sanottuna, keino oppia Elixir, OTP ja Phoenix LiveView kunnolla sen sijaan, että olisi opiskeltu niitä oppaiden avulla.
Mitä rakennettiin
Lähteet (sovituskerros)
- ·RSS / Atom – kyselypohjainen, syötteen URL-osoitteen automaattinen tunnistus; optimoitu CVE- ja toimittajien tietoturvasyötteille
- ·GitHub - OAuth; ilmoitukset, osoitetut ongelmat, tallennukset sekä Dependabot-hälytykset, joissa CVSS on liitetty kortin prioriteettiin
- ·Tietokanta – yleiskäyttöinen, SELECT-only-kyselyohjelma sivustoille Postgres ja MySQL, joka merkitsee epäilyttävät rivit ja tunnistaa automaattisesti otsikko- ja vakavuus-sarakkeet
- ·Webhook – push-pohjainen, HMAC -vahvistettu POST /webhooks/:id; tukee seuraavia syötteitä: GitHub, Sentry, Datadog ja PagerDuty
- ·Jokainen lähde toteuttaa yhden toimintatavan (fetch/3 + normalize/1), joten prosessiketjun ei tarvitse koskaan tietää, minkä tyyppisen lähteen kanssa se on tekemisissä
Hallitus ja luokitus
- ·Sääntöihin perustuva reititys: kohdista kohteet sarakkeisiin kentän / operaattorin / arvon perusteella, valinnaisella prioriteettisäännöllä (CVSS >= 9 asettaa prioriteetin 10)
- ·Luokittelija, joka valitsee ensimmäisen vastaavuuden ja käyttää varasuunnitelmana ”Inbox”-sääntöä; koko pelilaudan uudelleenluokittelu sääntöjen muuttuessa
Skiff (tekoälykerros)
- ·Tekoälyprosessin määritykset – kuvaile selkokielellä, mitä haluat seurata; komento Skiff palauttaa vahvistetun lähdekoodin ja reitityssääntöjen määritykset, jotka voit tarkistaa ja hyväksyä ennen kuin mitään kirjoitetaan
- ·Tekoälypöytäavustaja – agentti-pohjainen työkalunkäyttösilmukka, joka vastaa koko pelilaudalla esitettyihin kysymyksiin, osaa luoda kortteja ja voi tarvittaessa suorittaa vain lukuoikeudella varustetun SQL-kyselyn liitettyyn tietokantaan
- ·Anthropicin kautta lähetetyt kolumnien yhteenvedot Viestit osoitteeseen API osoitteessa SSE
Yhteistyö ja reaaliaikaisuus
- ·Jäsenten kutsuminen (katselija / muokkaaja), julkiset vain luku -jakolinkit, läsnäoloavatarit ja korttikohtaiset kommenttiketjut
- ·Phoenix PubSub + Presence: taulu päivittyy heti, kun uusi kohde saapuu, ilman että asiakaspuolella tarvitaan kyselyjä
Tekninen arkkitehtuuri
Mitä opin
Tämä oli ensisijaisesti oppimista varten tehty projekti, joten tässä ovat ne asiat, joita tämä kehitysympäristö minulle opetti – useat niistä kantapään kautta, kuten git-historiasta näkyy.
1. OTP määrittelee vikasietoisuuden uudelleen rakenteelliseksi valinnaksi, ei virheiden käsittelyksi
Koska olen tottunut pyyntö-vastaus-tyyppisiin taustapalvelimiin, ensimmäinen ajatukseni tilanteeseen ”mitä jos syöte on poissa käytöstä” oli try/catch-käsittely ja uudelleenkäynnistysliput. OTP nosti ratkaisun uudelle tasolle: mallintaa jokainen lähde omaksi valvottavaksi prosessikseen. Dredge käyttää yhtä SourceWorker GenServer -prosessia lähdettä kohden käyttäjäkohtaisen DynamicSupervisor -palvelun alla, joka rekisteröidään osoitteessa {user_id, source_id}. Epävakaa RSS-syöte voi kaatua ja käynnistyä uudelleen itsestään koskematta käyttäjän GitHub-kyselyyn, ja työntekijä on :transient, joten puhdas pysäytys pysyy pysäytettynä, kun taas kaatuminen käynnistyy uudelleen. Käynnistyksen yhteydessä root-valvoja lukee kaikki aktiiviset lähteet tietokannasta ja käynnistää jokaiselle työntekijän. Vian eristäminen ei ole enää jotain, mitä koodaan, vaan se on jotain, jonka järjestelmän rakenne tarjoaa minulle ilmaiseksi.
2. Käyttäytymismallit tekevät ”lisää uusi integraatio” -ongelmasta ratkaistun ongelman
Ensimmäisessä versiossa source_type-haarat käsiteltiin koodissa, joka suoritti kyselyjä. Tilanne paheni lähdettä kohden. Korvaamalla se sovitintoiminnolla – neljällä kutsukäskyllä, joista ytimenä toimivat fetch/3 ja normalize/1 – työntekijä kommunikoi abstraktin lähteen kanssa eikä luo koskaan uutta haaraa. Reddit:n tai Hacker News:n lisääminen myöhemmin on yhden moduulin toteuttamista, ei putkilinjan muokkaamista. Se on selkein hyöty, jonka olen kokenut suunnittelemalla rajapintaa varten sen sijaan, että olisin suunnitellut ensimmäisenä päivänä sattumalta käytössä olleita tapauksia varten.
3. Hallinnoitu infrastruktuuri pettää tavoilla, joista dokumentaatio ei varoita
Aikaa vievin vaihe oli saada tietokanta-adapteri toimimaan yhdessä Supabase:n kanssa, eikä tässä ollut mitään syytä Elixir:lle. Kolme todellista esteitä, kaikki git-historiassa: Supabase:n transaktiopooleri hylkää nimetyt valmistellut lauseet (korjattu pakottamalla prepare: :unnamed osoitteessa Postgrex), "suora" yhteys on vain IPv6 ja saavuttamaton useimmilta palvelimilta (korjattu ohjaamalla käyttäjät IPv4-pooleriin), ja postgres://-URL-osoitteet on pilkottava erillisiksi host/port/user/pass-vaihtoehdoiksi, koska ohjain ei hyväksy URL-osoitetta. Tärkein korjaus ei ollut lainkaan koodia – se oli yhteysmerkkijono-ohjeiden kirjoittaminen asennusliittymään, jotta seuraava henkilö ei törmää samaan esteeseen. Puolet integraatiotyöstä on oman vianetsinnän muuntamista jonkun toisen ohjeiksi.
4. Tekoälyominaisuus vaatii luottamusmallin ja kustannusmallin jo alusta alkaen
Kaksi asiaa, jotka olisin lisännyt vasta myöhemmin, jos en olisi joutunut pohtimaan niitä. Luottamus: avustaja voi tehdä kyselyjä kytkettyyn tietokantaan, joten kyselypolku varmistaa tiukasti, että sovittimessa noudatetaSELECT-only-periaatetta, rajoittaa rivimäärää ja yhteysmerkkijono säilytetään salattuna – malli saa lukuoikeuden, mutta ei koskaan kirjoitusoikeutta. Sama ajattelutapa näkyy myös putkigeneraattorissa: tekoälyn luomaa konfiguraatiota käsitellään epäluotettavana ehdotuksena, joka tuodaan tarkasteltavaksi ja vahvistetaan vasta käyttäjän hyväksyttyä sen, eikä sitä koskaan kirjoiteta suoraan tietokantaan. Kustannukset: jaettu API-avain tarkoittaa jaettua laskua, joten käyttö kulkee kiintiön ratkaisijan kautta – järjestelmänvalvojilla on rajaton käyttöoikeus, käyttäjä, joka toimittaa oman Anthropic-avaimensa, voi käyttää sitä rajattomasti omalla kustannuksellaan, ja kaikille muille asetetaan jaetulle avaimelle pehmeä päivittäinen yläraja, jossa monikutsun agenttisilmukka lasketaan yhdeksi pyynnöksi. LLM:n tuominen tuotteeseen riippuu yhtä paljon siitä, mitä se ei voi tehdä ja mitä se ei voi maksaa, kuin siitä, mitä se voi tehdä.
5. LiveView tarjoaa reaaliaikaisen toiminnon ilman käyttöliittymäkehystä
Foorumi päivittyy reaaliaikaisesti – uudet viestit, läsnäoloavatarit, kommentit – ilman väliaikaista tallennustilaa (React), ilman asiakaspuolen tallennustilaa eikä kyselyjä (polling). Phoenix PubSub lähettää muutospyynnön (:new_item), ja palvelin piirtää kyseisen fragmentin uudelleen WebSocket-yhteyden kautta. Tämä vaatii kurinalaisuutta: kokoelmien on oltava LiveView-virtoja (jotta pitkäikäinen taulu ei täytä palvelimen muistia) ja on harkittava tarkkaan, mikä tila säilyy socketissa. SPA:n vaihtaminen palvelinohjatun renderoinnin tilalle poisti kokonaisen luokan asiakaspuolen ja palvelimen tilan synkronointivirheitä, joiden kanssa olen tottunut taistelemaan.
6. Tekoälyn nimeäminen muutti tuotteen luettavuutta
Pieni muutos, jolla oli valtava vaikutus. Alun perin avustaja näkyi käyttöliittymässä ja kehotteissa nimellä ”Claude”. Sen nimeäminen uudelleen muotoon ”Skiff” – eli tuotteen nimen antaminen toimittajan nimen sijaan – sai sen näyttämään Dredge-sivuston omalta ominaisuudelta pikemminkin kuin sinne kiinnitetyltä chatbotilta, ja irrotti huomaamattomasti tuotteen äänimaailman sen takana olevasta mallista. Brändäysmuutos ja arkkitehtuurimuutos (Anthropic-asiakkaan pitäminen yhden moduulin takana) osoittautuivat samaksi vaistoksi.
Turvallisuus
- ·cloak_ecto -palvelun avulla salattuina tallennetut tunnistetiedot ja tietokantayhteysmerkkijonot
- ·Webhook-syötteen luotettavuus tarkistetaan lähdekohtaisesti osoitteessa HMAC ennen kuin mitään dataa pidetään luotettavana
- ·Sekä tekoälytietokantatyökalu että tietokanta-adapteri noudattavat ehdottomasti periaatetta ”kirjoitusoikeudet vain tarvittaville käyttäjille” (SELECT-only); asennusohjeissa suositellaan vain lukuoikeudet omaavien tietokantakäyttäjien käyttöä
- ·Tekoälyn käyttöä on rajoitettu käyttäjäkohtaisilla kiintiöillä jaetun API-avaimen suojaamiseksi