Skip to content

slinkydeveloper/re-state

Repository files navigation

Re-State: Real Estate Tracker

A real estate tracking application for house hunting in Italy, powered by Restate for durable execution and Vercel AI SDK for intelligent property analysis.

Features

  • 🏠 Property Scraping: Automatically extract property details from idealista.it and immobiliare.it
  • πŸ“Š Property Management: Track properties with customizable status pipeline (to reach out β†’ visit β†’ offer β†’ bought/rejected)
  • πŸ“ Notes: Add manual notes to each property for additional context
  • πŸ€– AI Analysis: Ask questions about your properties and get intelligent comparisons and insights
  • πŸ” Filtering & Sorting: Easily filter by status and sort by price, size, or status
  • πŸ’ͺ Durable Execution: Powered by Restate - scraping and AI operations survive failures

Tech Stack

  • Backend: Restate Virtual Objects for stateful workflow management
  • AI: Vercel AI SDK with OpenAI GPT-4o for property analysis
  • Frontend: Next.js 15 (App Router)
  • Scraping: Cheerio for HTML parsing, AI-powered data extraction
  • Language: TypeScript

Prerequisites

Getting Started

1. Install Dependencies

npm install

2. Set Environment Variables

Create a .env.local file or export the OpenAI API key:

export OPENAI_API_KEY=your_openai_api_key

3. Start Restate Server

In a separate terminal, start the Restate server (the durable orchestrator):

npx @restatedev/restate-server@latest

The server will start on:

  • API endpoint: http://localhost:8080
  • Admin UI: http://localhost:9070

4. Start Next.js Development Server

npm run dev

The Next.js app will start on http://localhost:3000

5. Register Services with Restate

Register your services so Restate can proxy and durably execute them:

npx @restatedev/restate deployments register -y --use-http1.1 http://localhost:3000/restate

You can also register services via the Restate Admin UI at http://localhost:9070

6. Use the Application

Open http://localhost:3000 in your browser and:

  1. Create a new research project with your search criteria
  2. Add property listings from idealista.it or immobiliare.it
  3. Track properties through your pipeline
  4. Ask AI questions about your properties

Architecture

The application follows a 3-tier architecture:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚         Next.js Frontend (React)        β”‚
β”‚  - Research creation page               β”‚
β”‚  - Property table with filtering/sortingβ”‚
β”‚  - Q&A sidebar                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚
                  β”‚ HTTP
                  β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚       Next.js API Routes (REST)         β”‚
β”‚  - /api/research                        β”‚
β”‚  - /api/ads                             β”‚
β”‚  - /api/questions                       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚
                  β”‚ Restate Client
                  β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           Restate Server                β”‚
β”‚  (Proxies & durably executes services)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                  β”‚
                  β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    ResearchTracker Virtual Object       β”‚
β”‚  - Stores research criteria & ads       β”‚
β”‚  - Scrapes property listings (durable)  β”‚
β”‚  - AI-powered Q&A (durable LLM calls)   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

How Scraping Works

  1. User submits a property URL (idealista.it or immobiliare.it)
  2. API route calls ResearchTracker Virtual Object via Restate
  3. Virtual Object determines which scraper to use based on domain
  4. Scraper fetches HTML with proper User-Agent headers
  5. AI (GPT-4o-mini) extracts structured data from HTML using Italian prompts
  6. Property data is stored in Virtual Object state with deterministic ID
  7. Result returned to frontend

Key durability features:

  • ctx.run() wraps scraping to journal results (runs only once)
  • ctx.rand.uuidv4() generates deterministic IDs for properties
  • durableCalls() middleware journals LLM responses for Q&A

API Endpoints

Research

  • POST /api/research - Create new research project

    • Body: { name: string, criteria: string }
    • Returns: { name: string, criteria: string }
  • GET /api/research/:name - Get research criteria

    • Returns: { name: string, criteria: string }

Ads

  • POST /api/ads/:researchName - Add property listing

    • Body: { url: string }
    • Returns: PropertyAd object
  • GET /api/ads/:researchName - List all ads

    • Returns: { ads: PropertyAd[] }
  • PATCH /api/ads/:researchName/:adId/status - Update ad status

    • Body: { status: "to reach out" | "visit appointment taken" | "sent the offer" | "bought" | "rejected" }
  • PATCH /api/ads/:researchName/:adId/notes - Update ad notes

    • Body: { notes: string }

Questions

  • POST /api/questions/:researchName - Ask AI question

    • Body: { question: string }
    • Returns: { question: string, answer: string }
  • GET /api/questions/:researchName - Get Q&A history

    • Returns: { questions: QuestionAnswer[] }

Development

Project Structure

re-state/
β”œβ”€β”€ app/                           # Next.js app directory
β”‚   β”œβ”€β”€ page.tsx                   # Home page (research creation)
β”‚   β”œβ”€β”€ research/[name]/page.tsx   # Research management page
β”‚   └── api/                       # API routes
β”‚       β”œβ”€β”€ research/              # Research endpoints
β”‚       β”œβ”€β”€ ads/                   # Property ad endpoints
β”‚       └── questions/             # Q&A endpoints
β”œβ”€β”€ restate/                       # Restate services
β”‚   β”œβ”€β”€ endpoint.ts                # Service registration
β”‚   └── services/
β”‚       β”œβ”€β”€ types.ts               # Zod schemas & types
β”‚       β”œβ”€β”€ research-tracker.ts    # Virtual Object
β”‚       └── utils/
β”‚           β”œβ”€β”€ idealista-scraper.ts
β”‚           └── immobiliare-scraper.ts
└── package.json

Adding New Scrapers

To support additional property listing sites:

  1. Create a new scraper in restate/services/utils/
  2. Follow the same pattern as existing scrapers (AI extraction)
  3. Add domain check in research-tracker.ts addAd handler
  4. Update API route validation to allow the new domain

Monitoring

Check the Restate Admin UI at http://localhost:9070 to:

  • View invocation journals
  • See service state
  • Monitor durability and retries
  • Inspect completed operations

Deployment

This application is designed to be deployed on Vercel with Restate Cloud or self-hosted Restate:

  1. Deploy Next.js app to Vercel
  2. Set OPENAI_API_KEY in Vercel environment variables
  3. Set RESTATE_URL to your Restate Cloud or self-hosted endpoint
  4. Register services with your production Restate instance

For production deployment details, see Restate deployment docs.

About

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors