Skip to content

daveharmswebdev/upkeep-io

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

55 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Upkeep.io - Property Management System

A full-stack property management application built with Clean Architecture principles, featuring maintenance tracking, expense management, and vendor coordination across a portfolio of rental properties.

Architecture

Clean Architecture + DDD

This project follows Clean Architecture with strict separation of concerns:

apps/backend/src/
├── core/           # Pure domain models (no external dependencies)
├── domain/         # Abstract interfaces (repositories, services)
├── application/    # Use cases (pure business logic, fully testable)
├── infrastructure/ # Concrete implementations (Prisma, Bcrypt, JWT)
├── presentation/   # HTTP layer (controllers, middleware, routes)
├── container.ts    # Dependency injection (inversify)
└── server.ts       # Entry point (imports reflect-metadata FIRST)

Key Principles:

  • Domain entities never import from infrastructure or presentation
  • Use cases depend only on domain interfaces, never concrete implementations
  • All dependencies injected via inversify container
  • Changing from Prisma to MongoDB requires zero changes to domain/application layers

Tech Stack

Backend

  • Node.js + Express - REST API
  • TypeScript - Type safety
  • Prisma - Database ORM (local dev)
  • Flyway - Migration management (production)
  • PostgreSQL - Primary database
  • inversify - Dependency injection
  • bcrypt - Password hashing
  • JWT - Authentication
  • Jest - Testing

Frontend

  • Vue 3 - UI framework
  • Vite - Build tool
  • Pinia - State management
  • Vue Router - Client-side routing
  • Axios - HTTP client with JWT interceptors
  • TypeScript - Type safety

Infrastructure

  • Docker - Containerization
  • Railway - Hosting platform
  • GitHub Actions - CI/CD
  • Redis - Caching (planned)

Getting Started

Prerequisites

  • Node.js 18+
  • npm 9+
  • Docker & Docker Compose (for containerized setup)
  • PostgreSQL (for local non-Docker setup)

Installation

  1. Clone the repository

    git clone <repository-url>
    cd upkeep-io
  2. Install dependencies

    npm install
  3. Set up environment variables

    # Backend
    cp apps/backend/.env.example apps/backend/.env
    # Edit apps/backend/.env with your database credentials
    
    # Frontend
    cp apps/frontend/.env.example apps/frontend/.env
  4. Run database migrations

    npm run migrate:dev --workspace=apps/backend

Development

Option 1: Docker Compose (Recommended)

Run all services with a single command:

docker-compose up

Option 2: Local Development

Run backend and frontend separately:

# Terminal 1 - Backend
npm run dev:backend

# Terminal 2 - Frontend
npm run dev:frontend

Testing

# Run all tests
npm test

# Run unit tests only (use cases with mocked repositories)
npm run test:unit

# Run integration tests
npm run test:integration

# Watch mode
npm run test:watch --workspace=apps/backend

Building for Production

# Build all workspaces
npm run build

# Build backend only
npm run build:backend

# Build frontend only
npm run build:frontend

Project Structure

upkeep-io/
├── apps/
│   ├── backend/              # Express API
│   │   ├── src/
│   │   │   ├── application/  # Use cases (CreateUser, Login, CreateProperty)
│   │   │   ├── domain/       # Interfaces (IUserRepository, IPasswordHasher)
│   │   │   ├── infrastructure/ # Implementations (PrismaUserRepository, BcryptPasswordHasher)
│   │   │   ├── presentation/ # Controllers, routes, middleware
│   │   │   ├── container.ts  # DI configuration
│   │   │   └── server.ts     # Entry point
│   │   ├── prisma/           # Database schema
│   │   ├── Dockerfile
│   │   └── package.json
│   └── frontend/             # Vue 3 app
│       ├── src/
│       │   ├── api/          # Axios client with JWT interceptor
│       │   ├── stores/       # Pinia stores (auth)
│       │   ├── router/       # Vue Router with protected routes
│       │   ├── views/        # Pages (Login, Signup, Dashboard)
│       │   ├── App.vue
│       │   └── main.ts
│       ├── Dockerfile
│       ├── nginx.conf
│       └── package.json
├── libs/
│   ├── domain/               # Shared entities (User, Property) and errors
│   ├── validators/           # Zod schemas for input validation
│   └── auth/                 # JWT utilities
├── migrations/               # Flyway SQL migrations for production
├── .github/workflows/        # CI/CD pipelines
├── docker-compose.yml
├── package.json              # Workspace root
└── tsconfig.json             # Root TypeScript config with path aliases

Domain Model

