Skip to content

Commit aac5966

Browse files
authored
Merge pull request #147 from topcoder-platform/opportunities-v6
Add external Challenge Prisma client for Opportunities
2 parents df00093 + c06ab1f commit aac5966

51 files changed

Lines changed: 58120 additions & 59587 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,34 @@ remain compatible. Database access uses Prisma 7 with the PostgreSQL driver
3737
adapter. Domain events continue to be sent through the existing Bus API wrapper;
3838
this service does not connect to Kafka directly.
3939

40-
The API runtime client is Prisma 7. The checked-in
41-
`packages/challenge-prisma-client` artifact remains on Prisma 6 for its existing
42-
downstream consumers, so the root generation command intentionally targets only
43-
the API client. Upgrading that shared artifact requires a coordinated downstream
44-
release.
40+
The API runtime client and the checked-in external client use Prisma 7. The
41+
external client has a stable package wrapper at
42+
`packages/challenge-prisma-client`; generated Prisma files live below its
43+
`generated` directory so regeneration cannot overwrite the public contract.
44+
45+
## External Prisma client
46+
47+
Services that need to aggregate challenge data directly can install the
48+
`packages/challenge-prisma-client` Git subdirectory as
49+
`@topcoder/challenge-api-v6`. The package exports all generated challenge
50+
models, enums, Prisma helpers, and `PrismaClient`, plus this supported factory:
51+
52+
```ts
53+
import { createChallengePrismaClient } from '@topcoder/challenge-api-v6';
54+
55+
const challenges = createChallengePrismaClient(process.env.CHALLENGE_DATABASE_URL, {
56+
log: ['warn', 'error'],
57+
});
58+
```
59+
60+
`createChallengePrismaClient(connectionString, options?)` creates a Prisma 7
61+
PostgreSQL driver adapter, preserves the optional `schema` query parameter in
62+
the connection URL, and returns a disconnected client that connects lazily on
63+
its first query. Call `$disconnect()` during application shutdown. The factory
64+
throws `TypeError` when `connectionString` is empty or not a string; Prisma may
65+
raise its normal configuration and database errors while creating or using the
66+
client. Connection-defining `adapter` and `accelerateUrl` options are owned by
67+
the factory and intentionally excluded from its options type.
4568

4669
## Configuration
4770

@@ -90,7 +113,7 @@ configuration parameters.
90113
Run `nvm use` before pnpm commands. Make sure `DATABASE_URL` is set before any
91114
database operation or application startup.
92115

93-
1. Install dependencies and generate the Prisma client: `pnpm install`
116+
1. Install dependencies and generate both Prisma clients: `pnpm install`
94117
2. Build the API: `pnpm build`
95118
3. Create or update local database tables: `pnpm create-tables`
96119
4. Seed tables: `pnpm seed-tables`
@@ -130,7 +153,8 @@ database operation or application startup.
130153
DATABASE_URL=
131154
```
132155

133-
Then run `pnpm install`. The postinstall hook generates the Prisma 7 client.
156+
Then run `pnpm install`. The postinstall hook generates both the internal and
157+
external Prisma 7 clients.
134158

135159
2. 🚢 Start docker-compose with services which are required to start Topcoder Challenges API locally
136160

@@ -239,6 +263,13 @@ To run unit tests alone
239263
pnpm test
240264
```
241265

266+
To smoke-test the packaged external Prisma factory without connecting to a
267+
database:
268+
269+
```bash
270+
pnpm test:external-client
271+
```
272+
242273
To run unit tests with coverage report
243274

