Skip to content

Commit 05b39fd

Browse files
authored
Merge pull request #441 from Producdevity/refactor/split-pclistings-router
Refactor hardware modules around feature-owned architecture
2 parents be26f58 + 0faa8ce commit 05b39fd

279 files changed

Lines changed: 13728 additions & 9497 deletions

File tree

Some content is hidden

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

.env.docker.example

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,6 @@ NEXT_PUBLIC_GITHUB_URL="https://github.com/Producdevity/EmuReady"
7676
NEXT_PUBLIC_EMUREADY_LITE_GITHUB_URL="https://github.com/Producdevity/EmuReadyLite/releases"
7777
NEXT_PUBLIC_APP_URL="https://dev.emuready.com"
7878
NEXT_PUBLIC_ENABLE_SW=false
79-
NEXT_PUBLIC_ENABLE_ASYNC_LISTINGS_FILTERS=false
80-
NEXT_PUBLIC_ENABLE_V2_LISTINGS=false
8179
NEXT_TELEMETRY_DISABLED=1
8280
NEXT_IMAGE_UNOPTIMIZED=false
8381

.env.example

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ NEXT_PUBLIC_EMUREADY_LITE_GITHUB_URL="https://github.com/Producdevity/EmuReadyLi
5151
NEXT_PUBLIC_APP_URL="http://localhost:3000" # Make sure to change this if you are using a tunnel
5252
NEXT_PUBLIC_ENABLE_SW=false
5353
NEXT_PUBLIC_ENABLE_PATREON_VERIFICATION=true
54-
NEXT_PUBLIC_ENABLE_ASYNC_LISTINGS_FILTERS=false
55-
NEXT_PUBLIC_ENABLE_V2_LISTINGS=false
5654
NEXT_TELEMETRY_DISABLED=1
5755
NEXT_IMAGE_UNOPTIMIZED=false
5856

.env.test.example

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ NEXT_PUBLIC_APP_URL="https://dev.emuready.com"
4040
NEXT_PUBLIC_ENABLE_PATREON_VERIFICATION=true
4141
NEXT_PUBLIC_ENABLE_SW=false
4242
NEXT_PUBLIC_DISABLE_COOKIE_BANNER=true
43-
NEXT_PUBLIC_ENABLE_ASYNC_LISTINGS_FILTERS=false
44-
NEXT_PUBLIC_ENABLE_V2_LISTINGS=false
4543
NEXT_TELEMETRY_DISABLED=1
4644
NEXT_IMAGE_UNOPTIMIZED=true
4745

AGENTS.md

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,53 @@ This file is the source of working guidance for AI coding agents in this reposit
3333
- Feature folders should follow the project-structure guidance from Bulletproof React:
3434
https://github.com/alan2207/bulletproof-react/blob/master/docs/project-structure.md
3535
- Within `src/features/*`, prefer scoped subdirectories such as `components`, `hooks`, `utils`, `server`, and `shared` instead of flat feature folders.
36-
- Routers in `src/server/api/routers/` are thin orchestration layers. They handle auth context, schema-validated input, repository/service calls, and response formatting.
36+
- Feature-owned modules may colocate client, server, and shared code under
37+
`src/features/<domain>/<module>/`.
38+
- Use this feature module structure for new or actively-refactored domain code:
39+
- `shared/` contains Zod schemas, types, constants, and pure formatting helpers usable by client and server.
40+
- `server/` contains repositories, services, policies, mappers, and feature-owned tRPC routers.
41+
- `client/` contains hooks, reusable components, and workflow views. Add client API wrappers only when they remove real duplication or encode a stable UI contract.
42+
- `client/admin/` is allowed for admin-only workflows.
43+
- Import direction matters more than folder names:
44+
- `client/` may import from its feature `shared/` and app-wide client-safe utilities.
45+
- `server/` may import from its feature `shared/`, server utilities, and repositories.
46+
- `shared/` must not import from `client/`, `server/`, `src/app`, or server-only libraries.
47+
- `src/app/**` routes/pages should compose feature modules; feature modules should not import from `src/app/**`.
48+
- tRPC routers are transport adapters. Feature-specific routers should live in the feature `server/` folder when that feature owns the full use case; `src/server/api/root.ts` should only compose them.
49+
- Legacy routers in `src/server/api/routers/` are thin orchestration layers. They handle auth context, schema-validated input, repository/service calls, and response formatting.
3750
- Do not put raw Prisma queries or business logic in routers.
38-
- Define Zod schemas in `src/schemas/*`; do not define inline schemas in router `.input(...)` calls.
39-
- All database access belongs in repository classes under `src/server/repositories/` extending `BaseRepository`.
51+
- Define Zod schemas in feature `shared/*.schemas.ts` for feature-owned code, or in `src/schemas/*` for legacy/shared code. Do not define inline schemas in router `.input(...)` calls.
52+
- Feature-owned tRPC procedures should declare `.output(...)` with Zod schemas. Compatibility transports that must keep legacy shapes should still have explicit legacy output schemas instead of returning raw Prisma payloads by convention.
53+
- All database access belongs in repository classes. Feature-owned repositories may live in feature `server/` folders; legacy/shared repositories may remain under `src/server/repositories/`.
54+
- New or actively-refactored feature-owned Prisma repositories should extend `PrismaRepository` or `PrismaWriteRepository` from `src/server/persistence/prisma.repository.ts` for Prisma client ownership and shared write handling. Do not extend the legacy `BaseRepository` unless the inherited behavior is deliberately required and documented.
55+
- Do not add generic CRUD methods to shared repository bases. Prisma already provides typed CRUD; feature repositories should expose domain/use-case persistence operations with named select contracts.
56+
- For feature-owned Prisma repositories, prefer a `server/persistence/` subfolder for named `select` contracts, query builders, and Prisma error translation. Derive repository record types from Prisma `GetPayload` plus those named `select` contracts instead of hand-maintaining structural copies.
57+
- Services should depend on the concrete feature repository by default. Do not add service-owned `Pick<Repository, ...>` contracts only for tests.
58+
- Add repository interfaces only for real boundaries: multiple implementations, external provider adapters, lifecycle concerns that route composition cannot handle directly, or domain/application layers that intentionally must not depend on infrastructure.
4059
- Repositories should use project error helpers and consistent database operation handling.
41-
- Multi-step business logic, external API orchestration, and complex calculations belong in services under `src/server/services/`.
60+
- Multi-step business logic, external API orchestration, and complex calculations belong in services under feature `server/` folders or legacy `src/server/services/`.
61+
- Use policy functions for reusable authorization/business access rules that must be shared across transports. Routers may still use broad auth procedures, but services should enforce feature-level capabilities when the use case can be called from multiple transports.
4262
- Use `AppError` and `ResourceError` helpers instead of raw `Error`, raw strings, or one-off `TRPCError` usage.
4363
- Use specialized procedures such as `protectedProcedure`, `adminProcedure`, and `permissionProcedure(...)` instead of ad hoc permission checks.
4464

