mojmajstor/implementation.md
echo 5102ed23c1 feat: Phase 1 - project setup, auth, and base UI
Set up Expo SDK 56 project with TypeScript and Expo Router (file-based).

Backend:
- Full Convex schema (users, accounts, sessions, ads, categories,
  reviews, chats, messages, posts) deployed to self-hosted instance
- Custom email/password auth with SHA-256 hashing via Convex actions
- Query/mutation scaffolds for all domain tables
- Convex environment variables configured on backend

App structure:
- Root layout with ConvexProvider, ThemeProvider, AuthContext
- (auth) group: login and register screens (Macedonian UI)
  with role selection (handyman/customer)
- (tabs) group: 5 tabs (Home, Explore, Posts, Chat, Profile)
  each with nested Stack layouts
- Placeholder detail screens for ad, post, chat, review flows
- 404 not-found screen in Macedonian

UI primitives (components/ui/):
- Button (4 variants), Input, Card, Loading, Avatar, Rating, Badge
- ThemeProvider with light/dark palette via React context

All user-facing strings in Macedonian. Code identifiers in English.
TypeScript passes with zero errors.
2026-05-29 18:18:58 +02:00

9.8 KiB

МојМајстор - Implementation Plan

Overview

МојМајстор (My Handyman) is a mobile app connecting local handymen with customers in Macedonia. Built with Expo React Native and a self-deployed Convex backend, all UI text in Macedonian.


Tech Stack

Layer Technology
Frontend Expo SDK 52+, React Native, TypeScript
Navigation Expo Router (file-based)
Backend Convex (self-hosted)
Auth Convex Auth (email/password + phone)
Styling NativeWind (Tailwind for RN)
Chat Convex real-time queries
Maps react-native-maps
Image Upload Convex file storage + expo-image-picker
Deployment EAS Build + Update

Data Model (Convex Schema)

users

  • _id, name, phone, email, role ("handyman" | "customer"), avatarId?, createdAt

ads

  • _id, handymanId (ref users), title, description, category, location, lat?, lng?, priceRange?, imageIds[], availability, ratingAvg?, reviewCount, createdAt, updatedAt

categories

  • _id, name (Macedonian), slug, icon?, sortOrder

reviews

  • _id, adId (ref ads), customerId (ref users), handymanId (ref users), rating (1-5), comment, createdAt

chats

  • _id, participantIds[] (ref users), lastMessageAt, createdBy

messages

  • _id, chatId (ref chats), senderId (ref users), content, imageId?, createdAt

posts (customer needs)

  • _id, customerId (ref users), title, description, category, location, budget?, status ("open" | "closed"), createdAt, updatedAt

Project Structure

mojmajstor/
├── app/                          # Expo Router pages
│   ├── _layout.tsx               # Root layout + auth state
│   ├── (auth)/
│   │   ├── _layout.tsx
│   │   ├── login.tsx
│   │   └── register.tsx
│   ├── (tabs)/
│   │   ├── _layout.tsx           # Bottom tab navigator
│   │   ├── index.tsx             # Home / search
│   │   ├── explore.tsx           # Browse categories & ads
│   │   ├── posts.tsx             # Customer needs feed
│   │   ├── chat.tsx             # Chat list
│   │   └── profile.tsx          # User profile
│   ├── ad/
│   │   ├── [id].tsx              # Ad detail
│   │   └── create.tsx            # Create ad (handyman)
│   ├── post/
│   │   ├── [id].tsx              # Post detail
│   │   └── create.tsx            # Create post (customer)
│   ├── chat/
│   │   └── [id].tsx              # Chat conversation
│   └── review/
│       └── create.tsx            # Leave a review
├── components/
│   ├── ui/                       # Reusable UI primitives
│   │   ├── Button.tsx
│   │   ├── Card.tsx
│   │   ├── Input.tsx
│   │   ├── Rating.tsx
│   │   ├── Avatar.tsx
│   │   ├── Badge.tsx
│   │   └── Loading.tsx
│   ├── AdCard.tsx
│   ├── PostCard.tsx
│   ├── ChatListItem.tsx
│   ├── MessageBubble.tsx
│   ├── CategoryGrid.tsx
│   ├── SearchBar.tsx
│   ├── LocationPicker.tsx
│   └── ReviewCard.tsx
├── convex/                       # Backend
│   ├── _generated/
│   ├── schema.ts
│   ├── auth.config.ts
│   ├── users.ts
│   ├── ads.ts
│   ├── categories.ts
│   ├── reviews.ts
│   ├── chats.ts
│   ├── messages.ts
│   └── posts.ts
├── lib/
│   ├── constants.ts              # Colors, spacing, Macedonian strings
│   ├── hooks.ts                  # Custom hooks
│   └── utils.ts
├── assets/
│   └── images/
├── app.json
├── package.json
├── tailwind.config.js
├── tsconfig.json
└── eas.json

Implementation Phases

Phase 1: Project Setup & Auth (Week 1)

