Nest Easy
Manage & Build
Platform Delivery Briefing — Team & Developer Handover
ClientAS Elite Estates LTD (Nest Easy) StatusLive in Production ✓ DateFebruary 2026 Prepared byAgile Tech Solutions
02 Headline
We built a full PropTech platform ahead of schedule —
and it's already live.
The original brief expected a phased delivery over many months. We moved fast, made the right technical decisions up front, and delivered a complete MVP that exceeds what was scoped.
11
Backend Modules
Auth, Properties, Tenancies, Payments, Compliance, Maintenance, Documents, Notifications, Audit, Reports, Users
20+
Frontend Pages
Full dashboard, tenant portal, all CRUD views, compliance tracking, financial reports, admin panel
6
Live Containers
API, Web, Nginx, PostgreSQL + PostGIS, Redis, MinIO — all running on VPS
100%
MVP Criteria Met
Every success criterion from the original spec has been delivered and is live
01
The full feature set, explained clearly for the team and client.
04 Brief vs Delivered
Original Requirements → Status
Requirement What Was Scoped What Was Built Status
Property Management Add, edit, archive properties Full CRUD, multi-type (Flat/House/HMO), portfolio view, PostGIS geospatial fields ✓ Live
Tenancy Management Agreements, dates, status Full tenancy lifecycle, status engine, rent/deposit tracking, renewal tracking ✓ Live
Rent Collection Stripe payments, reminders Stripe integration, payment history, overdue detection, Bull queue email reminders ✓ Live
Compliance Tracking 6 certificate types, Awaab's Law All 6 types, expiry tracking, RAG status, automated alerts at 90/30/7 days, PDF export ✓ Live
Maintenance & Repairs Requests, contractor assignment Full workflow (Open→Resolved), Awaab's deadlines, cost tracking, photo uploads ✓ Live
Document Management Upload, categorise, download MinIO storage, presigned downloads, category tags, bulk export ✓ Live
Financial Reporting Rent roll, arrears, forecasting Full financial dashboard, rent roll, arrears report, income/expense, CSV/PDF export ✓ Live
Tenant Portal View tenancy, pay rent, requests Dedicated tenant interface, payment gateway, maintenance requests, notifications ✓ Live
Notifications In-app bell, email alerts Real-time bell with unread count, email via Nodemailer, full history, mark-read ✓ Live
Audit Logging Immutable trail, searchable Every action logged, admin panel with filters (user/action/entity/date), pagination ✓ Live
Admin Panel Not in original spec User management (roles, activate/deactivate), audit log viewer — added proactively ✓ Bonus
Subscription Tiers Stripe subscriptions, RBAC Schema built, Stripe webhook ready — UI config pending (Phase 2 item) ⚡ Phase 2
05 Live Platform — Every Page
Manager / Admin Dashboard
  • /login & /register — JWT auth, role-gated
  • /properties — portfolio list, search, filter by type
  • /properties/[id] — full detail: tenancies, compliance, maintenance, docs
  • /properties/new — create property with full form validation
  • /tenants — all tenants, linked tenancies, status
  • /finance — rent roll, arrears, income vs expense, forecast
  • /compliance — RAG dashboard, all certificate types across portfolio
  • /maintenance — all requests, priority filter, contractor assignment
  • /documents — file library, category filter, presigned download
  • /settings — user profile, notification preferences
  • /admin/users — user management (ADMIN role only)
  • /admin/audit — full audit log with filters (ADMIN role only)
Tenant Portal
  • Dedicated simplified interface
  • View tenancy details and documents
  • Make rent payments via Stripe
  • Raise maintenance requests with photos
  • In-app notifications
