./01 Esittely

Julkaise
Nopeasti.
Ja luotettavasti.

Viemme tekoälyn tuottaman koodin prototyypistä tuotantoon. Enemmän ominaisuuksia, vähemmän työtä, ilman että tuotanto hajoaa.

AI-työkaluilla pääset toimivaan prototyyppiin nopeasti. Tuotteen kasvaessa koodia kasaantuu ilman arkkitehtuuria ja jokainen muutos on riski.

Luomme järjestelmät, jotka pysäyttävät virheet ennen tuotantoa: tyyppiturvallisuus, automaattiset testit, CI/CD-putket ja infrastruktuuri koodina.

Lopputuloksena sinulla on koodikanta, johon tiimisi voi luottaa.

./02 Referenssit

Referenssit

Mitä asiakkaamme sanovat

Ranta Labs teki meidän AI-koodatulle softalle tehokkaan tietoturva- ja arkkitehtuurianalyysin. Saatiin tarkka kuva riskikohdista ja selkeät ohjeet siitä, miten tuote saadaan turvallisesti tuotantoon. Vahva suositus.

OA

Onni Ahonen

CEO @ Floy

Ranta Labs pystytti meille Infrastructure as Coden ja refaktoroi koodikannan moderneihin standardikirjastoihin ja toimivampaan arkkitehtuuriin. Tämän avulla AI-avusteinen kehityksemme on nopeutunut yli 3x. Saamme enemmän ominaisuuksia tuotantoon pienemmällä tiimillä.

VR

Veeti Roponen

CTO @ MailMoo

./03 Näin toimimme

Näin se toimii

Automaattiset tarkistukset, jotka pysäyttävät virheet jokaisessa vaiheessa tyyppitarkistuksesta käyttöönottoon. Jokainen muutos varmistetaan ennen tuotantoa.

Vaihe 1

Tyyppiturvallisuus

Nappaa virheet ennen julkaisua