Core Entities

  • User - System users (property owners)
  • Property - Rental properties with addresses and metadata
  • MaintenanceWork - Central aggregate for tracking work, costs, and travel (planned)
  • WorkPerformer - Tracks who did work (owner, family, vendor) and time (planned)
  • Vendor - Reusable vendors (HVAC, plumbers, etc.) (planned)
  • Receipt - Material purchases for tax deduction tracking (planned)
  • TravelActivity - Mileage tracking for IRS deductions (planned)
  • RecurringService - Scheduled vendor services (planned)

See property-management-domain-model.md for detailed specifications.

API Documentation

Interactive API Documentation: http://localhost:3000/api-docs

Full Swagger/OpenAPI 3.0 documentation is available at /api-docs when running the backend server. The interactive UI allows you to:

  • Browse all endpoints with detailed descriptions
  • View request/response schemas auto-generated from Zod validators
  • Test endpoints directly with "Try it out" functionality
  • Authenticate with JWT tokens for protected endpoints

Quick Reference

Authentication

  • POST /api/auth/signup - Create new user account
  • POST /api/auth/login - Login and receive JWT token

Properties (Protected - requires JWT)

  • POST /api/properties - Create a new property
  • GET /api/properties - List all properties for authenticated user
  • GET /api/properties/:id - Get property by ID
  • PUT /api/properties/:id - Update property
  • DELETE /api/properties/:id - Delete property

Leases (Protected - requires JWT)

  • POST /api/leases - Create a new lease with lessees and occupants
  • GET /api/leases - List all leases
  • GET /api/leases/:id - Get lease by ID with details
  • PUT /api/leases/:id - Update lease
  • DELETE /api/leases/:id - Delete lease (soft delete)
  • GET /api/leases/property/:propertyId - List leases for a property
  • POST /api/leases/:id/lessees - Add lessee to lease
  • DELETE /api/leases/:id/lessees/:personId - Remove lessee from lease
  • POST /api/leases/:id/occupants - Add occupant to lease
  • DELETE /api/leases/:id/occupants/:occupantId - Remove occupant from lease

For complete details, examples, and to test the API interactively, visit /api-docs

Environment Variables

Backend (apps/backend/.env)

DATABASE_URL=postgresql://user:password@localhost:5432/upkeep_dev
JWT_SECRET=your-secret-key-change-this-in-production
JWT_EXPIRES_IN=7d
PORT=3000
NODE_ENV=development
CORS_ORIGIN=http://localhost:5173

Frontend (apps/frontend/.env)

VITE_API_URL=http://localhost:3000/api

Deployment

Railway Setup

  1. Create Railway Project with services:

    • PostgreSQL database
    • Backend (Node.js)
    • Frontend (Static)
    • Redis (optional)
  2. Configure Environment Variables in Railway dashboard

  3. Set up GitHub Secrets:

    • RAILWAY_TOKEN
    • RAILWAY_DATABASE_URL
    • RAILWAY_DATABASE_USER
    • RAILWAY_DATABASE_PASSWORD
  4. Push to main branch - GitHub Actions will:

    • Run tests
    • Apply Flyway migrations
    • Deploy backend and frontend

Database Migrations

Local Development (Prisma)

# Create and apply migration
npm run migrate:dev --workspace=apps/backend

# Check migration status
npm run migrate:status --workspace=apps/backend

# Regenerate Prisma client
npm run generate --workspace=apps/backend

Production (Flyway)

  1. Update apps/backend/prisma/schema.prisma
  2. Run npm run migrate:dev to generate Prisma migration
  3. Copy generated SQL to migrations/VXXX__description.sql
  4. Commit and push - GitHub Actions runs Flyway

Testing Philosophy

  • Unit Tests - Test use cases with mocked repositories (no database, no Express)
  • Integration Tests - Test full request flow with real database
  • Use cases in application/ layer should have 100% coverage
  • Controllers in presentation/ layer should be thin

Example testable use case:

// Fully testable without database
const mockRepo = { findById: jest.fn(), save: jest.fn() };
const useCase = new CreateUserUseCase(mockRepo, mockHasher, mockTokenGen);
const result = await useCase.execute({ email, password, name });

Cost Budget

Target: $100/month

  • Railway services: ~$35-45/month
  • PostgreSQL, Redis, Backend, Frontend
  • Leaves $55-65 for scaling

Contributing

  1. Create feature branch from main
  2. Implement changes following Clean Architecture
  3. Write unit tests for use cases
  4. Ensure all tests pass: npm test
  5. Create pull request

License

Proprietary - All rights reserved

Resources

About

Rental property management platform

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •