feat: add catastro SSOT integration, 3DGS hybrid pipeline, casa demo v3

- SPEC: add User Story 0 (Property Setup via Catastro) as P1 entry
- SPEC: add catastro_data and catastro_imports tables to data model
- PLAN: add Phase 2A (Catastro Integration) with 8 tasks
- AGENTS.md: add 3 key decisions (Catastro SSOT, 3DGS hybrid, plan inputs)
- Demo v3: Spanish apartment (C/ Altabix 24, 3ºB, Elche), 7 rooms,
  upload panel for catastro/DXF, proper collisions on all doors
This commit is contained in:
2026-05-29 01:03:32 +02:00
parent 3db7e47994
commit be3221e93d
8 changed files with 2785 additions and 3 deletions
+14 -1
View File
@@ -8,9 +8,22 @@
## User Scenarios & Testing
### User Story 0 — Property Setup via Catastro (Priority: P1) 🎯 MVP Entry
As a real estate agent, I enter a property address and InteriorScan fetches the building's exterior footprint from the Spanish Cadastro (INSPIRE WFS), so the 3D model starts with verified exterior walls before I upload any photos.
**Why this priority**: The Catastro provides the SSOT for exterior geometry — wall outlines, building height, and number of floors. This eliminates manual exterior wall drawing and ensures dimensional accuracy. Interior walls come from photos or user-uploaded floor plans.
**Independent Test**: Enter "C/ Altabix 24, Elche" → refcat is resolved → building polygon is displayed on a minimap → exterior walls are generated in the 3D scene.
**Acceptance Scenarios**:
1. **Given** I am creating a new project, **When** I type a Spanish address and submit, **Then** the system resolves it to a cadastral reference (refcat) and fetches the building footprint polygon from INSPIRE WFS.
2. **Given** a building footprint is fetched, **When** the 3D scene initializes, **Then** exterior walls appear at the correct dimensions matching the Catastro polygon, with the correct number of floors.
3. **Given** the Catastro lookup fails, **When** no polygon is found, **Then** the system falls back to manual wall drawing or DXF/SVG upload.
### User Story 1 — Upload & Process (Priority: P1) 🎯 MVP Core
As a real estate agent, I upload 30-100 photos of a property and InteriorScan reconstructs the interior as a 3D walkthrough, so I can share a link with potential buyers who navigate it like a first-person game.
As a real estate agent, I upload 30-100 photos of a property and InteriorScan reconstructs the interior as a 3D walkthrough, so I can share a link where potential buyers navigate it like a first-person game.
**Why this priority**: Without reconstruction, nothing else matters. This is the core value proposition.
@@ -148,6 +148,31 @@ export const processingJobs = pgTable('processing_jobs', {
createdAt: timestamp('created_at').defaultNow().notNull(),
});
// ── Catastro Data ─────────────────────────────────────
export const catastroData = pgTable('catastro_data', {
id: cuid2('id').primaryKey(),
projectId: cuid2('project_id').references(() => projects.id).notNull(),
refcat: text('refcat'), // 14-20 digit cadastral reference
addressNormalized: text('address_normalized'), // Normalized address from Catastro
buildingFootprint: jsonb('building_footprint'), // GeoJSON polygon from INSPIRE WFS
buildingHeight: text('building_height'), // e.g., "12.5" meters
numberOfFloors: integer('number_of_floors'), // From Catastro
floorArea: text('floor_area'), // m² from Catastro
gmlSource: text('gml_source'), // URL of the GML source file
fetchedAt: timestamp('fetched_at').defaultNow().notNull(),
});
export const catastroImports = pgTable('catastro_imports', {
id: cuid2('id').primaryKey(),
projectId: cuid2('project_id').references(() => projects.id).notNull(),
format: text('format').notNull(), // 'dxf', 'svg', 'png', 'gml'
originalKey: text('original_key'), // S3 key for uploaded file
parsedWalls: jsonb('parsed_walls'), // Array of {x1, z1, x2, z2, height, thickness}
source: text('source').notNull(), // 'catastro', 'upload', 'manual'
createdAt: timestamp('created_at').defaultNow().notNull(),
});
// ── Subscriptions ───────────────────────────────────
export const subscriptions = pgTable('subscriptions', {
+15 -2
View File
@@ -46,9 +46,22 @@ See `data-model.md` (separate document — same directory).
---
## Phase 2: Photo Upload & Processing Pipeline (P1) 🎯 MVP Core
## Phase 2: Property Setup & Photo Upload (P1) 🎯 MVP Core
### 2A: Upload API
### 2A: Catastro Integration
- [ ] T007 Create `packages/catastro/` — Catastro client package
- [ ] T008 Write failing test: address "C/ Altabix 24, Elche" → refcat resolved
- [ ] T009 Implement OVK address search (SOAP/REST → refcat)
- [ ] T010 Write failing test: refcat → building polygon GML from INSPIRE WFS
- [ ] T011 Implement INSPIRE WFS client (GML → GeoJSON polygon)
- [ ] T012 Implement GML polygon → wall segments converter (`{x1,z1,x2,z2,height,thickness}`)
- [ ] T13 Write failing test: POST /api/v1/projects with address → catastro_data populated
- [ ] T014 Implement project creation with Catastro lookup (address → refcat → footprint → walls)
**Checkpoint**: Enter "C/ Altabix 24, Elche" → building polygon rendered in minimap → exterior walls in 3D scene.
### 2B: Photo Upload API
- [ ] T007 Write failing test: POST /api/v1/projects with photos returns 201 + project ID
- [ ] T008 Implement project creation endpoint with Zod validation