YOU ARE: A developer assistant (Copilot) that must scaffold a production-minded, maintainable, modular TypeScript monorepo for the Humanet MVP.
GOAL: Create a monorepo that contains:
- frontend/ -> Next.js (TypeScript, App Router), TailwindCSS, React Query
- backend/ -> Node.js + Express (TypeScript, ES Modules), MongoDB with Mongoose
- shared/ -> Shared TypeScript types/interfaces
- scripts, CI, Docker, linting, tests, and developer tooling
GENERAL RULES (apply everywhere):
- Use TypeScript everywhere. "strict": true.
- Use components
- Use ES Modules (package.json "type": "module") for backend.
- Keep files small: prefer <300 lines. Break functionality into services/controllers/utils.
- Use async/await. No .then chains for primary flows.
- Separate concerns: controllers -> services -> models -> routes. Controllers only handle req/res, services contain business logic, models only define DB schema.
- Validate all external input with Zod (backend).
- Use JWT for auth (access token + refresh token optional). Store JWT as HttpOnly cookie for frontend flows.
- Use a shared
shared/src/typesfor common types (Idea, User, Comment, DTOs). - Add ESLint + Prettier + Husky + lint-staged. Add sample unit tests.
- Create Dockerfiles for frontend & backend and a docker-compose to run backend + frontend + MongoDB locally.
SCOPED MVP FEATURES (minimum working):
- Auth: signup/login/logout using email + password (hashed with bcrypt).
- Idea: create/read/list/search/fork (parentId link), upvote (one upvote per user).
- Idea family tree endpoint: GET /ideas/:id/tree returns nested tree.
- Comments on ideas.
- Basic karma: upvotes increment user's karma; forks give attribution.
- Simple frontend pages: landing, ideas list, idea detail (family tree preview), post idea form, login/signup, profile.
- Place all reusable UI components inside
/frontend/src/components/. - Do not duplicate components. Always reuse or extend existing ones.
- Check
/components/before creating a new component. - Use shadcn/ui and Tailwind as base building blocks.
- Wrap shadcn components into custom components for consistent design.
- Keep components modular and small. Break down large ones into smaller parts.
- Variants should be handled via props, not duplication.
STEP-BY-STEP TASKS (do them sequentially; commit per major step):
-
Create monorepo root & workspaces
- Initialize repo root package.json with pnpm workspaces:
{ "name": "humanet", "private": true, "workspaces": ["frontend", "backend", "shared"], "scripts": { "dev": "concurrently \"pnpm --filter backend dev\" \"pnpm --filter frontend dev\"", "lint": "pnpm -w lint", "test": "pnpm -w test" } } - Add README.md with short project summary and local dev steps.
- Initialize repo root package.json with pnpm workspaces:
-
Shared package
shared/package.jsonwith"type": "module", build script if needed.- Create
shared/src/types/idea.ts,user.ts,comment.tswith TypeScript interfaces:export interface UserDTO { _id?: string; username: string; email: string; bio?: string; karma?: number; skills?: string[]; } export interface IdeaDTO { _id?: string; title: string; description: string; tags?: string[]; domain?: string[]; authorId: string; parentId?: string | null; upvotes?: number; createdAt?: string; } export interface CommentDTO { _id?: string; ideaId: string; authorId: string; text: string; createdAt?: string; }
-
Backend scaffold
backend/package.json(type: module) with scripts:dev-> ts-node-dev tosrc/server.tsbuild-> tscstart-> node dist/server.js
backend/tsconfig.json:{ "compilerOptions": { "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", "outDir": "dist", "rootDir": "src", "strict": true, "esModuleInterop": true, "skipLibCheck": true, "resolveJsonModule": true, "baseUrl": "./", "paths": { "@shared/*": ["../shared/src/*"] } }, "include": ["src"] }- Create
backend/src/config/index.tsto read environment variables using dotenv and zod. - Create
backend/src/app.tsthat configures express middlewares:- helmet, cors (allow frontend origin with credentials), express.json, cookie-parser, morgan (dev).
- Create
backend/src/server.tsto connect to MongoDB and start server (graceful shutdown). - Create
backend/src/models/with Mongoose schemas in TS:user.model.ts(username, email, passwordHash, bio, skills[], karma(Number), createdAt)idea.model.ts(title, description, tags[], domain[], author(ObjectId), parentId(ObjectId|null), upvotes(Number default 0), upvoters [ObjectId], forkCount)comment.model.ts
- Ensure
idea.modelhas atext indexon title + description for search:IdeaSchema.index({ title: 'text', description: 'text', tags: 'text' }); - Create
backend/src/typesas needed for internal types.
-
Backend layers: controllers/services/routes
- For each resource (auth, users, ideas, comments) build:
services/<resource>.service.tswith database logiccontrollers/<resource>.controller.tsthat calls services and returns responsesroutes/<resource>.routes.tsthat registers routes on an Express Router
- Implement DTOs & validators using Zod:
validation/createIdea.schema.tsetc.
- Implement
auth.middleware.tsthat extracts JWT from HttpOnly cookie or Authorization header; verifies JWT and attaches user to req. - Implement
error.middleware.tsfor centralized error handling (custom AppError class).
- For each resource (auth, users, ideas, comments) build:
-
Auth
- Implement
/api/auth/signup(validate, hash password with bcrypt, create user). - Implement
/api/auth/login(verify password, sign JWT, set HttpOnly cookie). - Implement
/api/auth/me(protected, return user profile). - JWT: sign with process.env.JWT_SECRET, expiresIn short (e.g., 15m) for access. Optionally implement refresh token later.
- Implement
-
Ideas API
- Endpoints:
POST /api/ideas-> create idea (validate with Zod, require auth)GET /api/ideas-> list ideas with optionalsearch,domain,tags,page,limitGET /api/ideas/:id-> get idea detail (populate author)GET /api/ideas/:id/tree-> return nested family tree (limit depth, use recursion or aggregation)POST /api/ideas/:id/fork-> create new idea with parentId set to :id; increment parent forkCount; attribute original author (store relation)POST /api/ideas/:id/upvote-> toggle upvote: update upvoters set, increment/decrement upvotes; increment author's karma when upvote occurs
- Use mongoose transactions for multi-step operations (fork increments + create child + attribution).
- Endpoints:
-
Comments API
POST /api/ideas/:id/commentsGET /api/ideas/:id/comments
-
Family tree implementation notes
- Store parentId on idea (single parent). Child ideas are those with parentId === parent._id. For tree endpoint:
- Use a recursive query (server-side) or an aggregation that builds children array.
- Limit recursion depth (configurable).
- For faster lookup, consider materialized path (string of ancestor ids) in future, but for MVP recursion is fine.
- Store parentId on idea (single parent). Child ideas are those with parentId === parent._id. For tree endpoint:
-
Search
- Implement text search using MongoDB text index:
- Query:
{ $text: { $search: keyword } }withscore: { $meta: "textScore" }and sort by score. - For fuzzy / semantic later, design API to accept
useSemantic=trueflag.
- Query:
- Implement text search using MongoDB text index:
-
Karma rules (simple MVP)
- Upvote increases idea.upvotes and author.karma += 1.
- Fork creation gives original author karma +2 and increases forkCount.
- Ensure upvote is idempotent per user: keep
upvoters: ObjectId[].
-
Backend tests
- Setup Jest + ts-jest + Supertest.
- Add integration test for auth, create idea, fork idea, tree endpoint. Mock or use test MongoDB (in-memory mongodb-memory-server).
-
Frontend scaffold (Next.js, App Router)
frontend/package.jsonscripts:dev,build,start,lint,test.- Use
pnpminstall; usenext@latest,react,react-dom,tailwindcss,@tanstack/react-query,axios. - Setup Tailwind per Next.js docs (globals in app/globals.css).
- Create
frontend/src/app/layout.tsxwith React Query provider and global layout (header with nav). - Create simple pages:
app/page.tsx-> Landing with CTA and latest ideas list (fetch via React Query).app/ideas/page.tsx-> Ideas list with search input, filters, pagination.app/ideas/[id]/page.tsx-> Idea detail page: shows idea content, family-tree preview, comments, fork button, upvote button.app/auth/login/page.tsx&app/auth/signup/page.tsxapp/profile/[username]/page.tsx
- Implement
frontend/src/lib/api.tsaxios client:- baseURL = process.env.NEXT_PUBLIC_API_URL
- withCredentials = true
- Implement React Query hooks in
frontend/src/hooks/:useIdeas,useIdea,useCreateIdea,useForkIdea,useUpvoteIdea,useComments
- Implement small UI components:
IdeaCard.tsx,IdeaForm.tsx,CommentList.tsx,FamilyTreePreview.tsx(simple tree rendering using recursion)
-
Frontend auth flow
- After login, backend returns HttpOnly cookie and user payload (or /auth/me fetch).
- For protected UI actions, check
auth/meand show login if not authenticated. - Keep JWT handling server-side (HttpOnly cookie) to avoid XSS risks.
-
Shared types usage
- Import DTO types from
sharedin both frontend and backend to keep contract stable. - Example import path via tsconfig paths alias
@shared/*.
- Import DTO types from
-
Linting, formatting, commit hooks
- Root config files:
.eslintrc.cjsconfigured for workspace: set base rules for both frontend and backend and plugin:@typescript-eslint..prettierrcstandard rules.
- Install Husky and lint-staged: pre-commit run
pnpm -w lint-stagedwhich will run formatting + tests on changed files.
- Root config files:
-
CI
- Add
.github/workflows/ci.ymlto:- Install pnpm, run
pnpm -w install. - Run
pnpm -w lint,pnpm -w test,pnpm -w build(build frontend & backend). - Cache pnpm store.
- Install pnpm, run
- Add
-
Docker
- Add
backend/Dockerfile(node:18-alpine -> build -> dist -> node run). - Add
frontend/Dockerfile(node build -> serve). - Add
docker-compose.ymlfor local environment with services:- mongo: official mongo image with volume
- backend: build from backend Dockerfile, depends_on: mongo
- frontend: build from frontend Dockerfile, depends_on: backend
- Add
-
Documentation
- Add
docs/ARCHITECTURE.mdexplaining layers and decisions. - Add
docs/DEV_SETUP.mdwith step-by-step local dev instructions (env variables list). - Add API contract summary at
docs/API.md(routes and payloads).
- Add
-
Quality gates & best practices
- Ensure every new route has:
- Zod schema for inputs
- Unit tests for service logic
- Integration test for route in backend tests
- Keep functions < 50 lines where possible; files < 300 lines.
- Use index barrel files only when appropriate; avoid deep barrel import confusion.
- Ensure every new route has:
-
Post-scaffold tasks (future)
- Add GitHub OAuth login (optional).
- Implement semantic search (embeddings + pgvector or dedicated vector DB).
- Implement merge proposals for duplicates & attribution history.
- Add analytics and admin moderation tools.
FILES & EXAMPLES (create these exact files as part of scaffolding — make them runnable):
backend/src/server.ts:
import 'dotenv/config';
import mongoose from 'mongoose';
import { createApp } from './app.js';
const app = createApp();
const MONGO = process.env.MONGO_URL!;
mongoose.set('strictQuery', true);
await mongoose.connect(MONGO);
const PORT = Number(process.env.PORT ?? 4000);
app.listen(PORT, () => console.log(`Backend listening on ${PORT}`));- backend/src/app.ts:
import express from 'express';
import helmet from 'helmet';
import cors from 'cors';
import morgan from 'morgan';
import cookieParser from 'cookie-parser';
import routes from './routes/index.js';
import { errorHandler } from './middlewares/error.middleware.js';
export function createApp() {
const app = express();
app.set('trust proxy', true);
app.use(helmet());
app.use(cors({ origin: process.env.FRONTEND_URL, credentials: true }));
app.use(morgan('dev'));
app.use(express.json());
app.use(cookieParser());
app.use('/api', routes);
app.use(errorHandler);
return app;
}- backend/src/models/idea.model.ts:
import { Schema, model } from 'mongoose';
const IdeaSchema = new Schema({
title: { type: String, required: true },
description: { type: String, required: true },
tags: { type: [String], default: [] },
domain: { type: [String], default: [] },
author: { type: Schema.Types.ObjectId, ref: 'User', required: true },
parentId: { type: Schema.Types.ObjectId, ref: 'Idea', default: null },
upvotes: { type: Number, default: 0 },
upvoters: { type: [Schema.Types.ObjectId], default: [] },
forkCount: { type: Number, default: 0 }
}, { timestamps: true });
IdeaSchema.index({ title: 'text', description: 'text', tags: 'text' });
export const IdeaModel = model('Idea', IdeaSchema);- frontend/src/lib/api.ts:
import axios from 'axios';
const api = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000/api',
withCredentials: true
});
export default api;- frontend/src/app/layout.tsx (Next.js app router skeleton):
import './globals.css';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
const queryClient = new QueryClient();
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<QueryClientProvider client={queryClient}>
<header>{/* nav */}</header>
<main>{children}</main>
</QueryClientProvider>
</body>
</html>
);
}IMPORTANT: After scaffolding, run pnpm -w install and pnpm dev from root. Ensure env files:
backend/.env: MONGO_URL, JWT_SECRET, FRONTEND_URL, PORT
frontend/.env.local: NEXT_PUBLIC_API_URL
FINAL NOTES FOR YOU (the developer):
Ask the assistant (Copilot) to create a series of commits (one per major step) instead of one giant change. This makes reviews easy.
Verify the backend server boots and POST /api/auth/signup and POST /api/ideas work end-to-end before building UI pages.
Keep the shared types contract stable. Use these types on both ends.
Prioritize the core flows (auth → create idea → fork idea → tree endpoint) before styling.
Now: scaffold the repo exactly following steps 1–20. Create files and configs shown above. For any file you create, ensure it is TypeScript, strictly typed, and small; create unit tests for each service. Ask for follow-up to implement semantic search or enterprise features.