diff --git a/.specify/specs/001-interiorscan-mvp/SPEC.md b/.specify/specs/001-interiorscan-mvp/SPEC.md index b98ff1d..f25f656 100644 --- a/.specify/specs/001-interiorscan-mvp/SPEC.md +++ b/.specify/specs/001-interiorscan-mvp/SPEC.md @@ -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. diff --git a/.specify/specs/001-interiorscan-mvp/data-model.md b/.specify/specs/001-interiorscan-mvp/data-model.md index 2f0cd51..5df4af5 100644 --- a/.specify/specs/001-interiorscan-mvp/data-model.md +++ b/.specify/specs/001-interiorscan-mvp/data-model.md @@ -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', { diff --git a/.specify/specs/001-interiorscan-mvp/plan.md b/.specify/specs/001-interiorscan-mvp/plan.md index 8316c43..18251a2 100644 --- a/.specify/specs/001-interiorscan-mvp/plan.md +++ b/.specify/specs/001-interiorscan-mvp/plan.md @@ -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 diff --git a/AGENTS.md b/AGENTS.md index 685e6f7..3454e70 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -41,6 +41,9 @@ See `.specify/memory/constitution.md` β€” all development must comply. - **Self-hosted**: All infra self-hosted except Stripe. - **API-first**: Every feature has REST API before UI. - **Open exports**: OBJ, E57, LAS/LAZ, DXF minimum. IFC in P4+. +- **Catastro SSOT**: Spanish Cadastro (INSPIRE WFS) is the single source of truth for building exterior geometry. Address β†’ refcat β†’ footprint polygon β†’ exterior walls. Interior comes from photos. +- **3DGS for visuals**: Hybrid pipeline β€” mesh for collision/measurement, Gaussian Splatting for visual quality (gsplat MIT license, never graphdeco-inria research-only). +- **Plan inputs**: (1) Catastro address lookup, (2) DXF/SVG/PNG upload, (3) manual wall editor, in that order of preference. ## Development Commands diff --git a/demo-v2-textured.html b/demo-v2-textured.html new file mode 100644 index 0000000..7e9158b --- /dev/null +++ b/demo-v2-textured.html @@ -0,0 +1,971 @@ + + + + + + InteriorScan β€” Textured Walkthrough Demo + + + +
+
+ +
πŸ“ Mercedes-Benz Vegar Β· PolΓ­gono 122, Elche
+
Walkthrough Ready
+
+ + + + + +
+
+ +
+ +
+ +
+
Showroom Principal
+
8.2m Γ— 12.4m Β· 101.7 mΒ²
+
+ +
Floor Plan
+ +
+
Room:Showroom Principal
+
Dimensions:8.24 Γ— 12.38 m
+
Area:101.93 mΒ²
+
Height:3.10 m
+
Photos used:47 / 68
+
+ +
+
πŸ“· Reconstruction Pipeline
+
COLMAP SfM β†’ camera poses
+
OpenMVS β†’ dense cloud
+
Mesh generation
+
Photo texturing βœ“
+
LOD + Draco compression
+
+ +
🎨 Photo textures active
+ +
+
WASD Move
+
Mouse Look
+
Shift Sprint
+
M Measures
+
T Textures
+
F Wireframe
+
+ +
+

InteriorScan

+
+ Photo-textured 3D walkthrough.
+ Real photos projected onto reconstructed geometry. +
+
Click to Enter
+
WASD move Β· Mouse look Β· Shift sprint Β· T textures Β· F wireframe
+
+
+
+ + + + + + \ No newline at end of file diff --git a/demo-v3-casa.html b/demo-v3-casa.html new file mode 100644 index 0000000..e6cfd38 --- /dev/null +++ b/demo-v3-casa.html @@ -0,0 +1,582 @@ + + + + + + InteriorScan β€” Casa Demo + + + +
+
+ +
πŸ“ C/ Altabix 24, 3ΒΊB Β· Elche
+
87 fotos procesadas
+
+ + + + +
+
+ +
+ +
+
+
SalΓ³n
+
5.2m Γ— 4.1m Β· 21.3 mΒ²
+
+
Plano cargado
+ + + +
+
πŸ“· Pipeline de reconstrucciΓ³n
+
Plano catastral β†’ muros
+
87 fotos β†’ COLMAP SfM
+
OpenMVS β†’ malla densa
+
Texturizado foto β†’ malla βœ“
+
+ +
+
WASD Mover
+
RatΓ³n Mirar
+
Shift Correr
+
M Medidas
+
T Texturas
+
F Malla
+
+ +
+

