SecretoCho
menu

case 01 / 05live

Novi Kvadrat

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

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.

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.
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.
fig · a project page
  1. Browsers client5 languages
    • to Next.js app: cookies
  2. Next.js app service277 pages
    • to Postgres: queries
    • to Edge Function: parse query
  3. Cron jobs processcrons + pg_cron
    • to Postgres: rollups
  4. Edge Function serviceAI search
  5. Postgres storeRLS everywhere
  6. Official data externalstats, registry
    • to Postgres: ingest
  7. iOS app client · in buildSwiftUI
    • to Postgres: Swift SDK
  8. OpenStreetMap externalopen 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 model
  • an 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 service
  • photoreal map tiles
  • MapLibre and three.js on open data
chose
MapLibre and three.js on open data

Image variants

options
  • paid image transforms
  • a 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 once
  • twins 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.

rent + saleadmin + portal5 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.
fig · a layout, desktop
The same layout page on a phone, the floor plan first.
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.
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.
trace and link · staff admin · placeholder data
Linking: a building record dragged onto its traced shape.
link · staff admin · placeholder data
Matching the map: the map’s building outlines grouped under the developer’s eight buildings, before a merge.
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.
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.
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.

correct picks 99.65%gpu runs 815,400 storeys in ~123 msfloor plate 13 ms

the floor you click is the floor you get. measured before built.
  1. OpenStreetMap externalfootprints
    • to Buildings: Overpass
  2. Buildings processsales buildings
    • to Storeys: slabs
  3. Storeys processone per floor
    • to Floor plate: pick ray
  4. Floor plate serviceopens in 13 ms
    • to Public viewer
  5. Staff studio clientBD0–BD9
    • to Buildings: edit
  6. Dev models process · plannedGLB · flagged
    • to Storeys: placed
  7. Public viewer client · plannedbehind 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.
fig · 3D Buildings Studio · staff admin · placeholder data
Grouping: the map’s parts gathered into the developer’s buildings, as a draft before Save.
group the map · staff admin · placeholder data
The storey stack of one building, with each storey’s height.
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.
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.
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.
fig · the whole-floor plan · design · placeholder data

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.

The Novi Kvadrat home page in the dark theme on a desktop browser.
fig · the home page, dark
A city guide on a desktop browser: Belgrade’s overview and figures beside its map.
fig · a city guide
The Novi Kvadrat home page on a phone.
home
A new-build project page on a phone.
project
A city guide on a phone: Belgrade’s overview and figures.
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. First commit; design and build begin
  2. City and area guides launch34 guides, AI-drafted
  3. 3D buildings BD0–BD9 deployedthe 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/292SQL proof checks pass; 53 of 53 planted mutants caught
  1. lead session
  2. builder agents
  3. reviewerson a different model
  4. hard gates

Status and next

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

5languages, live at novikvadrat.rs
  1. live at novikvadrat.rsrent + sale · admin + portal
  2. public 3D viewerbehind a flag
  3. developer modelsbehind a flag
  4. SwiftUI companion appin development