| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
NestJS drop-in replacement for tc-project-service, serving the Topcoder platform at /v6/projects.
Projects API v6 manages the full project lifecycle: project CRUD, member management, invites, phases, phase products, attachments, workstreams, copilot request/opportunity/application workflows, and metadata.
It is the platform replacement for tc-project-service (/v5) and is consumed by multiple frontend apps and backend services.
Key design decisions:
sequenceDiagram
participant Client
participant TokenRolesGuard
participant ProjectContextInterceptor
participant PermissionGuard
participant Controller
participant Service
participant Prisma
participant EventBus
Client->>TokenRolesGuard: HTTP request + Bearer JWT / M2M token
TokenRolesGuard->>TokenRolesGuard: Validate JWT, set request.user
TokenRolesGuard->>ProjectContextInterceptor: pass
ProjectContextInterceptor->>Prisma: Load project members (if :projectId route)
ProjectContextInterceptor->>Controller: request.projectContext populated
Controller->>PermissionGuard: @RequirePermission check
PermissionGuard->>Controller: authorized
Controller->>Service: business logic
Service->>Prisma: DB query
Service->>EventBus: publish Kafka event (on mutations)
Service-->>Controller: result
Controller-->>Client: HTTP response
| NestJS Module | Responsibility |
|---|---|
| GlobalProvidersModule | Prisma, JWT, M2M, Logger, EventBus, shared services |
| ApiModule | Aggregates all feature modules |
| ProjectModule | Project CRUD, listing, billing account lookup |
| ProjectMemberModule | Member add/update/remove |
| ProjectInviteModule | Invite create/update/delete, email notifications |
| ProjectPhaseModule | Phase CRUD |
| PhaseProductModule | Phase product CRUD |
| ProjectAttachmentModule | File/link attachment CRUD, S3 presigned URLs |
| ProjectSettingModule | Project settings |
| WorkstreamModule | Workstream + work + workitem CRUD |
| CopilotModule | Copilot request/opportunity/application workflows |
| MetadataModule | Project types, templates, forms, plan configs, org configs, milestone templates, work-management permissions |
| HealthCheckModule | GET /v6/projects/health |
For the full v5 -> v6 mapping table, see docs/api-usage-analysis.md.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v6/projects | JWT / M2M | List projects with filters (keyword, status, memberOnly, billingAccountId, sort, page, perPage) |
| POST | /v6/projects | JWT / M2M | Create project |
| GET | /v6/projects/:projectId | JWT / M2M | Get project by ID (includes members, invites) |
| PATCH | /v6/projects/:projectId | JWT / M2M | Update project |
| DELETE | /v6/projects/:projectId | Admin only | Soft-delete project |
| GET | /v6/projects/:projectId/billingAccount | JWT / M2M | Default billing account (Billing Accounts API with Salesforce fallback) |
| GET | /v6/projects/:projectId/billingAccounts | JWT / M2M | All billing accounts for project |
| GET | /v6/projects/:projectId/permissions | JWT / M2M | Regular human JWT: caller work-management policy map. M2M, admins, project managers, talent managers, and project copilots on the project: per-member permission matrix with project permissions and template policies |
Talent Manager note:
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v6/projects/:projectId/members | JWT / M2M | List members |
| GET | /v6/projects/:projectId/members/:id | JWT / M2M | Get member |
| POST | /v6/projects/:projectId/members | JWT / M2M | Add member |
| PATCH | /v6/projects/:projectId/members/:id | JWT / M2M | Update member role |
| DELETE | /v6/projects/:projectId/members/:id | JWT / M2M | Remove member |
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v6/projects/:projectId/invites | JWT / M2M | List invites |
| GET | /v6/projects/:projectId/invites/:inviteId | JWT / M2M | Get invite |
| POST | /v6/projects/:projectId/invites | JWT / M2M | Create invite(s) - returns 201 when any invite is created and includes { success[], failed[] } for rejected targets |
| PATCH | /v6/projects/:projectId/invites/:inviteId | JWT / M2M | Accept / decline invite |
| DELETE | /v6/projects/:projectId/invites/:inviteId | JWT / M2M | Delete invite |
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v6/projects/:projectId/phases | JWT / M2M | List phases |
| GET | /v6/projects/:projectId/phases/:phaseId | JWT / M2M | Get phase |
| POST | /v6/projects/:projectId/phases | JWT / M2M | Create phase |
| PATCH | /v6/projects/:projectId/phases/:phaseId | JWT / M2M | Update phase |
| DELETE | /v6/projects/:projectId/phases/:phaseId | JWT / M2M | Soft-delete phase |
| GET | /v6/projects/:projectId/phases/:phaseId/products | JWT / M2M | List phase products |
| GET | /v6/projects/:projectId/phases/:phaseId/products/:productId | JWT / M2M | Get phase product |
| POST | /v6/projects/:projectId/phases/:phaseId/products | JWT / M2M | Create phase product (challenge linkage via details.challengeGuid) |
| PATCH | /v6/projects/:projectId/phases/:phaseId/products/:productId | JWT / M2M | Update phase product |
| DELETE | /v6/projects/:projectId/phases/:phaseId/products/:productId | JWT / M2M | Soft-delete phase product |
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v6/projects/:projectId/attachments | JWT / M2M | List attachments |
| GET | /v6/projects/:projectId/attachments/:id | JWT / M2M | Get attachment (file -> presigned S3 URL) |
| POST | /v6/projects/:projectId/attachments | JWT / M2M | Upload file or add link attachment |
| PATCH | /v6/projects/:projectId/attachments/:id | JWT / M2M | Update attachment metadata |
| DELETE | /v6/projects/:projectId/attachments/:id | JWT / M2M | Soft-delete + async S3 removal |
| Method | Path | Auth | Description |
|---|---|---|---|
| GET/POST | /v6/projects/:projectId/workstreams | JWT / M2M | List / create workstreams |
| GET/PATCH/DELETE | /v6/projects/:projectId/workstreams/:id | JWT / M2M | Get / update / delete workstream |
| GET/POST | /v6/projects/:projectId/workstreams/:workStreamId/works | JWT / M2M | List / create works (maps to ProjectPhase) |
| GET/PATCH/DELETE | /v6/projects/:projectId/workstreams/:workStreamId/works/:id | JWT / M2M | Get / update / delete work |
| GET/POST | /v6/projects/:projectId/workstreams/:workStreamId/works/:workId/workitems | JWT / M2M | List / create work items (maps to PhaseProduct) |
| GET/PATCH/DELETE | /v6/projects/:projectId/workstreams/:workStreamId/works/:workId/workitems/:id | JWT / M2M | Get / update / delete work item |
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v6/projects/copilots/requests | JWT / M2M | List all copilot requests (admin/PM sees all; others see own) |
| GET | /v6/projects/:projectId/copilots/requests | JWT / M2M | Project-scoped copilot requests |
| GET | /v6/projects/copilots/requests/:copilotRequestId | JWT / M2M | Get single copilot request |
| POST | /v6/projects/:projectId/copilots/requests | JWT / M2M | Create copilot request |
| PATCH | /v6/projects/copilots/requests/:copilotRequestId | JWT / M2M | Update copilot request |
| POST | /v6/projects/:projectId/copilots/requests/:copilotRequestId/approve | JWT / M2M | Approve request -> creates opportunity |
| GET | /v6/projects/copilots/opportunities | Public | Dynamically filter and page copilot opportunities |
| GET | /v6/projects/copilot/opportunity/:id (alias: /copilots/opportunity/:id) | Public | Get opportunity details and current-user application state |
| POST | /v6/projects/copilots/opportunity/:id/apply | JWT | Apply as copilot |
| GET | /v6/projects/copilots/opportunity/:id/applications | JWT | List applications |
| POST | /v6/projects/copilots/opportunity/:id/assign | JWT | Assign copilot (triggers member/state transitions) |
| DELETE | /v6/projects/copilots/opportunity/:id/cancel | JWT | Cancel opportunity (cascade) |
Copilot request management routes accept M2M tokens with project-write authorization such as write:projects, all:projects, or all:connect_project.
The opportunity list supports database-level search, status, projectId, projectName, type, skills, requested-start/created date ranges, sorting, and current-user applied / applicationStatus filters. The existing response array and pagination headers remain compatible. See docs/copilot-opportunities.md for the exact contract, aliases, current-user fields, and examples.
Cross-service consumers can install the checked-in packages/projects-prisma-client subdirectory as @topcoder/projects-api-v6. It exports all generated Projects Prisma models, enums, and PrismaClient, plus createProjectsPrismaClient(connectionString, options?), which configures the required Prisma 7 PostgreSQL adapter. See the package README for installation and lifecycle usage.
See docs/api-usage-analysis.md (P2 section) for the complete metadata list.
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v6/projects/metadata | JWT / M2M | Aggregate metadata object |
| GET/POST/PATCH/DELETE | /v6/projects/metadata/projectTypes | JWT / M2M | Project type CRUD |
| GET/POST/PATCH/DELETE | /v6/projects/metadata/projectTemplates | JWT / M2M | Project template CRUD |
| GET | /v6/projects/metadata/productTemplates | JWT / M2M | Product templates |
| GET/POST/PATCH/DELETE | /v6/projects/metadata/workManagementPermission | JWT / M2M | Work-management permission rows |
| GET/POST/PATCH/DELETE | /v6/projects/metadata/orgConfig | JWT / M2M | Org config |
| GET/POST/PATCH/DELETE | /v6/projects/metadata/milestoneTemplates | JWT / M2M | Milestone template CRUD |
| GET/POST/PATCH/DELETE | /v6/projects/metadata/forms | JWT / M2M | Form CRUD |
| GET/POST/PATCH/DELETE | /v6/projects/metadata/planConfigs | JWT / M2M | Plan config CRUD |
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /v6/projects/health | Public | Liveness check |
Swagger UI: http://localhost:3000/v6/projects/api-docs
Layered auth details and guard usage are documented in docs/PERMISSIONS.md.
JWT Bearer token -> TokenRolesGuard -> request.user
↓
ProjectContextInterceptor (loads project members for :projectId routes)
↓
PermissionGuard / AdminOnlyGuard / ProjectMemberGuard / CopilotAndAboveGuard
↓
Controller (@CurrentUser, @ProjectMembers decorators)
| Scope | Implies |
|---|---|
| all:connect_project / all:project | All project read/write scopes |
| all:projects | read:projects + write:projects |
| all:project-members | read:project-members + write:project-members |
| all:project-invites | read:project-invites + write:project-invites |
| all:* | All scopes |
For full event envelope and payload schemas, see docs/event-schemas.md.
| Kafka Topic | Trigger |
|---|---|
| project.created | POST /v6/projects |
| project.updated | PATCH /v6/projects/:projectId (status change or field update) |
| project.action.billingAccount.update | PATCH /v6/projects/:projectId (only when billingAccountId changes) |
| project.deleted | DELETE /v6/projects/:projectId |
| project.member.added | POST /v6/projects/:projectId/members |
| project.member.removed | DELETE /v6/projects/:projectId/members/:id |
Reference source: .env.example.
| Variable | Required | Default | Description |
|---|---|---|---|
| DATABASE_URL | ✅ | - | PostgreSQL connection string for Prisma |
| AUTH_SECRET | ✅ | - | JWT signing secret (from tc-core-library-js) |
| VALID_ISSUERS | ✅ | - | JSON array of accepted JWT issuers |
| AUTH0_URL | ✅ | - | Auth0 token endpoint for M2M |
| AUTH0_AUDIENCE | ✅ | - | M2M audience |
| AUTH0_PROXY_SERVER_URL | - | - | Auth0 proxy (optional) |
| AUTH0_CLIENT_ID | ✅ | - | M2M client ID |
| AUTH0_CLIENT_SECRET | ✅ | - | M2M client secret |
| KAFKA_URL | - | - | Legacy/compatibility setting; not used by current tc-bus-api-wrapper client init |
| KAFKA_ERROR_TOPIC | ✅ | - | Kafka topic used by tc-bus-api-wrapper for postError routing (required by wrapper init) |
| KAFKA_CLIENT_CERT | - | - | Legacy/compatibility setting; not used by current tc-bus-api-wrapper client init |
| KAFKA_CLIENT_CERT_KEY | - | - | Legacy/compatibility setting; not used by current tc-bus-api-wrapper client init |
| BUSAPI_URL | ✅ | - | Topcoder Bus API base URL |
| KAFKA_PROJECT_CREATED_TOPIC | ✅ | project.created | Kafka topic |
| KAFKA_PROJECT_UPDATED_TOPIC | ✅ | project.updated | Kafka topic |
| KAFKA_PROJECT_BILLING_ACCOUNT_UPDATED_TOPIC | ✅ | project.action.billingAccount.update | Kafka topic |
| KAFKA_PROJECT_DELETED_TOPIC | ✅ | project.deleted | Kafka topic |
| KAFKA_PROJECT_MEMBER_ADDED_TOPIC | ✅ | project.member.added | Kafka topic |
| KAFKA_PROJECT_MEMBER_REMOVED_TOPIC | ✅ | project.member.removed | Kafka topic |
| ATTACHMENTS_S3_BUCKET | ✅ | - | S3 bucket for file attachments |
| PROJECT_ATTACHMENT_PATH_PREFIX | - | projects | S3 key prefix |
| PRESIGNED_URL_EXPIRATION | - | 3600 | Presigned URL TTL (seconds) |
| MAX_PHASE_PRODUCT_COUNT | - | 20 | Max phase products per phase |
| ENABLE_FILE_UPLOAD | - | true | Toggle S3 file upload |
| MEMBER_API_URL | ✅ | - | Member API base URL |
| IDENTITY_API_URL | ✅ | - | Identity API base URL |
| BILLING_ACCOUNTS_API_URL | - | - | Billing Accounts API base URL used for default billing-account lookup before Salesforce fallback |
| SALESFORCE_CLIENT_ID | ✅ | - | Salesforce JWT client ID |
| SALESFORCE_CLIENT_AUDIENCE | ✅ | https://login.salesforce.com | Salesforce audience |
| SALESFORCE_SUBJECT | ✅ | - | Salesforce JWT subject |
| SALESFORCE_CLIENT_KEY | ✅ | - | Salesforce private key |
| SALESFORCE_LOGIN_BASE_URL | - | https://login.salesforce.com | Salesforce login URL |
| SALESFORCE_API_VERSION | - | v37.0 | Salesforce API version |
| SALESFORCE_API_CONSUMER_KEY | - | - | Salesforce connected-app consumer key (client-credentials flow) used by the opportunity lookup endpoint |
| SALESFORCE_API_CONSUMER_SECRET | - | - | Salesforce connected-app consumer secret used by the opportunity lookup endpoint |
| SALESFORCE_LOGIN_URL | - | https://topcoder.my.salesforce.com | Salesforce origin used for the client-credentials token exchange |
| SALESFORCE_REST_API_VERSION | - | 65.0 | Salesforce REST API version for the opportunity lookup (no leading v) |
| SFDC_BILLING_ACCOUNT_NAME_FIELD | - | Billing_Account_name__c | SOQL field name |
| SFDC_BILLING_ACCOUNT_MARKUP_FIELD | - | Mark_Up__c | SOQL field name |
| SFDC_BILLING_ACCOUNT_ACTIVE_FIELD | - | Active__c | SOQL field name |
| INVITE_EMAIL_SUBJECT | - | - | Email subject for invites |
| SENDGRID_PROJECT_INVITATION_KNOWN_USER_TEMPLATE_ID | - | - | SendGrid template ID for registered users (Join/Decline invite email) |
| SENDGRID_PROJECT_INVITATION_UNKNOWN_USER_TEMPLATE_ID | - | - | SendGrid template ID for unregistered emails (Register invite email) |
| SENDGRID_TEMPLATE_PROJECT_MEMBER_INVITED | - | - | Legacy fallback SendGrid template ID when dedicated invite template vars are unset |
| SENDGRID_TEMPLATE_COPILOT_ALREADY_PART_OF_PROJECT | - | - | SendGrid template ID |
| SENDGRID_TEMPLATE_INFORM_PM_COPILOT_APPLICATION_ACCEPTED | - | - | SendGrid template ID |
| COPILOT_PORTAL_URL | - | - | Copilot portal URL (used in invite emails) |
| WORK_MANAGER_URL | ✅ | - | Work Manager base URL used to build invite action links in emails. Format: https://work.topcoder.com. Must not have a trailing slash. |
| ACCOUNTS_APP_URL | - | - | Accounts app URL (used in invite emails) |
| UNIQUE_GMAIL_VALIDATION | - | false | Treat Gmail + aliases as same address |
| PORT | - | 3000 | HTTP listen port |
| API_PREFIX | - | v6 | Global route prefix |
| HEALTH_CHECK_TIMEOUT | - | 60000 | Health check timeout (ms) |
| PROJECT_SERVICE_PRISMA_TIMEOUT | - | 10000 | Prisma query timeout (ms) |
| CORS_ALLOWED_ORIGIN | - | - | Additional CORS origin (regex string) |
| NODE_ENV | - | development | Node environment |
pnpm installpostinstall runs prisma generate.
Configure DATABASE_URL, then run:
pnpm exec prisma migrate dev
pnpm prisma db seedCopy .env.example to .env and fill in all required variables.
pnpm run start:devpnpm run build
pnpm run start:prodpnpm lintMust pass before every commit per AGENTS.md.
pnpm buildMust pass before every commit per AGENTS.md.
| Command | Purpose |
|---|---|
| pnpm test | Unit tests (Jest) |
| pnpm test:cov | Unit tests with coverage |
| pnpm test:e2e | Full e2e suite |
| pnpm test:load | Load / performance tests (autocannon) |
| pnpm test:deployment | Deployment smoke validation |
Open findings are tracked inline with TODO (security) comments in source.
| Location | Finding | Severity | Status |
|---|---|---|---|
| src/main.ts | CORS_ALLOWED_ORIGIN env var compiled directly into RegExp - ReDoS risk | Medium | Open - validate/escape before use |
| src/main.ts | CORS returns '*' for requests with no Origin header | Low | Open - consider returning false for server-to-server calls |
| src/main.ts | Swagger UI publicly accessible with no auth in production | Medium | Open - restrict by IP or add HTTP Basic auth, or gate behind env flag |
| src/main.ts | Duplicate Swagger mount at /v6/projects-api-docs | Low (quality) | Open - consolidate to single path |
| Event publication logging | Environment-derived Kafka topics and raw client errors could reach clear-text logs | High | Resolved - log fixed operation markers and allowlisted error categories only |
| docs/DEPENDENCIES.md | GitHub-sourced Topcoder packages do not have a registry release stream | Low | Mitigated with immutable commit pins; external API dependencies install only their generated Prisma-client subdirectories |
Summary from docs/DEPENDENCIES.md:
Full details: docs/DEPENDENCIES.md.
Open TODO (quality) findings from prior phases:
| Location | Finding |
|---|---|
| src/main.ts | serializeBigInt should move to src/shared/utils/serialization.utils.ts |
| src/main.ts | LoggerService instantiated per HTTP request - hoist to module scope |
| src/main.ts | Duplicate Swagger mount - consolidate to one path |
| src/main.ts | WorkStreamModule included in Swagger but not in ApiModule imports - causes documentation drift |
| src/shared/services/permission.service.ts | Large switch/case permission map - refactor to a data-driven lookup table |
| src/api/copilot/copilot.utils.ts | Sort utility functions duplicated across copilot sub-services - centralize |
Full details: docs/DIFFERENCES_FROM_V5.md and docs/MIGRATION_FROM_TC_PROJECT_SERVICE.md.
Migration runbook (phased rollout, rollback, monitoring): docs/MIGRATION_RUNBOOK.md.
| Document | Purpose |
|---|---|
| docs/PERMISSIONS.md | Full permission system reference, guard usage, M2M scope hierarchy |
| docs/api-usage-analysis.md | v5 -> v6 endpoint mapping, P0/P1/P2 classification, consumer call patterns |
| docs/event-schemas.md | Kafka event envelope and payload schemas |
| docs/DIFFERENCES_FROM_V5.md | Intentional differences and improvements vs tc-project-service |
| docs/MIGRATION_FROM_TC_PROJECT_SERVICE.md | Auth migration guide, permission mapping, consumer notes |
| docs/MIGRATION_RUNBOOK.md | Phased rollout, rollback procedures, monitoring alerts |
| docs/DEPENDENCIES.md | Dependency security audit, outdated packages, overrides |
| docs/timeline-milestone-migration.md | Guidance for future timeline/milestone migration |
| Back | FazBrowse Home | New Git URL |