Baby Monitor Timmy började med en enkel idé: en babyvakt som respekterar integriteten hemma. Inga inspelningar i molnet, inga onödiga datavägar ut från barnrummet. Det många inte ser är att jag bygger Timmy som ett soloprojekt i Zürich, och GitHub Copilot är min mycket snabba parprogrammerare.
Arbetsflödet mellan människa och AI
Uppdelningen är tydlig: jag definierar funktioner, sätter prioriteringar och fattar arkitekturbeslut. Copilot hjälper till med implementationen: skriver kod, lägger till tester, ringar in buggar och förbereder steg inför lansering.
En typisk sprint ser ungefär ut så här för mig:
- Funktionsbeskrivning: Jag beskriver vad funktionen ska göra, inklusive specialfall och begränsningar.
- Implementation: Copilot föreslår kod och följer projektets befintliga konventioner.
- Testning: Automatiserade end-to-end-tester körs på två emulatorer och kontrollerar den verkliga anslutningen mellan baby- och föräldraenheten.
- Distribution: När testerna går igenom förbereds Android- och iOS-versioner för rätt butiker och testkanaler.
Den här cykeln upprepas för funktioner och buggfixar. Jag skriver inte varje rad själv, men jag bestämmer vad som byggs, varför det byggs och om ett förslag passar Timmy.
Från koncept till WebRTC
Den centrala tekniska uppgiften var tydlig från början: ljud och video i realtid mellan två telefoner. WebRTC var det självklara valet, men att integrera det med Flutter är inte enkelt: ICE-kandidater, SDP-förhandling, TURN-reservlösning och DataChannels måste fungera tillsammans i rätt ordning.
Copilot hjälpte mig att sätta ihop de här delarna steg för steg: konfigurera peer-anslutningen, hålla den kritiska ordningen rätt (DataChannel före SDP-offer, onTrack före setRemoteDescription) och lägga signaleringen i Firebase Firestore. Varje del behövde fungera på två emulatorer innan jag gick vidare.
Säker parkoppling med ECDH
En av de mest kritiska funktionerna var det säkra parkopplingssystemet. Två enheter behöver upprätta ömsesidigt förtroende utan att förlita sig på att en central server intygar deras identitet. Lösningen: ett ECDH P-256-nyckelutbyte via Firebase, kombinerat med ett visuellt verifieringsnummer (SAS) som upptäcker man-in-the-middle-attacker.
Copilot hjälpte till att implementera den kryptografiska kedjan: nyckelgenerering, utbyte av offentliga nycklar, härledning av en gemensam hemlighet, SAS-beräkning och AES-256-GCM-kryptering av alla efterföljande signaleringsdata. Jag skickar inte parkopplingsnyckeln till serverdelen; endast dess SHA-256-hash används som dokumentidentifierare i Firestore.
Säkerhetsgranskning: hitta och åtgärda sårbarheter
AI-stödd utveckling handlar för mig inte bara om att skriva snabbare. Den hjälper också till med systematisk buggjakt. Under en fokuserad säkerhetsgranskning analyserade Copilot kodbasen och hittade sex problem som jag behövde åtgärda:
- Saknad validering av indata i signaleringsdata
- Möjliga kapplöpningstillstånd vid hantering av ICE-kandidater
- Inaktuell sessionsdata som inte rensades bort ordentligt
- För tillåtande säkerhetsregler i Firestore
- Bristande hantering av certifikatfästning
- Otillräcklig felhantering i flödet för TURN-autentiseringsuppgifter
Alla sex åtgärdades i samma sprint. Här är Copilot stark: att läsa många filer, jämföra mönster och markera ställen som jag behöver granska närmare.
Iterativa sprintar: så utvecklades appen
Timmy växte genom snabba men tydligt avgränsade sprintar. Några milstolpar:
- v1.8: Helt omgjord parkoppling — en kod med 4 tecken och ECDH P-256 via Firebase ersatte den gamla direktnyckelmetoden.
- v1.10: Sprint för säkerhetshärdning — granskning och åtgärdande av de sex sårbarheterna.
- v1.11: Mörkt läge på alla skärmar, plus startsidan och bloggen du läser just nu.
- v1.12: Stor omarbetning av föräldraskärmen, mörkerseendeläge och rörelsedetektering genom analys av kamerabilder.
Varje sprint följer samma grundmönster: beskriv målet, granska förslagen, testa automatiskt och leverera sedan till testarna.
E2E-testning mellan enheter
Du kan inte testa en babyvakt ordentligt på en enda enhet. Jag behöver en babyenhet och en föräldraenhet. Projektet började med två Android-emulatorer som kördes samtidigt. Numera kompletteras det flödet med tester i en lokal iOS-simulator och kontroller på riktiga enheter. Det automatiserade Android-testskriptet gör fortfarande följande:
- Installerar appen på båda emulatorerna
- Går igenom parkopplingen på båda enheterna
- Kontrollerar att ljud- och videoanslutningar upprättas
- Testar push-to-talk, kamerastyrning och andra funktioner
Eftersom båda emulatorerna delar samma IP-adress (10.0.2.15), är en direkt peer-to-peer-anslutning via STUN omöjlig. Varje testkörning måste gå via Cloudflares TURN-relä. Det är irriterande men användbart: den mest komplicerade anslutningsvägen testas varje gång.
Vad jag lärde mig
Att bygga en komplett app med en AI-parprogrammerare lärde mig några saker:
- Arkitekturen är viktigare än någonsin. Tydliga konventioner och en väl dokumenterad kodbas hjälper AI:n att föreslå konsekvent kod. Otydlighet blir snabbt dyr.
- Testning går inte att förhandla bort. AI-genererad kod behöver samma noggranna testning som kod skriven av människor. Automatiserade E2E-tester fångade problem som hade varit lätta att missa manuellt.
- Människan behåller kontrollen. Varje arkitekturbeslut, varje säkerhetsmässig avvägning och varje avgränsning av produkten är fortfarande mitt ansvar. AI snabbar upp implementationen, men ersätter inte omdömet.
- Snabbhet möjliggör kvalitet. Eftersom funktioner släpps på timmar i stället för dagar, finns det mer utrymme för iterationer, finslipning och buggfixar. Snabbt betyder inte automatiskt bra.
Framåt
Baby Monitor Timmy fortsätter att utvecklas. iOS-lanseringen närmar sig; därefter kommer fler sensorfunktioner och fortsatt säkerhetshärdning. Arbetsflödet är i stort sett detsamma: jag anger riktning och gränser, och Copilot hjälper till att snabbt implementera och kontrollera.
De säkerhetsrelevanta byggstenarna finns nu inom tydliga gränser i det offentliga kodarkivet baby-monitor-timmy-core. Där dokumenteras också arkitekturbesluten kring parkoppling, signalering och backendgränssnitt.