65+
## API Compatibility And Legacy Contracts
66+
67+
- Before introducing any `legacy` select, repository method, route, endpoint,
68+
schema, type, mapper, compatibility branch, or response shape, audit known
69+
consumers first. For mobile/public API work, this includes
70+
`/Volumes/T9/Coding/personal/2026/Emulation/EmuReadyApp` when it is available,
71+
or a temporary clone of `Producdevity/EmuReadyApp` on the `master` branch when
72+
the local app checkout is unavailable or not production-synced.
73+
- Record which fields consumers actually read. Do not preserve fields only
74+
because they existed in an old Prisma payload, old inferred type, or old API
75+
response.
76+
- Decide compatibility case by case: remove unused old fields, migrate the
77+
consumer, keep one standardized endpoint with a small low-cost superset, or
78+
keep a separate legacy contract only when the audited consumer behavior truly
79+
requires it.
80+
- Legacy contracts must have an owner, a reason, and an expected removal path.
81+
Remove legacy code as soon as audited consumers do not need it.
82+
4583
## Database And Prisma
4684

4785
- Treat database changes as high risk.
@@ -60,6 +98,12 @@ This file is the source of working guidance for AI coding agents in this reposit
6098
- Do not use casts to hide type problems. Fix the underlying type issue.
6199
- Handle null and undefined explicitly.
62100
- Use generated Prisma types where appropriate.
101+
- Prefer deriving types from existing contracts instead of hand-maintaining
102+
structural copies. Use Prisma `GetPayload`, Zod `z.input`/`z.output`, tRPC
103+
`RouterInput`/`RouterOutput`, `ReturnType`, and `typeof` on const contracts
104+
before adding a new interface or structural type alias. Add new manual
105+
interfaces/types only for genuinely new UI/application state or external
106+
boundaries that cannot be inferred, and keep them narrow and local.
63107
- Do not add unused functions, exports, or speculative helpers.
64108
- Remove dead code when refactoring.
65109
- Do not remove or rewrite existing TODO comments unless the user explicitly

config/image-hosts.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
export const GAME_IMAGE_PROVIDER_HOST_PATTERNS = [
2+
'media.rawg.io',
3+
'cdn.thegamesdb.net',
4+
'images.igdb.com',
5+
'assets.nintendo.com',
6+
'shared.akamai.steamstatic.com',
7+
'cdn1.epicgames.com',
8+
'cdn2.unrealengine.com',
9+
'images.gog-statics.com',
10+
] as const
11+
12+
export const NEXT_IMAGE_REMOTE_HOST_PATTERNS = [
13+
'placehold.co',
14+
'*.clerk.com',
15+
'*.clerk.accounts.dev',
16+
'storage.ko-fi.com',
17+
'ko-fi.com',
18+
...GAME_IMAGE_PROVIDER_HOST_PATTERNS,
19+
] as const
20+
21+
export const NEXT_IMAGE_REMOTE_PATTERNS = NEXT_IMAGE_REMOTE_HOST_PATTERNS.map((hostname) => ({
22+
protocol: 'https' as const,
23+
hostname,
24+
pathname: '/**',
25+
}))

0 commit comments

Comments
 (0)