244275
```bash
@@ -310,6 +341,17 @@ Refer to the verification document `Verification.md`
310341
bypass. Any update that starts in or transitions to a completed or cancelled status cannot change
311342
the effective `is_test_challenge` value; omitting metadata preserves it. Normal authorization
312343
checks still apply.
344+
- Role-specific member competition searches use
345+
`GET /v6/challenges?memberId={memberId}&resourceRoleId={resourceRoleUuid}`.
346+
`resourceRoleId` is an exact UUID and requires `memberId`. The resource role is
347+
applied before all challenge filters, global sorting, totals, and pagination;
348+
omitting it preserves the existing any-resource behavior of `memberId`. This
349+
public query only narrows results and never grants access: anonymous callers
350+
retain anonymous visibility, and authenticated callers remain subject to
351+
whitelist, group, and task rules based on the caller. For “My competitions,”
352+
pass the configured Submitter resource-role UUID. Deploy migration
353+
`20260813130000_add_role_to_member_access_view` before this service version,
354+
because the generated Prisma client expects the view's new `roleId` column.
313355
- API base configuration points to v6 in dev/local and v5 in prod (for compatibility):
314356
- Dev: `work-manager/config/constants/development.js`.
315357
- Local: `work-manager/config/constants/local.js`.

docs/swagger.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ paths:
5353
- Challenges
5454
description: |
5555
Retrieve challenges in the system.
56+
57+
`resourceRoleId` may be combined with `memberId` to restrict the member's
58+
resource-associated challenges to one UUID resource role before challenge
59+
filtering, sorting, totals, and pagination. It does not grant access: results
60+
remain subject to the caller's whitelist, group, and task visibility. Anonymous
61+
callers receive only challenges visible to anonymous users.
5662
security:
5763
- bearer: []
5864
produces:
@@ -354,6 +360,12 @@ paths:
354360
description: Filter challenges memberId has access to
355361
required: false
356362
type: string
363+
- name: resourceRoleId
364+
in: query
365+
description: Filter the member resource association by exact resource-role UUID. Requires memberId. This only narrows results and does not grant challenge access.
366+
required: false
367+
type: string
368+
format: UUID
357369
- name: sortBy
358370
in: query
359371
description: Sort the results by the field.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@
55
"main": "dist/main.js",
66
"packageManager": "pnpm@11.15.1",
77
"scripts": {
8+
"prebuild": "pnpm run prisma:generate",
89
"build": "nest build",
910
"start": "node dist/main.js",
1011
"start:dev": "nest start --watch",
1112
"start:debug": "nest start --debug --watch",
1213
"start:prod": "node dist/main.js",
1314
"postinstall": "pnpm run prisma:generate",
14-
"prisma:generate": "prisma generate --generator client",
15+
"prisma:generate": "prisma generate",
1516
"lint": "eslint --no-error-on-unmatched-pattern \"*.ts\" \"src/**/*.ts\" \"prisma/**/*.ts\" \"test/**/*.ts\"",
1617
"lint:fix": "pnpm lint --fix",
1718
"format": "prettier --write \"*.ts\" \"src/**/*.ts\" \"prisma/**/*.ts\" \"test/**/*.ts\"",
@@ -21,6 +22,7 @@
2122
"recalculate-winners": "node --require ts-node/register/transpile-only data-migration/src/scripts/recalculateChallengeWinners.js",
2223
"recalculate-winners:csv": "node --require ts-node/register/transpile-only data-migration/src/scripts/recalculateChallengeWinners.js --csv-only",
2324
"test": "NODE_ENV=test mocha --require ts-node/register/transpile-only \"test/unit/**/*.test.{js,ts}\" --exit",
25+
"test:external-client": "node --test packages/challenge-prisma-client/factory.test.js",
2426
"e2e": "NODE_ENV=test mocha --require ts-node/register/transpile-only \"test/e2e/*.test.{js,ts}\" --exit",
2527
"test:cov": "nyc --reporter=html --reporter=text pnpm test",
2628
"e2e:cov": "nyc --reporter=html --reporter=text pnpm e2e",
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# `@topcoder/challenge-api-v6`
2+
3+
This package is the supported external Prisma client for the Challenge API v6
4+
schema. It re-exports the generated Prisma surface and provides
5+
`createChallengePrismaClient(connectionString, options?)`, which configures the
6+
Prisma 7 PostgreSQL driver adapter and honors the connection URL's optional
7+
`schema` query parameter.
8+
9+
```ts
10+
import { createChallengePrismaClient } from '@topcoder/challenge-api-v6';
11+
12+
const client = createChallengePrismaClient(process.env.CHALLENGE_DATABASE_URL);
13+
const activeCount = await client.challenge.count({
14+
where: { status: 'ACTIVE' },
15+
});
16+
await client.$disconnect();
17+
```
18+
19+
Callers that need bounded database work can pass PostgreSQL pool settings
20+
without constructing the Prisma 7 adapter themselves:
21+
22+
```ts
23+
const client = createChallengePrismaClient(databaseUrl, {
24+
driverOptions: {
25+
connectionTimeoutMillis: 5000,
26+
query_timeout: 5000,
27+
statement_timeout: 5000,
28+
},
29+
});
30+
```
31+
32+
The client connects lazily. Applications own its lifecycle and must disconnect
33+
it during shutdown. An empty or non-string connection URL raises `TypeError`;
34+
Prisma reports its normal configuration and database errors during creation or
35+
query execution.

0 commit comments

Comments
 (0)