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.
256 lines
9.8 KiB
Markdown
256 lines
9.8 KiB
Markdown
# МојМајстор - 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. |