Goal: Bootable app with authentication.

  1. Initialize Expo project with TypeScript template
  2. Install dependencies: expo-router, nativewind, convex, @convex-dev/auth, expo-image-picker, react-native-maps, expo-location
  3. Configure NativeWind (Tailwind) + constants (colors, Macedonian strings)
  4. Set up Convex project & self-deploy
  5. Define schema.ts with all tables
  6. Configure Convex Auth (email/password + phone)
  7. Build root _layout.tsx with auth state observer
  8. Build (auth)/login.tsx - email/phone login
  9. Build (auth)/register.tsx - role selection (handyman/customer) + profile creation
  10. Build UI primitives: Button, Input, Card, Loading

Deliverable: User can sign up, log in, see role-specific tab layout.


Phase 2: Home & Categories (Week 2)

Goal: Browse and discover handymen.

  1. Seed categories table (Мајстор за сѐ, Водоинсталатер, Електричар, Тескар, Фарбар, Керамичар, Зидар, Градежник, столар, Молер, Електричар, Клима монтажер, etc.)
  2. Build (tabs)/_layout.tsx - bottom nav (Почетна, Пребарување, Огласи, Чат, Профил)
  3. Build (tabs)/index.tsx - home screen with hero search + category grid + featured ads
  4. Build CategoryGrid component with icons per category
  5. Build SearchBar component with text + location filter
  6. Build (tabs)/explore.tsx - category list → filtered ad list
  7. Build AdCard component (image, title, rating, location, price range)
  8. Create ads.ts Convex queries: list, getByCategory, search, getByHandyman
  9. Wire up real data to ad listings

Deliverable: Customer can browse categories and see handyman ads.


Phase 3: Ad Creation & Detail (Week 3)

Goal: Handymen can post and manage ads.

  1. Build ad/create.tsx - multi-step form:
    • Step 1: Category selection
    • Step 2: Title, description, price range
    • Step 3: Location (map picker or text)
    • Step 4: Availability schedule
    • Step 5: Photo upload (up to 5)
  2. Build ad/[id].tsx - ad detail page:
    • Gallery, description, location map, availability, rating, reviews
    • "Започни разговор" (Start chat) button
    • "Напиши оценка" (Write review) button
  3. Create ads.ts mutations: create, update, delete
  4. Handle image upload via Convex file storage + expo-image-picker
  5. Build profile.tsx - handyman view with their ads list, edit/delete

Deliverable: Handymen can create, view, edit, delete their ads. Customers can view full details.


Phase 4: Customer Posts (Week 4)

Goal: Customers can post their needs; handymen can respond.

  1. Build post/create.tsx - customer need form (title, description, category, location, budget, urgency)
  2. Build post/[id].tsx - post detail with responses
  3. Build (tabs)/posts.tsx - feed of open customer posts
  4. Create posts.ts Convex queries & mutations: create, list, getByCustomer, close
  5. Add "Одговори на оглас" (Respond to post) flow for handymen → starts a chat

Deliverable: Customers post needs, handymen browse and respond.


Phase 5: In-App Chat (Week 5)

Goal: Real-time messaging between customer and handyman.

  1. Build (tabs)/chat.tsx - chat list with last message preview, unread indicator
  2. Build chat/[id].tsx - full conversation screen with:
    • Message bubbles (text + optional image)
    • Input bar with send button + image picker
    • Real-time updates via Convex onUpdate
  3. Create chats.ts Convex queries & mutations: create, listByUser
  4. Create messages.ts Convex queries & mutations: send, listByChat (paginated)
  5. Add push notification support via Expo Notifications
  6. Add "Започни разговор" button on ad detail → creates or opens existing chat

Deliverable: Users can chat in real-time with image support.


Phase 6: Reviews & Ratings (Week 6)

Goal: Customer can rate and review handymen.

  1. Build review/create.tsx - star rating + comment form
  2. Build ReviewCard component
  3. Add review summary to AdCard and ad detail page
  4. Create reviews.ts Convex queries & mutations: create, getByAd, getByHandyman
  5. Update ads table: compute ratingAvg and reviewCount on review creation (Convex trigger)
  6. Sort ads by rating in search/explore

Deliverable: Customers leave reviews; ratings visible on ads.


Phase 7: Polish & Production (Week 7)

Goal: Production-ready app.

  1. Full Macedonian localization (all strings in lib/constants.ts)
  2. Error handling & loading states on every screen
  3. Pull-to-refresh on list screens
  4. Pagination on ad feeds and chat messages
  5. Offline-first considerations (Convex optimistic updates)
  6. Deep linking configuration
  7. App icon & splash screen (Macedonian-themed)
  8. EAS Build configuration for iOS + Android
  9. App store metadata (Македонски)
  10. Performance audit (list virtualization, image optimization)
  11. Accessibility pass (labels, contrast, font scaling)

Deliverable: Published app on App Store & Google Play.


Key Decisions & Notes

  • Language: All user-facing text is in Macedonian (Македонски). Code variables and comments in English.
  • Role system: Determined at registration. Handymen see ad creation; customers see post creation. Both can chat.
  • Maps: Use react-native-maps with OpenStreetMap tiles (no Google API key needed for MVP).
  • Convex self-deploy: Deploy via Docker on own infra for full data sovereignty.
  • Auth strategy: Start with email/password, add phone OTP via Twilio in Phase 7.
  • Image optimization: Compress before upload using expo-image-manipulator. Max 5 images per ad.
  • Search: Convex full-text search on ad title/description. Location filter via lat/lng bounding box.