---
title: Novi Kvadrat
description: A five-language property platform for Serbia, built end to end.
url: https://secretocho.design/work/novi-kvadrat/
type: CreativeWork
status: live
published: 2025-12-01
---

# Novi Kvadrat

> A five-language property platform for Serbia, built end to end.

case 01 / 05 · live

- **role**: Sole designer and developer, end to end, in a core team of four
- **period**: since Dec 2025
- **client**: Novi Kvadrat Group DOO
- **platforms**: web · installable PWA · iOS in development
- **credit**: Design & Development by SecretoCho for Novi Kvadrat Group DOO
- **public**: novikvadrat.rs

![The Novi Kvadrat home page on a desktop browser, with its search over new developments across Serbia.](https://secretocho.design/_astro/home-desktop-light.CmAPc153_Z2pxh3O.jpg)

## at a glance

- Marketplaces for new builds, resale and rent, a business portal and an admin console, in one Next.js app.
- Five languages, each with its own URLs and about 17,000 strings.
- Security lives in the database: row-level security on every table, authorization that denies by default.
- In-browser studios turn a scanned plan into rooms and raise map buildings into storeys.
- Built in waves of AI agents, with tests that were tested themselves.

- **new-build projects listed, across 29 cities**: ~480
- **developers with projects on the platform**: 352
- **pages**: 277
- **API route handlers**: 601

## Context

Novi Kvadrat is a property platform for Serbia, live at novikvadrat.rs: new builds, resale and rentals in one place, for the people who buy and rent and for the people who sell to them. Everything ships in English, Serbian, Turkish, German and Russian.

Buyers and renters browse new-build projects, sale and rental listings, official market statistics and city guides. Developers, agencies, agents and landlords publish through a business portal with inventory, a sales hub, leads, deals and analytics. Tenants get leases, invoices, inspections and maintenance, and staff run the platform from an admin console.

Three studios work right in the browser: one turns a floor plan into rooms, one raises 3D buildings, one draws site plans. I designed and built every part of it, from the brand mark to the database.

I’m the designer and developer in a core team of four, with a growth manager and two customer-relations leads who also run QA and content. The founder sets the product direction, the general manager steers, and the rest of the company gives feedback every week.

![The new-developments map on a desktop browser: Belgrade in 3D, its new-build projects raised as blue buildings.](https://secretocho.design/_astro/newdev-desktop-light-map.CRgEgl46_Z1k37i0.png)

*fig · new builds on the map*

## Constraints

- Five languages from the first release, each with its own URLs: the new-builds page is /novogradnja in Serbian and /new-developments in English, across 27 localized routes.
- Licensed drawings stay private: developers’ floor plates and site-plan sources live in private storage behind short-lived signed URLs.
- Open tooling for maps and 3D: no paid 3D services and no photoreal map tiles.
- Licences decide the data: an AI floor-plan dataset with a non-commercial licence was ruled out.
- One designer and developer for the design, the code, the data and the delivery, in a core team of four.

## Architecture

One Next.js app serves every audience: the public marketplace, buyer accounts, a business portal split by kind of organization, tenant and vendor pages, and the admin console. That is 277 pages (75 on the public side, 59 in the portal, 143 in the admin console) on 601 API route handlers.

Security lives in the database. Every table has row-level security; tables only the server may touch deny everyone else, and privileged functions are locked to the server’s own role. Sessions are cookies read on the server, so no token sits in the browser’s storage.

Each redesigned screen ships as a twin of the old one behind a cookie, and tests pin the old one byte for byte until the switch. Each launch feature sits behind one constant that turns its routes, navigation, sitemap entries and teasers on or off together.

![A new-build project page on a desktop browser: its gallery, then its name, status and key facts.](https://secretocho.design/_astro/project-desktop-light.Bv-W7l88_ZPT1tt.jpg)

*fig · a project page*

1. **Browsers** client · 5 languages
   - to Next.js app: cookies
2. **Next.js app** service · 277 pages
   - to Postgres: queries
   - to Edge Function: parse query
3. **Cron jobs** process · crons + pg\_cron
   - to Postgres: rollups
4. **Edge Function** service · AI search
5. **Postgres** store · RLS everywhere
6. **Official data** external · stats, registry
   - to Postgres: ingest
7. **iOS app** client · in build · SwiftUI
   - to Postgres: Swift SDK
8. **OpenStreetMap** external · open map data
   - to Postgres: footprints

*one app for every audience. the database decides who sees what.*

## Decision log

### Floor plans: drawn, not recognized

- **options**: train a plan-recognition modelan in-browser editor with snapping and a polygonizer
- **chose**: an in-browser editor with snapping and a polygonizer
- **why**: The best public training set, CubiCasa5K, carries a non-commercial licence, so it cannot power a commercial product.

### Maps and 3D

- **options**: a paid 3D servicephotoreal map tilesMapLibre and three.js on open data
- **chose**: MapLibre and three.js on open data

### Image variants

- **options**: paid image transformsa self-hosted variant generator
- **chose**: a self-hosted variant generator
- **why**: Each WebP variant is made on its first request, then served from the CDN.

### Redesigns

- **options**: switch every screen at oncetwins behind a cookie
- **chose**: twins behind a cookie
- **why**: The old screen stays pinned byte for byte by tests until the new one takes over.

## Floor Plan Studio

· deep dive

An in-browser SVG editor turns a scanned plan into rooms with measured areas, so each photo lands in the room it shows, with its camera angle.

1. Upload the plan; one line locks the scale.
2. Trace the walls; corners snap to 90°.
3. Closed loops become rooms, with their areas.
4. Doors and windows snap onto the walls.
5. Photos land in their rooms, cameras aimed.
6. The plan goes live on the listing.

Walls become rooms through a planar-graph polygonizer: it walks the faces of the wall graph, orients each by its signed area and joins holes to their rooms. Photos drop into rooms by point-in-polygon tests, not bounding boxes, and each camera carries a bearing and a 45, 65 or 90° field of view, so a visitor sees where a photo was taken.

It ships in rent and sale, in the admin console and the business portal, in five languages.

*Diagram: Floor Plan Studio, step by step: a calibration line locks the scale at 6.00 metres; walls are traced with 90-degree snaps until the loop closes; four rooms flood with their areas, 58.5 square metres in all; doors and windows snap onto the walls; three photos land in their rooms and camera cones turn to their bearings; the readiness checks pass and the plan becomes a listing in five languages.*

rent + sale · admin + portal · 5 languages

*a scanned plan goes in. **a walkable listing comes out.***

![A layout page on a desktop browser: one apartment type of a new-build project, with its floor plan and room areas.](https://secretocho.design/_astro/layout-desktop.DmpqagO9_ZiSUfB.png)

*fig · a layout, desktop*

![The same layout page on a phone, the floor plan first.](https://secretocho.design/_astro/layout-phone.CMVjKE_e_25XDTI.png)

*fig · a layout, phone*

## Site Plan Studio, live in the staff admin

· deep dive

A developer sells named buildings. The map knows only outlines, often more of them than there are buildings, and none of them named. Site Plan Studio joins the two, and it is live in the staff admin.

1. Upload the developer’s site plan and set north.
2. Trace each building on the plan.
3. Link each traced shape to its building.
4. Group the map’s outlines under the buildings they belong to.
5. Pin the plan to the map.
6. A buyer picks a building by what is left in it. · the public view is a design

Nothing on the map is thrown away: the studio groups the map’s outlines under the developer’s buildings and keeps the old rows. On the project page, the plan is meant to show every building with what is left in it, so a buyer starts from what is for sale.

![Site Plan Studio in the staff admin: a developer’s site plan with eight traced buildings, a readiness checklist down the left and the selected building’s details on the right.](https://secretocho.design/_astro/site-plan-main.Cxqp3OW5_2w6VlI.png)

*fig · Site Plan Studio · staff admin · placeholder data*

![The building tool: a building traced on the site plan and linked to its record in one go.](https://secretocho.design/_astro/site-plan-building-tool.BiB7rurh_ZBnBme.png)

*trace and link · staff admin · placeholder data*

![Linking: a building record dragged onto its traced shape.](https://secretocho.design/_astro/site-plan-linking.C-OJfcoJ_esg6U.png)

*link · staff admin · placeholder data*

![Matching the map: the map’s building outlines grouped under the developer’s eight buildings, before a merge.](https://secretocho.design/_astro/site-plan-merge.CaBLl0wH_ZHx2fX.png)

*group the map · staff admin · placeholder data*

![Pin to the map: the site plan laid half-transparent over the map, turned with a knob and scaled from a corner.](https://secretocho.design/_astro/site-plan-pin-to-map.mGNeuuBT_bdacw.png)

*pin to the map · staff admin · placeholder data*

![The site plan on a project page: eight buildings, each with what is left in it, a selected building’s card and the list of buildings.](https://secretocho.design/_astro/site-plan-public.BaaT3T_G_Ze7ywW.png)

*fig · the site plan on a project page · design · placeholder data*

## 3D buildings, measured before built

· deep dive

A tap on a 3D building must pick the right storey, even half hidden behind another one. The approach was measured before it was built: a throwaway spike ran 81 headless GPU runs and 199 renders.

1. Building footprints come in.
2. Storeys extrude, slab by slab.
3. A pick ray finds the first visible storey.
4. That storey unfolds into its floor plate.
5. BD0–BD9 run in the staff studio.
6. The public 3D viewer waits behind a flag.

Plain map extrusions picked the correct storey 99.65% of the time; 5,400 storeys updated in about 123 ms, and a whole floor plate opened in 13 ms. The numbers come from one desktop GPU, headless, so they say nothing yet about a phone.

One bug taught the model something. On one map tile, 40 basemap features held 750 building polygons, and one feature id spanned 2.2 km, so hiding a duplicate by its id hid 17 unrelated buildings. Duplicates are now suppressed by their geometry, and the basemap is never hidden.

In the staff admin, the 3D Buildings Studio groups the map’s parts into the developer’s buildings, stacks their storeys, traces a whole-floor plate and links each storey to its units. The public viewer stays behind a flag.

*Diagram: 3D buildings, measured before built: three footprints extrude storey by storey; a pick ray from a screen point finds storey 6 of the tallest building, which unfolds into its floor plate. 81 headless GPU runs gave 99.65 percent correct storey picks, 5,400 storeys in about 123 milliseconds, a floor plate in 13 milliseconds. Phases BD0 to BD9 are in production in the staff studio; the public viewer and developer models wait behind flags.*

correct picks **99.65%** · gpu runs **81** · **5,400** storeys in **~123 ms** · floor plate **13 ms**

*the floor you click is the floor you get. **measured before built.***

1. **OpenStreetMap** external · footprints
   - to Buildings: Overpass
2. **Buildings** process · sales buildings
   - to Storeys: slabs
3. **Storeys** process · one per floor
   - to Floor plate: pick ray
4. **Floor plate** service · opens in 13 ms
   - to Public viewer
5. **Staff studio** client · BD0–BD9
   - to Buildings: edit
6. **Dev models** process · planned · GLB · flagged
   - to Storeys: placed
7. **Public viewer** client · planned · behind a flag

*open map data in. one storey out.*

![The 3D Buildings Studio in the staff admin: a project’s buildings raised on the map, storey by storey.](https://secretocho.design/_astro/3d-main.DFNXhoCU_Z1LRBxQ.png)

*fig · 3D Buildings Studio · staff admin · placeholder data*

![Grouping: the map’s parts gathered into the developer’s buildings, as a draft before Save.](https://secretocho.design/_astro/3d-group.BbEfXvH-_ZRjj14.png)

*group the map · staff admin · placeholder data*

![The storey stack of one building, with each storey’s height.](https://secretocho.design/_astro/3d-stack.DoBgDBJt_MtHNG.png)

*the storey stack · staff admin · placeholder data*

![Tracing a whole-floor plate: unit regions drawn over a private floor drawing, one plate for floors 1–6.](https://secretocho.design/_astro/3d-plate.C0kHc4A__Z13RpgU.png)

*the floor plate · staff admin · placeholder data*

![Assigning units to a storey: four units of one floor joined to their building, and a unit of another project refused.](https://secretocho.design/_astro/3d-units.CvFo2qOD_Z2lb9cN.png)

*storeys to units · staff admin · placeholder data*

![A whole-floor plan as a buyer would see it: each unit drawn with its status as a pattern and a word, a sold unit’s card, and the same units as a list.](https://secretocho.design/_astro/3d-public-plate.BgUxoFAD_ZwQpl9.png)

*fig · the whole-floor plan · design · placeholder data*

## AI search that never invents listings

· deep dive

A small model returns validated filters, never listings, and a deterministic fallback stands behind it. The model shapes the search; it never writes the results.

The query goes to an edge function with its input capped at 500 characters and its answer at 400 tokens. With no key set, the page falls back without a word. Projects also carry 1,024-dimension embeddings for semantic search.

**500** · characters, the most a query sends to the model

1. **Visitor query** client · 5 languages
   - to Small model: raw text
   - to Fallback: fallback
2. **Small model** service · 500 chars in
   - to Validator: intent
3. **Validator** process · server, browser
   - to Listings: filters
4. **Listings** store · live queries
5. **Fallback** process · regex, no model
   - to Validator: intent

1. A question, in any of five languages.
2. A small model turns it into a search intent.
3. A regex covers what the model misses.
4. The intent is clamped on the server and checked again in the browser.
5. Results come only from live database queries.

*the model shapes the search. it never writes the results.*

## Stack

### frontend

- **Next.js 16**: one App Router app for every audience
- **React 19 and TypeScript**: the interface and the code around it
- **Tailwind CSS**: styling under the design-system layer
- **MapLibre GL**: maps and 3D buildings
- **three.js**: custom 3D layers and storey picking

### backend

- **Supabase**: Postgres, auth, storage and Edge Functions

### data

- **PostgreSQL with PostGIS**: listings, geography and row-level security

### ai

- **pgvector**: embeddings for semantic search
- **GLM-4.5-Air**: search intent from free text
- **Claude Code**: multi-agent build waves

### mobile

- **SwiftUI**: the iOS app, in development

### infra

- **Vercel and Cloudflare**: hosting and scheduled jobs behind a CDN

### design

- **Phosphor**: one icon library across every surface

### other

- **Vitest and Playwright**: unit tests and visual baselines

## Design

The brand mark and the app icon are mine, and so is the design system, built twice: first a 19-board, mobile-first library on canvas, then a code layer of about 350 files. Lint rules ban any colour or icon outside the system, so the marketplaces, the portal and the admin console share one visual language. 1,023 visual-regression baselines, in light and dark at 1440 and 390 px, catch any drift.

The design system has its own case: [Novi Kvadrat Design System](https://secretocho.design/work/novi-kvadrat-design-system/).

![The Novi Kvadrat home page in the dark theme on a desktop browser.](https://secretocho.design/_astro/home-desktop-dark.CBsOcIpF_bK4ak.jpg)

*fig · the home page, dark*

![A city guide on a desktop browser: Belgrade’s overview and figures beside its map.](https://secretocho.design/_astro/guide-desktop-light.ksvIoIQ2_1SKFzG.jpg)

*fig · a city guide*

![The Novi Kvadrat home page on a phone.](https://secretocho.design/_astro/home-phone-light.jp0xqn4D_11DKWU.jpg)

*home*

![A new-build project page on a phone.](https://secretocho.design/_astro/project-phone-light.DpS6eGOK_Z2lygO0.jpg)

*project*

![A city guide on a phone: Belgrade’s overview and figures.](https://secretocho.design/_astro/guide-phone-light.VerYRsXF_ZDSxek.jpg)

*guide*

## wc -l

· as of Oct 2026

- **new-build projects listed, across 29 cities**: ~480
- **developers with projects on the platform**: 352
- **pages**: 277
- **API route handlers**: 601
- **lines of TypeScript**: ~1.1M
- **Postgres migrations, RLS on every table**: 390
- **languages: en, sr, tr, de, ru**: 5
- **commits since Dec 2025**: 844
- **test files**: 2,354
- **visual-regression baselines**: 1,023
- **SQL proofs, with 53/53 mutants killed**: 292/292
- **correct storey picks in 81 GPU runs**: 99.65%

## Timeline

1. Dec 2025 · First commit; design and build begin
2. 26 Jul 2026 · City and area guides launch · 34 guides, AI-drafted
3. Oct 2026 · 3D buildings BD0–BD9 deployed · the public viewer waits behind a flag

## How it was built

Built in waves: I write the code with AI agents, the two customer-relations leads run QA on what lands, and the company’s weekly feedback steers the next wave. 844 commits since December 2025, about 9 in 10 co-authored with Claude. A lead session freezes the contracts, builder agents work in parallel, reviewers on a different model check their work, and hard gates decide what lands.

The tests were tested too: the SQL proofs pass 292 of 292 checks and caught all 53 planted mutants. A production build is a required gate, ever since type checks and unit tests missed a server-only module leaking into the browser bundle.

**292/292** · SQL proof checks pass; 53 of 53 planted mutants caught

1. lead session
2. builder agents
3. reviewers · on a different model
4. hard gates

## Status and next

Live today in five languages. What comes next is drawn faint until it ships.

**5** · languages, live at novikvadrat.rs

1. live at novikvadrat.rs · rent + sale · admin + portal
2. public 3D viewer · behind a flag
3. developer models · behind a flag
4. SwiftUI companion app · in development

## Proves

- [Frontend and web](https://secretocho.design/about/#capabilities)
- [Data, maps and 3D](https://secretocho.design/about/#capabilities)
- [Security and data integrity](https://secretocho.design/about/#capabilities)
- [AI inside products](https://secretocho.design/about/#capabilities)
- [Design systems](https://secretocho.design/about/#capabilities)
- [AI-orchestrated delivery](https://secretocho.design/about/#capabilities)

## Related

- [Axel Properties](https://secretocho.design/work/axel-properties/)
- [Novi Kvadrat Design System](https://secretocho.design/work/novi-kvadrat-design-system/)
