diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 725e69a..3c5b5fb 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -1,25 +1,39 @@ -# foundary-1770670477 +# Foundary -Project deployed to gbgf39u8.threesix.ai via threesix.ai platform. +A product studio for conversational product development. Deployed to gbgf39u8.threesix.ai via threesix.ai platform. + +## Monorepo layout + +This is a **pnpm workspace monorepo**. Key locations: + +- `apps/web/` — Frontend web application (`@foundary/web`) +- `apps/api/` — Backend API server (`@foundary/api`) +- `packages/shared/` — Shared types, utilities, constants (`@foundary/shared`) +- `packages/config/` — Shared tsconfig and lint config (`@foundary/config`) + +Internal dependencies use `workspace:*` protocol. ## Quick Start ```bash -# Clone -git clone https://git.threesix.ai/jordan/foundary-1770670477.git -cd foundary-1770670477 +# Install +pnpm install -# Build -docker build -t foundary-1770670477 . +# Dev +pnpm dev -# Run -docker run -p 8080:8080 foundary-1770670477 +# Build all +pnpm build + +# Docker +docker build -t foundary . +docker run -p 8080:80 foundary ``` ## Deployment Pushes to `main` trigger automatic deployment via Woodpecker CI: -1. Build Docker image +1. Build Docker image (multi-stage) 2. Push to registry (registry.threesix.ai) 3. Update Kubernetes deployment @@ -30,3 +44,4 @@ Live at: https://gbgf39u8.threesix.ai - Keep the Dockerfile optimized for build time - Use multi-stage builds when possible - All config via environment variables +- Use pnpm for package management — no npm or yarn diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..cf04042 --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +shamefully-hoist=true +strict-peer-dependencies=false diff --git a/Dockerfile b/Dockerfile index e7846dc..46daa24 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,21 @@ -# Default Dockerfile - replace with your application +# Stage 1 — Install dependencies +FROM node:20-alpine AS deps +RUN corepack enable && corepack prepare pnpm@9.15.4 --activate +WORKDIR /app +COPY package.json pnpm-workspace.yaml pnpm-lock.yaml* .npmrc ./ +COPY apps/web/package.json ./apps/web/ +COPY apps/api/package.json ./apps/api/ +COPY packages/shared/package.json ./packages/shared/ +COPY packages/config/package.json ./packages/config/ +RUN pnpm install --frozen-lockfile || pnpm install + +# Stage 2 — Build +FROM deps AS build +COPY . . +RUN pnpm build + +# Stage 3 — Production image FROM nginx:alpine - -# Copy static files or your app -COPY . /usr/share/nginx/html/ - +COPY --from=build /app/apps/web/dist /usr/share/nginx/html/ EXPOSE 80 - CMD ["nginx", "-g", "daemon off;"] diff --git a/README.md b/README.md index 947cf63..a1cec9f 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,59 @@ -# foundary-1770670477 +# Foundary -Deployed at: https://gbgf39u8.threesix.ai +**A product studio for conversational product development.** -## Getting Started +Foundary lets teams shape, build, and ship products through structured conversations. Instead of disconnected specs, tickets, and hand-offs, Foundary keeps the entire product development lifecycle inside a single conversational thread — from initial idea through launched product. -1. Clone the repository -2. Build with Docker: `docker build -t foundary-1770670477 .` -3. Run locally: `docker run -p 8080:8080 foundary-1770670477` +## How it works -## CI/CD +1. **Converse** — Describe what you want to build in plain language. Foundary captures intent, constraints, and decisions as structured product artifacts. +2. **Refine** — Iterate on scope, priorities, and design through ongoing dialogue. Every conversation turn updates the living product definition. +3. **Ship** — Foundary translates the conversation into deployable outputs and tracks progress against the goals you defined together. -This project uses Woodpecker CI for continuous deployment. Pushing to `main` will: -- Build a Docker image -- Push to the container registry -- Deploy to Kubernetes +## Monorepo structure -## Resources +``` +foundary/ +├── apps/ +│ ├── web/ # Web application (frontend) +│ └── api/ # API server (backend) +├── packages/ +│ ├── shared/ # Shared types, utilities, and constants +│ └── config/ # Shared configuration (TypeScript, ESLint) +├── package.json # Workspace root +├── pnpm-workspace.yaml +└── Dockerfile +``` -- Live site: https://gbgf39u8.threesix.ai -- Git repository: https://git.threesix.ai/jordan/foundary-1770670477.git +## Getting started + +```bash +# Install dependencies +pnpm install + +# Run the web app in development +pnpm dev + +# Build all packages and apps +pnpm build + +# Run tests across the monorepo +pnpm test + +# Type-check everything +pnpm typecheck +``` + +## Deployment + +Pushes to `main` trigger automatic deployment via Woodpecker CI: + +1. Build Docker image (multi-stage, optimized for cache) +2. Push to container registry (`registry.threesix.ai`) +3. Update Kubernetes deployment + +Live at: https://gbgf39u8.threesix.ai + +## Contributing + +This is a pnpm workspace monorepo. All packages use `workspace:*` protocol for internal dependencies. Run commands from the root — pnpm will route them to the correct workspace packages. diff --git a/apps/api/package.json b/apps/api/package.json new file mode 100644 index 0000000..72d0f30 --- /dev/null +++ b/apps/api/package.json @@ -0,0 +1,16 @@ +{ + "name": "@foundary/api", + "version": "0.0.1", + "private": true, + "description": "Foundary API server", + "scripts": { + "dev": "echo 'api dev server not configured yet'", + "build": "echo 'api build not configured yet'", + "typecheck": "tsc --noEmit", + "lint": "echo 'no linter configured yet'", + "test": "echo 'no tests configured yet'" + }, + "dependencies": { + "@foundary/shared": "workspace:*" + } +} diff --git a/apps/api/src/index.ts b/apps/api/src/index.ts new file mode 100644 index 0000000..203e89f --- /dev/null +++ b/apps/api/src/index.ts @@ -0,0 +1,2 @@ +export { }; +console.log("@foundary/api"); diff --git a/apps/api/tsconfig.json b/apps/api/tsconfig.json new file mode 100644 index 0000000..5f23179 --- /dev/null +++ b/apps/api/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../packages/config/tsconfig.base.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src"] +} diff --git a/apps/web/package.json b/apps/web/package.json new file mode 100644 index 0000000..3b37aa1 --- /dev/null +++ b/apps/web/package.json @@ -0,0 +1,16 @@ +{ + "name": "@foundary/web", + "version": "0.0.1", + "private": true, + "description": "Foundary web application", + "scripts": { + "dev": "echo 'web dev server not configured yet'", + "build": "echo 'web build not configured yet'", + "typecheck": "tsc --noEmit", + "lint": "echo 'no linter configured yet'", + "test": "echo 'no tests configured yet'" + }, + "dependencies": { + "@foundary/shared": "workspace:*" + } +} diff --git a/apps/web/src/index.ts b/apps/web/src/index.ts new file mode 100644 index 0000000..76c043f --- /dev/null +++ b/apps/web/src/index.ts @@ -0,0 +1,2 @@ +export { }; +console.log("@foundary/web"); diff --git a/apps/web/tsconfig.json b/apps/web/tsconfig.json new file mode 100644 index 0000000..8634b23 --- /dev/null +++ b/apps/web/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../packages/config/tsconfig.base.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src", + "jsx": "react-jsx" + }, + "include": ["src"] +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..a75d92b --- /dev/null +++ b/package.json @@ -0,0 +1,18 @@ +{ + "name": "foundary", + "private": true, + "version": "0.0.1", + "description": "Foundary — a product studio for conversational product development", + "scripts": { + "dev": "pnpm --filter @foundary/web dev", + "build": "pnpm -r build", + "lint": "pnpm -r lint", + "test": "pnpm -r test", + "typecheck": "pnpm -r typecheck" + }, + "engines": { + "node": ">=20", + "pnpm": ">=9" + }, + "packageManager": "pnpm@9.15.4" +} diff --git a/packages/config/package.json b/packages/config/package.json new file mode 100644 index 0000000..2078f1e --- /dev/null +++ b/packages/config/package.json @@ -0,0 +1,11 @@ +{ + "name": "@foundary/config", + "version": "0.0.1", + "private": true, + "description": "Shared configuration (TypeScript, ESLint, etc.)", + "main": "./tsconfig.base.json", + "scripts": { + "lint": "echo 'no linter configured yet'", + "test": "echo 'no tests configured yet'" + } +} diff --git a/packages/config/tsconfig.base.json b/packages/config/tsconfig.base.json new file mode 100644 index 0000000..3f45e79 --- /dev/null +++ b/packages/config/tsconfig.base.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "declaration": true, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "isolatedModules": true + } +} diff --git a/packages/shared/package.json b/packages/shared/package.json new file mode 100644 index 0000000..7067989 --- /dev/null +++ b/packages/shared/package.json @@ -0,0 +1,14 @@ +{ + "name": "@foundary/shared", + "version": "0.0.1", + "private": true, + "description": "Shared types, utilities, and constants", + "main": "./src/index.ts", + "types": "./src/index.ts", + "scripts": { + "build": "tsc --build", + "typecheck": "tsc --noEmit", + "lint": "echo 'no linter configured yet'", + "test": "echo 'no tests configured yet'" + } +} diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts new file mode 100644 index 0000000..a138108 --- /dev/null +++ b/packages/shared/src/index.ts @@ -0,0 +1,15 @@ +export type ConversationMessage = { + id: string; + role: "user" | "assistant" | "system"; + content: string; + timestamp: number; +}; + +export type Product = { + id: string; + name: string; + description: string; + status: "draft" | "in-progress" | "launched"; + createdAt: number; + updatedAt: number; +}; diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json new file mode 100644 index 0000000..82c6c13 --- /dev/null +++ b/packages/shared/tsconfig.json @@ -0,0 +1,16 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true + }, + "include": ["src"] +} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..3ff5faa --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,3 @@ +packages: + - "apps/*" + - "packages/*"