Skip to content

Commit 13d97fd

Browse files
authored
claude docs (#375)
1 parent c843e18 commit 13d97fd

4 files changed

Lines changed: 465 additions & 0 deletions

File tree

.claude/CLAUDE.md

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
TPEN Services is the backend API for TPEN3 (Transcription for Paleographical and Editorial Notation), a web-based tool for transcribing and annotating digital manuscripts. This Node.js/Express API provides:
8+
9+
- **IIIF-compliant** annotation services following W3C Web Annotation standards
10+
- **Multi-user collaboration** with role-based access control
11+
- **Persistent storage** of transcriptions via RERUM/TinyThings
12+
- **Project management** for organizing manuscript transcription work
13+
- **RESTful API** endpoints for frontend applications
14+
15+
The service acts as a middleware layer between TPEN3 frontends and multiple data storage backends (MongoDB for metadata, RERUM for annotations).
16+
17+
## Tech Stack
18+
19+
### Core Technologies
20+
- **Node.js**: >= 22.20.0 (REQUIRED - uses modern JS features)
21+
- **Express**: 5.1.0 - Web framework
22+
- **MongoDB**: 6.20.0 - Primary database for projects, users, groups
23+
- **RERUM/TinyThings**: External service for persistent annotation storage
24+
25+
### Key Dependencies
26+
- **Auth0**: JWT-based authentication via express-oauth2-jwt-bearer
27+
- **IIIF**: @iiif/helpers for Presentation API support
28+
- **DOMPurify**: XSS protection for user input
29+
- **Jest**: Testing framework with Supertest for API testing
30+
31+
## Project Structure
32+
33+
```
34+
/
35+
├── auth/ # Authentication middleware (Auth0 JWT validation)
36+
├── bin/ # Server startup script (tpen3_services.js)
37+
├── classes/ # Core business logic classes
38+
│ ├── Project.js # Project CRUD and validation
39+
│ ├── User.js # User profile and membership
40+
│ ├── Group.js # Collaborator groups and permissions
41+
│ ├── Layer.js # Annotation layers (RERUM-backed)
42+
│ ├── Page.js # Annotation pages (RERUM-backed)
43+
│ └── Line.js # Individual annotations (RERUM-backed)
44+
├── database/ # Database abstraction layer
45+
│ ├── dbDriver.js # Unified interface for all DBs
46+
│ ├── mongo/ # MongoDB implementation
47+
│ └── tiny/ # RERUM/TinyThings implementation
48+
├── project/ # Project API routes
49+
├── userProfile/ # User profile routes
50+
├── utilities/ # Shared utilities and helpers
51+
└── __tests__/ # Test suites
52+
```
53+
54+
## Core Concepts
55+
56+
### Projects
57+
- Container for manuscript transcription work
58+
- Contains layers, manifests, metadata, and tools
59+
- Linked to a Group for access control
60+
- Identified by MongoDB ObjectId
61+
62+
### Layers
63+
- Logical groupings of annotations (e.g., "Transcription", "Translation")
64+
- Stored in RERUM as AnnotationCollections
65+
- Contains Pages which contain Lines
66+
67+
### Pages
68+
- Represents annotations for a single manuscript page/canvas
69+
- Stored as AnnotationPages in RERUM
70+
- Linked to IIIF canvas URIs
71+
72+
### Lines
73+
- Individual annotations/transcriptions
74+
- Stored as Web Annotations in RERUM
75+
- Target specific regions on manuscript images
76+
77+
### Groups
78+
- Manage project membership and permissions
79+
- Support custom roles beyond OWNER/CONTRIBUTOR/VIEWER
80+
- Control who can edit, view, or manage projects
81+
82+
## API Architecture
83+
84+
### RESTful Conventions
85+
```javascript
86+
GET /project/:id // Retrieve resource
87+
POST /project/create // Create new resource
88+
PUT /project/:id // Update resource
89+
DELETE /project/:id // Delete resource
90+
```
91+
92+
### Response Patterns
93+
```javascript
94+
// Success
95+
res.status(200).json(data)
96+
97+
// Error
98+
res.status(400).json({ error: "message" })
99+
100+
// No content
101+
res.status(204).send()
102+
```
103+
104+
### Common Status Codes
105+
- 200: Success
106+
- 201: Created
107+
- 401: Unauthorized (invalid/missing token)
108+
- 403: Forbidden (insufficient permissions)
109+
- 404: Not Found
110+
- 500: Server Error
111+
112+
## Database Strategy
113+
114+
### MongoDB (Primary Storage)
115+
- Projects, Users, Groups, HotKeys collections
116+
- Handles metadata, relationships, and configuration
117+
- ObjectId-based identification
118+
119+
### RERUM/TinyThings (Annotation Storage)
120+
- Persistent, versioned annotation storage
121+
- Returns stable URIs for annotations
122+
- Handles Layers, Pages, Lines as JSON-LD
123+
- Accessed via HTTP API
124+
125+
### Database Abstraction
126+
```javascript
127+
// Always use the abstraction layer
128+
const database = new dbDriver("mongo")
129+
await database.save(data, "projects")
130+
await database.findOne({ _id: id }, "projects")
131+
```
132+
133+
## Authentication & Authorization
134+
135+
### Authentication Flow
136+
1. Client sends JWT in `Authorization: Bearer <token>`
137+
2. `auth0Middleware()` validates token with Auth0
138+
3. User agent extracted from token claims
139+
4. User record loaded/created from database
140+
141+
### Authorization Model
142+
```javascript
143+
// Default roles
144+
OWNER // Full control, can transfer ownership
145+
CONTRIBUTOR // Can edit content
146+
VIEWER // Read-only access
147+
148+
// Permission checking
149+
Project.checkUserAccess(userId, "edit_page", "layer", layerId)
150+
```
151+
152+
### Protected Routes
153+
```javascript
154+
router.post("/path", auth0Middleware(), async (req, res) => {
155+
const userId = req.user._id
156+
// Route handler
157+
})
158+
```
159+
160+
## Development Workflow
161+
162+
### Getting Started
163+
```bash
164+
# Install dependencies
165+
npm install
166+
167+
# Set up environment
168+
cp sample.env .env
169+
# Edit .env with your configuration
170+
171+
# Start development server
172+
npm run dev
173+
174+
# Run tests
175+
npm test
176+
```
177+
178+
### Environment Variables
179+
```
180+
# Essential for development
181+
PORT=3001
182+
MONGODB=mongodb://localhost:27017
183+
MONGODBNAME=tpen3
184+
RERUMURL=https://store.rerum.io/v1
185+
AUDIENCE=https://yourapp.auth0.com/api
186+
DOMAIN=yourapp.auth0.com
187+
```
188+
189+
### Making Changes
190+
191+
1. **Follow existing patterns** - Look at similar code for guidance
192+
2. **Use the abstraction layers** - Don't access databases directly
193+
3. **Validate input** - Use utility validators in `/utilities`
194+
4. **Handle errors gracefully** - Use respondWithError() helper
195+
5. **Write tests** - Add tests for new functionality
196+
197+
## Testing Guidelines
198+
199+
### Running Tests
200+
```bash
201+
npm run allTests # All tests
202+
npm run unitTests # Unit tests only
203+
npm run E2Etests # End-to-end tests
204+
npm run dbTests # Database tests
205+
```
206+
207+
### Test Organization
208+
- Tag tests with descriptive labels (e.g., `user_class`, `auth_test`)
209+
- Use Supertest for API endpoint testing
210+
- Mock external services when appropriate
211+
- Tests should be independent and idempotent
212+
213+
## Code Style & Conventions
214+
215+
### JavaScript Style
216+
```javascript
217+
// ES6+ modules
218+
import { something } from './module.js'
219+
220+
// Async/await for all async operations
221+
async function processData() {
222+
const result = await database.find({}, "collection")
223+
return result
224+
}
225+
226+
// Early returns with guard clauses
227+
if (!isValid) {
228+
return respondWithError(res, 400, "Invalid input")
229+
}
230+
231+
// Nullish coalescing and optional chaining
232+
const value = data?.property ?? defaultValue
233+
```
234+
235+
### Naming Conventions
236+
- Files: camelCase.js
237+
- Classes: PascalCase
238+
- Functions/variables: camelCase
239+
- Routes: kebab-case
240+
- Database collections: UPPERCASE
241+
242+
### Commit Messages
243+
```
244+
feat: Add new feature
245+
fix: Fix bug
246+
docs: Update documentation
247+
test: Add tests
248+
refactor: Refactor code
249+
```
250+
251+
## Security Considerations
252+
253+
### Input Validation
254+
```javascript
255+
// Always sanitize user input
256+
import DOMPurify from 'isomorphic-dompurify'
257+
const clean = DOMPurify.sanitize(userInput)
258+
259+
// Check for suspicious content
260+
if (checkIfSuspicious(content)) {
261+
throw new Error("Suspicious content detected")
262+
}
263+
```
264+
265+
### Authentication Required
266+
- All write operations require valid JWT
267+
- User permissions checked before data modifications
268+
- Ownership verified for sensitive operations
269+
270+
### CORS Configuration
271+
- Configured per endpoint as needed
272+
- Default CORS settings in common_cors.json
273+
- Restrictive by default
274+
275+
## Common Tasks
276+
277+
### Adding a New API Endpoint
278+
1. Create route file in appropriate directory
279+
2. Define route with authentication middleware
280+
3. Implement business logic in classes/
281+
4. Add validation and error handling
282+
5. Write tests for the endpoint
283+
284+
### Working with Projects
285+
```javascript
286+
// Load a project
287+
const project = new Project(projectId)
288+
await project.load()
289+
290+
// Check user access
291+
const canEdit = await project.checkUserAccess(userId, "edit", "project")
292+
293+
// Update project
294+
project.title = "New Title"
295+
await project.save()
296+
```
297+
298+
### Working with Annotations
299+
```javascript
300+
// Create a new annotation page
301+
const page = new Page({
302+
label: "Page 1",
303+
target: canvasUri
304+
})
305+
await page.save()
306+
307+
// Add to layer
308+
layer.pages.push(page.id)
309+
await layer.save()
310+
```
311+
312+
### Database Operations
313+
```javascript
314+
// Always use the driver abstraction
315+
const db = new dbDriver("mongo")
316+
317+
// Find documents
318+
const projects = await db.find({ creator: userId }, "projects")
319+
320+
// Update document
321+
await db.update({ _id: id, ...updates }, "projects")
322+
```
323+
324+
### Testing Your Changes
325+
```javascript
326+
// Write a test for your feature
327+
describe('My Feature', () => {
328+
test('should do something', async () => {
329+
const response = await request(app)
330+
.post('/api/endpoint')
331+
.send({ data: 'test' })
332+
333+
expect(response.status).toBe(200)
334+
expect(response.body).toHaveProperty('result')
335+
})
336+
})
337+
```
338+
339+
## Important Notes
340+
341+
1. **RERUM Integration**: Annotation data is stored externally in RERUM. Always handle RERUM API failures gracefully.
342+
343+
2. **MongoDB Required**: While MariaDB support exists, MongoDB is the primary database and required for full functionality.
344+
345+
3. **IIIF Compliance**: All annotation responses follow IIIF Presentation API 3.0 and W3C Web Annotation standards.
346+
347+
4. **Async Everything**: All database operations and external API calls must use async/await.
348+
349+
5. **Token Expiry**: Always check JWT expiration before processing requests.
350+
351+
6. **Maintenance Mode**: Check `DOWN` environment variable for maintenance mode handling.
352+
353+
## Need Help?
354+
355+
- Check existing implementations in similar files
356+
- Review test files for usage examples
357+
- Look at utility functions in `/utilities` for common operations
358+
- Follow patterns established in the `/classes` directory

.claude/settings.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"statusLine": {
3+
"type": "command",
4+
"command": "bash /mnt/e/tpen3-services/.claude/statusline-command.sh"
5+
},
6+
"env": {
7+
"CLAUDE_CODE_MAX_OUTPUT_TOKENS": "500000",
8+
"CLAUDE_CODE_DISABLE_TERMINAL_TITLE": "1",
9+
"MAX_MCP_OUTPUT_TOKENS": "500000",
10+
"DISABLE_ERROR_REPORTING": "0",
11+
"DISABLE_NON_ESSENTIAL_MODEL_CALLS": "0",
12+
"DISABLE_PROMPT_CACHING": "0",
13+
"MAX_THINKING_TOKENS": "500000",
14+
"BASH_MAX_TIMEOUT_MS": "3000000",
15+
"OPENCODE_DISABLE_PRUNE": "true",
16+
"OPENCODE_DISABLE_AUTOCOMPACT": "true"
17+
}
18+
}

0 commit comments

Comments
 (0)