User Roles
ADMIN PROPERTY_MANAGER LANDLORD TENANT CONTRACTOR
Production URL
https://nest.agiletechsolutions.co.uk
02
Every technology choice, why it was chosen, and what it does.
07 Full Technology Stack
Layer Technology Version Why This Choice
FrontendNext.js (App Router)14Server-side rendering, React Server Components, SEO-ready. App Router gives layout nesting and streaming.
Backend APINestJS10TypeScript-native, decorator-based, modular architecture. Built-in DI, Guards, Interceptors. Scales cleanly.
LanguageTypeScript5End-to-end type safety. Shared types package ensures frontend/backend contract is never broken.
DatabasePostgreSQL + PostGIS15Relational integrity for tenancy/payment data. PostGIS extension adds geospatial queries for future map features.
ORMPrisma7Type-safe schema-as-code, auto-generated client, migration system. Single source of truth for DB shape.
AuthJWT (access + refresh)Stateless authentication. Access token (15 min) + refresh token (7 days) pattern. Bcrypt password hashing.
PaymentsStripeIndustry standard. Handles PCI compliance. Supports rent collection, subscriptions, deposits.
File StorageMinIOS3-compatible, self-hosted on the same VPS. No AWS dependency. Full data ownership.
Background JobsBull + RedisQueue-based job processing for email reminders, compliance alerts, PDF generation. Retries, scheduling.
EmailNodemailerSends via SMTP. Rent reminders, compliance expiry alerts, maintenance updates.
StylingTailwind CSS3Utility-first. No CSS files to maintain. Consistent design tokens. Works perfectly with component patterns.
State (Frontend)TanStack Query5Server state management. Caching, background refetch, optimistic updates. Replaces Redux for data fetching.
Reverse ProxyNginxAlpineRoutes /api/* to NestJS, /* to Next.js. Cloudflare IP allowlist, rate limiting, security headers.
ContainerisationDocker + Compose6-service stack runs identically in dev and production. No environment drift. Kubernetes-ready when needed.
CDN / DDoSCloudflareProxy in front of VPS. Handles SSL termination, DDoS protection, firewall rules.
08 System Architecture
How a request flows
🌐 Browser / Tenant App
☁️ Cloudflare
SSL · DDoS · CDN
↓ HTTP (port 80)
🔀 Nginx
Reverse Proxy · Rate Limit
Cloudflare IP allowlist
↓ routes by path
⚛️ Next.js :3000
Web UI (SSR)
🔌 NestJS :3001
REST API + Auth
↓ Prisma ORM
🐘 PostgreSQL + PostGIS
⚡ Redis
📦 MinIO
Traffic rules (Nginx)
  • /api/auth/* → NestJS, strict rate limit (5 req/min)
  • /api/stripe/webhook → NestJS, no rate limit (Stripe needs raw body)
  • /api/* → NestJS, standard rate limit (30 req/sec)
  • /* → Next.js (SSR pages)
Security layers
  • Cloudflare proxy — only Cloudflare IPs accepted at Nginx (all others → 444)
  • JWT Bearer auth on every API route
  • RBAC — every endpoint gated by role
  • Bcrypt password hashing (salt rounds: 10)
  • Nginx security headers (X-Frame-Options, CSP-ready, nosniff)
  • PostgreSQL exposed only on 127.0.0.1 (not to internet)
  • Redis + MinIO internal-only (Docker network)
09 Database Schema — Core Models
Core Entities
ModelKey FieldsPurpose
Useremail, passwordHash, role, isActive, refreshTokenHashAll platform users (all roles)
Propertyaddress, type, ownerId, managerId, geom (PostGIS), isActivePortfolio of managed properties
TenancypropertyId, tenantId, startDate, endDate, rentAmount, status, depositAmountTenancy agreements
PaymenttenancyId, amount, dueDate, paidAt, stripePaymentId, statusRent payment records
ComplianceItempropertyId, type (Gas/EICR/EPC…), expiryDate, status, alertSentCertificate tracking
MaintenanceRequestpropertyId, tenantId, status, priority, contractorId, AwaaabDeadlineRepair jobs
Supporting Entities
ModelKey Fields
DocumentpropertyId, uploadedBy, fileKey (MinIO), type, category, fileSize
AuditLoguserId, action, entity, entityId, metadata (JSON), ipAddress, createdAt
NotificationuserId, type, title, message, read, relatedEntity
SubscriptionuserId, stripeSubscriptionId, plan, status, currentPeriodEnd
MaintenancePhotorequestId, fileKey, uploadedBy, stage (before/after)
Key Design Decisions
  • Single User model for all roles — role field determines access
  • PostGIS geometry column on Property — ready for map features without schema change
  • AuditLog is append-only — no updates or deletes permitted
  • Document files stored in MinIO by key — DB holds metadata only
  • Compliance expiry tracked at item level — allows per-certificate alert history
  • All monetary amounts stored as Decimal (not float) — no rounding errors
  • RefreshTokenHash on User — supports token rotation and invalidation on logout
Database
# Connect
Host: postgres (Docker internal)
Port: 5432 (127.0.0.1 only)
DB: nesteasy_db
ORM: Prisma (migrate deploy)
03
How to manage the codebase, make changes, and deploy safely.
11 Codebase Structure
Monorepo Layout
nest-easy/
├── apps/
│ ├── api/ ← NestJS backend
│ │ ├── src/modules/ ← 11 feature modules
│ │ ├── prisma/ ← schema + migrations
│ │ └── Dockerfile
│ └── web/ ← Next.js frontend
│ ├── src/app/ ← routes (App Router)
│ ├── src/components/ ← UI components
│ ├── src/lib/api/ ← typed API clients
│ └── Dockerfile
├── docker/
│ ├── docker-compose.yml ← production stack
│ ├── .env ← compose variables
│ └── nginx/nginx.conf ← reverse proxy config
└── .env ← all secrets/config
API Module Structure (pattern)
# Each module follows this pattern:
src/modules/feature/
├── feature.module.ts ← wires DI
├── feature.controller.ts ← HTTP routes + guards
├── feature.service.ts ← business logic
└── dto/ ← input validation
Frontend File Pattern
# Each feature:
src/lib/api/feature.ts ← typed API client
src/components/dashboard/
FeatureView.tsx ← main component
src/app/(dashboard)/
feature/page.tsx ← route page (thin)
12 Developer Guide — Making a Backend Change
Adding or changing an API endpoint
1
Edit the Service
Add / modify business logic in feature.service.ts. This is where Prisma queries live.
2
Add the Route
Add @Get/@Post/@Patch in feature.controller.ts with correct @Roles() guard.
3
DB Change?
Edit prisma/schema.prisma, run pnpm prisma migrate dev --name description locally.
4
Build API Image
sudo docker compose build api from the docker/ directory.
5
Deploy
sudo docker compose up -d api — zero-downtime, migrations run automatically on startup.
🔐 Auth & Roles
Every controller uses @UseGuards(JwtAuthGuard, RolesGuard) at class level. Add @Roles(UserRole.ADMIN) on specific methods to restrict access. Use @CurrentUser() decorator to get the calling user.
📝 Audit Logging
Inject PrismaService and call this.prisma.auditLog.create() after significant mutations. Include userId, action (e.g. "CREATE_PROPERTY"), entity, entityId.
📧 Email / Queues
Inject EmailService to send transactional emails. For scheduled/background jobs, inject @InjectQueue('notifications') and add to the Bull queue with a delay.
13 Developer Guide — Making a Frontend Change
Adding a new UI page or feature
1
API Client
Add typed functions to src/lib/api/feature.ts using the apiClient axios wrapper. Always type the response.
2
Create Component
Add FeatureView.tsx in src/components/dashboard/. Use useQuery for data, useMutation for writes.
3
Create Route
Add page.tsx inside src/app/(dashboard)/feature/. Keep it thin — just renders the View component.
4
Build Image
sudo docker compose build web — Next.js builds to a standalone output inside the image.
5
Deploy
sudo docker compose up -d web — hot-swaps the web container, nginx continues serving.
🎨 Styling
Tailwind only — no custom CSS files. Use the cn() utility for conditional classes. Brand blue: #2563EB. Gray scale from gray-50 to gray-900.
📡 Data Fetching
Always use useQuery({ queryKey: ['feature', id], queryFn: api.get }). For mutations use useMutation + queryClient.invalidateQueries to refresh on success.
🔒 Role Gating
The Sidebar already fetches /users/me. Use useQuery(['users', 'me']) from the same cache to get the role in any component.
📱 Responsive
Use Tailwind responsive prefixes: sm:, md:, lg:. Dashboard has a fixed sidebar — on mobile consider a collapsible drawer (Phase 2).
14 Developer Guide — Deployment Workflow
Standard Deploy (change to api or web)
# 1. SSH into the VPS
ssh user@vps-ip
# 2. Pull latest code
cd ~/Nest/nest-easy
git pull origin main
# 3. Rebuild only changed service(s)
sudo docker compose -f docker/docker-compose.yml \
build api # or: web, or: api web
# 4. Restart the service
sudo docker compose -f docker/docker-compose.yml \
up -d api
# 5. Verify logs
sudo docker logs nesteasy_api --tail 30
Check all services are healthy
sudo docker compose -f docker/docker-compose.yml ps
# All 6 should show: Up ... (healthy)
Database Migrations
# Migrations run AUTOMATICALLY on API startup
# (CMD in Dockerfile: prisma migrate deploy && node ...)

# To create a new migration (local dev):
cd apps/api
pnpm prisma migrate dev --name add_field

# NEVER run migrate dev on production
# Production ONLY uses: migrate deploy
Important Files — Don't Touch Without Understanding
  • docker/.env — compose variable substitution values
  • .env (root) — all secrets, JWT keys, Stripe keys
  • docker/nginx/nginx.conf — IP allowlist, rate limits
  • apps/api/prisma/schema.prisma — single source of truth for DB
  • apps/api/src/common/guards/ — JWT + RBAC guards, all routes depend on these
Useful Container Commands
docker exec nesteasy_postgres psql -U nesteasy nesteasy_db ← DB shell
docker logs nesteasy_api -f ← live API logs
docker exec nesteasy_api node_modules/.bin/prisma studio ← DB GUI
15 Developer Guide — Environment & Secrets
Environment Variables (root .env)
Variable GroupVariablesWhere Used
DatabasePOSTGRES_PASSWORD, DATABASE_URLAPI container, Prisma
JWTJWT_SECRET, JWT_REFRESH_SECRET, JWT_EXPIRES_INNestJS auth module
StripeSTRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, STRIPE_PUBLISHABLE_KEYAPI (payments module)
MinIOMINIO_ACCESS_KEY, MINIO_SECRET_KEY, MINIO_BUCKET_NAMEAPI (documents module)
EmailSMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASSAPI (notifications module)
FrontendNEXT_PUBLIC_API_URL, NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYBaked into Next.js build
⚠️ NEXT_PUBLIC_ vars
These are baked into the Next.js build — changing them requires a full docker compose build web, not just a restart.
🔑 JWT Secrets
Changing JWT_SECRET invalidates ALL existing access tokens. Only change during a planned maintenance window — all users will need to re-login.
Two .env files
  • nest-easy/.env — loaded by API/web containers via env_file: in compose. Contains ALL secrets.
  • nest-easy/docker/.env — used by docker compose for ${VAR} substitution when building DATABASE_URL etc. Must stay in sync with root .env passwords.
Never commit
  • Either .env file (should be in .gitignore)
  • Any file containing sk_live_ or whsec_ keys
  • Database passwords
  • JWT secrets
✓ Best practice
Keep a password-manager entry for all production secrets. The .env.example file in the repo shows all keys with placeholder values.
04
How to hand this over to Nest Easy in the right way.
17 Recommended Delivery Approach
Three stages to a clean handover
🎯
Stage 1 — Client Demo
Walk through the live platform. Show every module. Record the session. Let the client operate it themselves while screen-sharing. Gather initial feedback.
Outcome: signed-off feature walkthrough
🧪
Stage 2 — UAT Period
Give the client a 2-week User Acceptance Testing window. Set up a few test landlord, tenant, and manager accounts. They put data in, we fix any issues they raise.
Outcome: client confidence, bug fixes logged and resolved
🚀
Stage 3 — Go Live
CNAME the client's domain to the VPS. Point Cloudflare to the correct origin. Update the Nginx server_name. Flip the platform to live branding with real Stripe keys.
Outcome: platform live on nesteasy.co.uk
📋 Go-Live Checklist
Replace Stripe test keys with live keys
Set up real SMTP (SendGrid recommended)
Create admin account for client team
Load initial property & landlord data
Update Nginx server_name for client domain
Verify Cloudflare CNAME is correct
📄 What to Hand Over
Admin login credentials
Video walkthrough recording
User guide (Manager + Tenant)
This team briefing document
Technical architecture doc
Support contact / SLA agreement
🔐 Credentials Transfer
Create ADMIN account for their team leader
Never share .env via email — use 1Password or similar
Change all default passwords before handover
Revoke Agile Tech admin accounts post-handover (or keep as support access)
📞 Support Arrangement
Define a support retainer or break-fix rate
Monthly platform fee covers hosting + maintenance?
Phase 2 features = new project scope
Agree on SLA: response time for critical issues
18 Client Domain & DNS Switch
Current Setup → Production Domain
# Current URL (our subdomain):
https://nest.agiletechsolutions.co.uk

# Target (client's domain):
https://manage.nesteasy.co.uk
# or whatever subdomain they choose
Steps to switch domain
# Step 1: Update Nginx server_name
# In docker/nginx/nginx.conf, change:
server_name nest.agiletechsolutions.co.uk;
# to:
server_name manage.nesteasy.co.uk;

# Step 2: Restart Nginx
sudo docker compose restart nginx

# Step 3: Add CNAME in Cloudflare
# manage.nesteasy.co.uk → [VPS IP]
# Set Proxy status: Proxied (orange cloud)
Live Stripe Keys Switch
# In root .env, replace test keys:
STRIPE_SECRET_KEY=sk_live_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PUBLISHABLE_KEY=pk_live_...

# In docker/.env and root .env update
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_...

# Then rebuild web (pk is baked into build):
sudo docker compose build web && docker compose up -d web

# Set up Stripe webhook in dashboard:
# URL: https://manage.nesteasy.co.uk/api/stripe/webhook
⚠️ SMTP for Production
The current SMTP config is a placeholder. Before go-live, configure a real email provider. We recommend SendGrid (free tier: 100 emails/day, reliable deliverability). Update SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS in .env and restart the API.
05
Phase 2 features — opportunities to extend the platform.
20 Phase 2 — Roadmap
# Feature Description Value to Client Effort
P1 Subscription Billing UI Landlord self-serve subscription management. Starter/Professional/Enterprise tiers. Upgrade/downgrade flows. Stripe Customer Portal embed. Direct revenue generation for Nest Easy Medium
P2 Digital Tenancy Signing DocuSign / HelloSign integration. Tenants sign agreements digitally. Audit trail on signatures. Auto-store in document library. Eliminates paper entirely, faster onboarding Medium
P3 Property Map View Map view of portfolio using PostGIS data already stored. Heat map of compliance status. Geographic grouping. PostGIS schema already ready — UI work only Low
P4 Mobile App React Native app (shares types from monorepo). Tenant app: payments, requests, notifications. Contractor app: job updates, evidence upload. Field access for tenants and contractors High
P5 PDF Compliance Packs One-click export of all compliance documents for a property as a branded PDF bundle. Puppeteer already installed. Required for letting agent compliance audits Low
P6 Two-Factor Auth TOTP (Google Authenticator) for admin/manager accounts. FIDO2 passkey support. SMS OTP fallback. Security upgrade for high-value accounts Medium
P7 CI/CD Pipeline GitHub Actions: lint → test → build → push Docker images → SSH deploy. Replaces manual SSH deployments. Faster, safer deployments with audit trail Low
P8 White-Label Multi-Tenancy Allow Nest Easy to re-sell the platform to other agents. Custom branding per tenant. Isolated data per organisation. Platform becomes a SaaS product High
A complete PropTech platform.
Built fast. Built right. Live today.
Every MVP requirement delivered. Infrastructure secure. Codebase clean and extensible. Ready for Phase 2 whenever the client wants to grow.
11
API Modules
20+
Frontend Pages
6
Live Containers
100%
MVP Delivered
8
Phase 2 Opportunities