Documentation Index
Fetch the complete documentation index at: https://docs.pyqdeck.in/llms.txt
Use this file to discover all available pages before exploring further.
Overview
PyqDeck is a pnpm monorepo containing two independent packages: backend and frontend. Each package has its own package.json, dependencies, and scripts, but they share a common root for tooling and CI.
pyqdeck/
├── backend/ # Express.js API server
├── frontend/ # Next.js 15 application
├── docs/ # Mintlify documentation
├── .github/workflows/ # CI/CD pipelines
├── render.yaml # Render deployment config
├── pnpm-workspace.yaml # Monorepo configuration
└── package.json # Root package.json
Design Principles
- Independent deployability - Each package can be built and deployed independently
- Clear boundaries - The only coupling is the API contract (
openapi.json)
- Shared tooling - Root-level scripts for linting, formatting, and CI
Backend Package
Tech Stack: Express 5, MongoDB (Mongoose 9), ES Modules
Architecture (Layered)
backend/src/
├── app.js # Express app setup, route mounting
├── index.js # Entry: Sentry, DB connect, graceful shutdown
├── config/ # Configuration (DB, mail, env)
├── controllers/ # Request handlers (13 controllers)
├── services/ # Business logic (13 services)
├── repositories/ # Data access layer (14 repositories)
├── models/ # Mongoose schemas (13+ models)
├── middlewares/ # Auth, error handling, validation
├── routes/ # Route definitions (13 route files)
├── utils/ # Shared utilities
└── docs/swagger.js # OpenAPI spec generation
Key Dependencies
| Category | Packages |
|---|
| Auth | @clerk/express |
| Validation | zod, express-validator |
| Error Tracking | @sentry/node, @sentry/profiling-node |
| Logging | @logtail/winston, winston |
| Email | resend |
| File Storage | @uploadthing/node |
| Security | helmet, cors, express-rate-limit |
Frontend Package
Tech Stack: Next.js 15, React 19, Tailwind CSS 4, shadcn/ui
Directory Structure
frontend/src/
├── app/ # Next.js App Router
├── components/
│ ├── ui/ # UI component library (55+ components)
│ └── ... # Feature components
├── hooks/ # React hooks (useApi, etc.)
├── lib/ # Utilities, API SDK (api-generated.ts)
└── styles/ # Global styles
Key Dependencies
| Category | Packages |
|---|
| Auth | @clerk/nextjs |
| UI | Radix UI, shadcn/ui components |
| Styling | Tailwind CSS 4 |
| API Client | Axios (via generated SDK) |
| Storybook | @storybook/nextjs-vite |
API Contract: The Only Coupling
The only dependency between frontend and backend is the OpenAPI spec:
backend/openapi.json → frontend/src/lib/api-generated.ts
This is enforced in CI:
- Backend tests run
- CI verifies
openapi.json hasn’t drifted
- Frontend build runs
gen:api to regenerate the SDK
- If any step fails, the PR is blocked
This means:
- Frontend never writes manual
fetch calls - everything goes through the generated SDK
- Backend changes are always type-safe - the SDK regenerates on every build
- No shared code - the packages communicate only via HTTP
CI/CD Pipeline
The monorepo has 8 GitHub Actions workflows:
| Workflow | Trigger | Purpose |
|---|
monorepo-ci.yml | Push/PR to main | Full 5-stage CI/CD pipeline |
lighthouse.yml | PR (frontend/) | Lighthouse performance audit |
bundle-analysis.yml | PR (frontend/) | Bundle size analysis |
storybook.yml | Push to main (frontend/) | Deploy Storybook to GitHub Pages |
load-test.yml | Push/PR (backend/) | k6 load testing |
codeql-analysis.yml | Push/PR/schedule | Security analysis |
release-drafter.yml | Push/PR | Auto-draft release notes |
pr-size-labeler.yml | PR | Label PRs by size |
5-Stage Pipeline (monorepo-ci.yml)
1. Security → pnpm audit --prod (both packages)
2. Quality → eslint + prettier checks
3. Backend → vitest + contract check
4. Frontend → gen:api + next build
5. Deploy → Docker build + Render deploy
Deployment
| Package | Platform | Method |
|---|
| Backend | Render | Docker (multi-stage build) |
| Frontend | Vercel | Vercel GitHub integration |
| Storybook | GitHub Pages | GitHub Actions |
| Docs | Mintlify | GitHub Actions |
Adding a New Package
If you need to add a new package (e.g., shared/ for common utilities):
- Create the directory with its own
package.json
- Add it to
pnpm-workspace.yaml
- Reference it in other packages via workspace protocol:
"@pyqdeck/shared": "workspace:*"
However, our current philosophy is to keep packages independent and communicate only via the API contract. Only add shared packages if there’s a compelling reason.
Next Steps