Carga un plano

+
Sube el plano arquitectΓ³nico o catastral para definir la geometrΓ­a. Luego las fotos texturizan el interior.
+
+ +
Arrastra un plano (DXF, SVG, PNG, PDF)
+
O pega una captura del catastro
+
+
β€” o usa una demo β€”
+ +
+ β‘  Plano β†’ Muros + β‘‘ Fotos β†’ Texturas + β‘’ Explorar +
+
+
+
+ + + + + \ No newline at end of file diff --git a/demo.html b/demo.html new file mode 100644 index 0000000..6b24156 --- /dev/null +++ b/demo.html @@ -0,0 +1,1128 @@ + + + + + + InteriorScan β€” FPS Walkthrough Demo + + + +
+ +
+ +
πŸ“ Mercedes-Benz Vegar Β· PolΓ­gono 122, Elche
+
Walkthrough Ready
+
+ + + +
+
+ + +
+ + + +
+ + + + + +
+ + +
+
Showroom Principal
+
8.2m Γ— 12.4m Β· 101.7 mΒ²
+
+ + +
+ +
Floor Plan
+
+ + + + + +
360Β° Photo Mode
+ + +
+
+ WASD Move +
+
+ Mouse Look +
+
+ Shift Sprint +
+
+ M Measures +
+
+ E 360Β° +
+
+ Esc Free cursor +
+
+ + +
+

InteriorScan

+
+ Walk through this space like a video game.
+ Not a slideshow β€” a real 3D experience. +
+
Click to Enter
+
WASD to move Β· Mouse to look Β· Tap to walk on mobile
+
+
+
+ + + + + + + \ No newline at end of file diff --git a/setup-samba.sh b/setup-samba.sh new file mode 100755 index 0000000..e7c31d1 --- /dev/null +++ b/setup-samba.sh @@ -0,0 +1,47 @@ +#!/bin/bash +# Setup Samba share for ~/projects (InteriorScan and other repos) +# Run with: sudo bash ~/projects/interiorscan/setup-samba.sh + +set -e + +echo "=== Setting up Samba share for ~/projects ===" + +# 1. Add share to smb.conf +if ! grep -q "\[projects\]" /etc/samba/smb.conf; then + cat >> /etc/samba/smb.conf << 'EOF' + +[projects] + comment = Development Projects + path = /home/monyi/projects + browseable = yes + read only = no + guest ok = yes + create mask = 0664 + directory mask = 0775 + force user = monyi +EOF + echo "βœ“ Share [projects] added to smb.conf" +else + echo "⚠ Share [projects] already exists in smb.conf" +fi + +# 2. Set permissions on projects dir +chmod -R 775 /home/monyi/projects 2>/dev/null || true +echo "βœ“ Permissions set on /home/monyi/projects" + +# 3. Test config +echo "" +echo "Testing Samba config..." +testparm -s 2>/dev/null | grep -A5 "\[projects\]" || echo "Run 'sudo testparm' to verify" + +# 4. Restart Samba +echo "" +echo "Restarting Samba services..." +systemctl restart smbd nmbd 2>/dev/null || service smbd restart 2>/dev/null || echo "⚠ Could not restart smbd β€” run: sudo systemctl restart smbd nmbd" + +echo "" +echo "=== Done! ===" +echo "From Windows, open: \\\\192.168.1.13\\projects" +echo "Or in File Explorer: \\\\192.168.1.13\\projects" +echo "" +echo "The demo.html is at: \\\\192.168.1.13\\projects\\interiorscan\\demo.html" \ No newline at end of file