Tarvitsen talotiedot ID:n perusteella bannerikomponenttia varten. Käytän tRPC houses.get endpointia id-parametrilla... reititin odottaa numeroa, mutta välitän merkkijonon.
houses.ts / [banner].tsx
1export const housesRouter = router({
2 get: publicProcedure
3 .input(z.object({ id: z.number() }))
4 .query(async ({ input }) => {
5 return await db.house.findUnique({
6 where: { id: input.id }
7 });
8 }),
9});
10
11const HouseBanner = () => {
12 // ❌ Type error: id is string, expected number
13 const { data } = trpc.houses.get.useQuery({ id: 'Atreides' });
14 ← Virhe
15 return <div>{data?.emblem}</div>;
16};
Terminaali
$ pnpm typecheck
src/pages/houses/[banner].tsx:17:62 - error TS2345:
Argument of type 'string' is not assignable to parameter of type 'number'.
17 const { data } = trpc.houses.get.useQuery({ id: 'Atreides' });
~~~~~~~~~
Found 1 error.
[banner].tsx
1const HouseBanner = () => {
2 // ✓ Fixed: convert to number
3 const { data } = trpc.houses.get.useQuery({
4 id: 1265
5 });
6
7 return <div>{data?.emblem}</div>;
8 };
spice-allocation.test.ts
1export function calculateWaterDiscipline(
2 harvestYield: number,
3 carryWeight: number,
4 stillsuitEfficiency: number
5): { rations: number; surplus: number } {
6 const baseNeed = harvestYield * 0.45;
7 const adjustedNeed = carryWeight > 100 ? baseNeed * 0.8 : baseNeed;
8 const recycled = adjustedNeed * (stillsuitEfficiency / 100);
9
10 return {
11 rations: Math.floor(adjustedNeed - recycled),
12 surplus: Math.floor(recycled * 0.3),
13 };
14}
15
16describe('calculateWaterDiscipline', () => {
17 it('should optimize rations for heavy loads in deep desert', () => {
18 const result = calculateWaterDiscipline(1000, 150, 95);
19 // ❌ Test fails - logic error in carryWeight threshold
20 expect(result.rations).toBe(45);← Virhe
21 expect(result.surplus).toBe(28);
22 });
23});
Terminaali
$ pnpm test
FAIL __tests__/spice-allocation.test.ts
calculateWaterDiscipline > should optimize rations for heavy loads in deep desert
Expected: 45
Received: 180
Logic error: carryWeight threshold should be >= 150, not > 100
1 test failed, 0 tests passed
spice-allocation.test.ts
1export function calculateWaterDiscipline(
2 harvestYield: number,
3 carryWeight: number,
4 stillsuitEfficiency: number
5): { rations: number; surplus: number } {
6 const baseNeed = harvestYield * 0.45;
7 // ✓ Fixed: correct threshold for heavy loads
8 const adjustedNeed = carryWeight >= 150 ? baseNeed * 0.8 : baseNeed;
9 const recycled = adjustedNeed * (stillsuitEfficiency / 100);
10
11 return {
12 rations: Math.floor(adjustedNeed - recycled),
13 surplus: Math.floor(recycled * 0.3),
14 };
15}
16
17describe('calculateWaterDiscipline', () => {
18 it('should optimize rations for heavy loads in deep desert', () => {
19 const result = calculateWaterDiscipline(1000, 150, 95);
20 expect(result.rations).toBe(45);
21 expect(result.surplus).toBe(28);
22 });
23
24 it('should handle light patrols differently', () => {
25 const result = calculateWaterDiscipline(1000, 80, 90);
26 expect(result.rations).toBe(225);
27 });
28});
Terminaali
$ git add . && git commit -m 'fix: correct carryWeight threshold'
$ git push origin main
→ CI pipeline triggered...
→ Running typecheck... ✓
→ Running tests... ✓
→ Running lint... ✓
→ Building application... ✓
→ Pulumi preview...
Previewing update (dev):
+ aws:lambda/function:Function harvest-reports
+ aws:iam/role:Role lambda-exec-role
Resources: +2 to create
lambda.ts
1import * as aws from "@pulumi/aws";
2
3// Create Lambda function for harvest reports
4const harvestReports = new aws.lambda.Function("harvest-reports", {
5 runtime: "nodejs20.x",
6 handler: "index.handler",
7 code: new pulumi.asset.FileArchive("./lambda"),
8 role: lambdaRole.arn,
9 environment: {
10 variables: {
11 DATABASE_URL: dbUrl,
12 },
13 },
14});
Terminaali
$ pulumi up -y
Updating (dev):
+ aws:lambda/function:Function harvest-reports created
+ aws:iam/role:Role lambda-exec-role created
Resources: +2 created
--- Invoke harvest-reports ---
ERROR: connect ECONNREFUSED 10.0.1.45:5432
at TCPConnectWrap.afterConnect [as oncomplete]
code: 'ECONNREFUSED',
syscall: 'connect',
lambda.ts
1import * as aws from "@pulumi/aws";
2
3const harvestReports = new aws.lambda.Function("harvest-reports", {
4 runtime: "nodejs20.x",
5 handler: "index.handler",
6 code: new pulumi.asset.FileArchive("./lambda"),
7 role: lambdaRole.arn,
8 environment: {
9 variables: { DATABASE_URL: dbUrl },
10 },
11 // ✓ Fixed: Add VPC configuration to access RDS
12 vpcConfig: {
13 subnetIds: [privateSubnet1.id, privateSubnet2.id],
14 securityGroupIds: [lambdaSecurityGroup.id],
15 },
16});
Terminaali
$ pulumi up -y
Updating (dev):
~ aws:lambda/function:Function harvest-reports updating
~ aws:lambda/function:Function harvest-reports updated
Resources: 1 changed
--- Invoke harvest-reports ---
Status: 200 OK
{ "crawlerId": "C-8492", "yield": 847.5, "region": "deep-desert" }
✓ Connection successful!
Terminaali
✓ TypeScript type checking passed
✓ Unit tests passed (42/42)
✓ Integration tests passed
✓ Linting passed
✓ Security scan passed
✓ Infrastructure deployed
✓ Smoke tests passed
─────────────────────────────
🚀 Deployed successfully to:
https://api.rantalabs.dev
─────────────────────────────
Shipped safely with guardrails!
./05 Blogi

Blogi

Käytännön oppaita tekoälyn tuottaman koodin tuotantoon viemiseen

./04 Aloitetaan

Valmis shippaamaan turvallisesti?

Kerro mitä olet rakentamassa. Arvioimme koodikantasi ja näytämme miten saamme sen tuotantoon.