Reader Access manages gated and private documentation access at reader-facing serving choke points. DocsAccessGuard and DocsVisibilityService decide project-level access and D4 visibility rules, while ProjectAccessController owns policy and share-link management. ReaderAuthGuard and ReaderTokenService ingest and verify the shared reader identity envelope, and password or share-token flows reject unpublished, hidden, unauthorized, or invalid requests.
36 entities in atloria-monorepo/apps/api/src/reader-access. 7 other subsystems depend on it, which makes it the 8th most depended-upon part of this codebase.
What it is made of
Its 36 entities sit in 12 files under atloria-monorepo/apps/api/src/reader-access: 8 interfaces, 7 services, 5 HTTP endpoints, 5 type aliases and 11 more.
visibility.util.ts holds 7 of them — more than any other file here.
DocsAccessService is what the rest of it leans on: 4 of its own members depend on it, more than on anything else inside the boundary.
Where work enters
1 controller publishes 5 HTTP endpoints — 2 GET, 1 PUT, 1 POST and 1 DELETE. They answer under /projects/:id. Every one of them declares a guard — JwtAuthGuard on 5 and RolesGuard on 5.
ProjectAccessController—atloria-monorepo/apps/api/src/reader-access/project-access.controller.ts:36getPolicy—atloria-monorepo/apps/api/src/reader-access/project-access.controller.ts:47updatePolicy—atloria-monorepo/apps/api/src/reader-access/project-access.controller.ts:55listShareLinks—atloria-monorepo/apps/api/src/reader-access/project-access.controller.ts:68createShareLink—atloria-monorepo/apps/api/src/reader-access/project-access.controller.ts:75revokeShareLink—atloria-monorepo/apps/api/src/reader-access/project-access.controller.ts:88
How work moves through it
mermaidflowchart LR ProjectAccessController0["ProjectAccessController"] ProjectAccessService10["ProjectAccessService"] ProjectAccessController0 --> ProjectAccessService10 PrismaService20["PrismaService"] ProjectAccessService10 --> PrismaService20 PlanService21["PlanService"] ProjectAccessService10 --> PlanService21 DocsAccessService22["DocsAccessService"] ProjectAccessService10 --> DocsAccessService22 AuditService23["AuditService"] ProjectAccessService10 --> AuditService23 ReaderTokenService30["ReaderTokenService"] DocsAccessService22 --> ReaderTokenService30 RedisService31["RedisService"] DocsAccessService22 --> RedisService31 EmailService32["EmailService"] DocsAccessService22 --> EmailService32 stop["refused"] ProjectAccessService10 -. "NotFoundException" .-> stop
Work enters at ProjectAccessController and passes through 8 other components. Each step below is a dependency edge between two entities in this repository, followed outward in order.
ProjectAccessControllertakes the work first —atloria-monorepo/apps/api/src/reader-access/project-access.controller.ts:36.- Next,
ProjectAccessControllerhands off toProjectAccessService—atloria-monorepo/apps/api/src/reader-access/project-access.service.ts:54. - Then,
ProjectAccessServicecallsPrismaService,PlanService,DocsAccessServiceandAuditService. - Finally,
DocsAccessServicecallsReaderTokenService,RedisServiceandEmailService.
Where the work stops
ProjectAccessServicestops the work withNotFoundExceptionwhen!project— “Project not found”.ProjectAccessServicestops the work withForbiddenExceptionwhenproject.organizationId !== user.organizationId— “Access denied to this project”.DocsAccessServicestops the work withNotFoundExceptionwhenvis === 'hidden'— “Document not found or not published for this audience”.DocsAccessServicestops the work withNotFoundExceptionwhen!ctx— “Project not found”.ReaderTokenServicestops the work withBadRequestExceptionwhencapTtl <= 0— “This access grant has already expired.”.
When a step fails
PrismaServicehandles failure in 1 place: it lets it reach the caller in all 1.DocsAccessServicehandles failure in 1 place: it lets it reach the caller in all 1.AuditServicehandles failure in 1 place: it logs it and continues in all 1.ReaderTokenServicehandles failure in 1 place: it turns it into a return value in all 1.
How it refuses and fails
7 of its components record a refusal or a failure handler.
All 7 of them refuse work outright, under a condition written into the component itself.
Their catch blocks handle a failure that already happened in 3 places.
Of those 3, 2 let it reach the caller and 1 turns it into a return value.
Boundaries
7 other subsystems depend on this one — Auth, Changelog, Project, Reader Account, Sdk, Technical Docs, Tours. Changing what it exposes changes them.
Those 7 hold 18 edges between them, unevenly: Project reaches in across 6 edges, while 2 of them hold one each. 18 edges arrive against 13 leaving — more of this repository reaches into it than it reaches out to. What they reach is narrower than the folder: 5 of its 36 members carry every inbound edge — ReaderAccessModule (7), ReaderTokenService (4) and DocsVisibilityService (4), plus 2 more. Of the 13 it sends out, 7 go to Database — more than to any other.
It depends on Database, Email, Billing, Audit, and on nothing else in this repository.
How this code is named
These conventions cover most of the codebase. Learning them is faster than reading an index — each one lets you find any member of its family without looking it up.
| Pattern | Where | Count | Examples |
|---|---|---|---|
*.service.ts | api/src/reader-access/ | 5 | docs-access.service.ts, reader-token.service.ts, project-access.service.ts, docs-visibility.service.ts |
Was this page helpful?