Skip to content

Commit bd900d9

Browse files
committed
Add agents file
1 parent 5d3c05c commit bd900d9

1 file changed

Lines changed: 252 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
# Agent Guide for Ackee
2+
3+
This document provides guidelines for AI coding agents working on the Ackee codebase.
4+
5+
## Project Overview
6+
7+
Ackee is a self-hosted Node.js analytics tool built with:
8+
9+
- **Backend**: Node.js (ESM modules), Express, Apollo Server (GraphQL), Mongoose (MongoDB)
10+
- **Frontend**: React (with createElement as `h`), Apollo Client, SCSS
11+
- **Build**: Custom build script (`build.js`), Rosid handlers
12+
- **Testing**: AVA test framework
13+
- **Code Quality**: ESLint + Prettier (via @electerious configs)
14+
15+
## Commands
16+
17+
### Build
18+
19+
```bash
20+
npm run build # Production build
21+
npm run build:pre # Development build (BUILD_ENV=pre)
22+
npm start # Build and start server
23+
```
24+
25+
### Development
26+
27+
```bash
28+
npm run dev # Start with nodemon (auto-rebuild + restart)
29+
npm run server # Start server without building
30+
```
31+
32+
### Testing
33+
34+
```bash
35+
npm test # Run lint + all tests
36+
npm run lint # ESLint + Prettier check only
37+
ava # Run all tests without linting
38+
ava test/path/to/file.js # Run a single test file
39+
ava test/**/*domains*.js # Run tests matching pattern
40+
ava --watch # Run in watch mode
41+
```
42+
43+
### Code Quality
44+
45+
```bash
46+
npm run eslint # Check JavaScript with ESLint
47+
npm run prettier -- --check # Check formatting
48+
npm run format # Auto-fix ESLint + Prettier issues
49+
```
50+
51+
### Health Check
52+
53+
```bash
54+
npm run healthcheck # Run health check script
55+
```
56+
57+
## Code Style Guidelines
58+
59+
### General Principles
60+
61+
- Use **ES modules** (`.js` files with `type: "module"` in package.json)
62+
- No TypeScript - pure JavaScript with JSDoc comments where needed
63+
- Functional programming style preferred
64+
- Keep code simple, readable, and minimal
65+
66+
### Imports
67+
68+
- Use `.js` extensions in all import paths
69+
- Group imports logically: external deps → internal modules → utils
70+
- Use named exports for utilities, default exports for main components/resolvers
71+
72+
```javascript
73+
import { randomUUID as uuid } from 'node:crypto'
74+
import Domain from '../models/Domain.js'
75+
import sortByProp from '../utils/sortByProp.js'
76+
```
77+
78+
### File Naming
79+
80+
- **Backend**: camelCase for files (e.g., `domains.js`, `requireAuth.js`)
81+
- **Frontend Components**: PascalCase (e.g., `Input.js`, `Dashboard.js`)
82+
- **Frontend Hooks**: camelCase with `use` prefix (e.g., `useDomains.js`)
83+
- **Constants**: camelCase files (e.g., `routes.js`, `intervals.js`)
84+
85+
### Formatting
86+
87+
- Uses Prettier via `@electerious/prettier-config`
88+
- Tabs for indentation (configured in Prettier)
89+
- Single quotes for strings
90+
- Trailing commas in multi-line structures
91+
- **Do not manually format** - run `npm run format` instead
92+
93+
### React Patterns
94+
95+
- Use `createElement as h` instead of JSX
96+
- Define PropTypes for all components
97+
- Use functional components with hooks
98+
- Custom hooks follow `use*` naming convention
99+
100+
```javascript
101+
import { createElement as h } from 'react'
102+
import PropTypes from 'prop-types'
103+
104+
const Component = (props) => {
105+
return h('div', { className: 'example' }, props.children)
106+
}
107+
108+
Component.propTypes = {
109+
children: PropTypes.node,
110+
}
111+
112+
export default Component
113+
```
114+
115+
### GraphQL Patterns
116+
117+
- Use `gql` template tag from `@apollo/client`
118+
- Define fragments in separate files
119+
- Mutations return `{ success, payload }` structure
120+
121+
```javascript
122+
const QUERY = gql`
123+
query fetchDomains {
124+
domains {
125+
...domainFields
126+
}
127+
}
128+
${domainFields}
129+
`
130+
```
131+
132+
### Error Handling
133+
134+
- Use `KnownError` class for user-facing errors
135+
- Catch and transform ValidationErrors from Mongoose
136+
- Always handle promise rejections
137+
- Use `signale` for logging (not `console.log`)
138+
139+
```javascript
140+
try {
141+
entry = await domains.add(input)
142+
} catch (error) {
143+
if (error.name === 'ValidationError') {
144+
throw new KnownError(messages(error.errors))
145+
}
146+
throw error
147+
}
148+
```
149+
150+
### Middleware Pattern
151+
152+
- Resolvers use `pipe()` utility to compose middleware
153+
- Common middleware: `requireAuth`, `blockDemoMode`
154+
155+
```javascript
156+
createDomain: pipe(requireAuth, blockDemoMode, async (parent, { input }) => {
157+
const entry = await domains.add(input)
158+
return { payload: entry, success: true }
159+
})
160+
```
161+
162+
### Database Patterns
163+
164+
- Export named functions for CRUD operations
165+
- Use `response()` transformer to shape data
166+
- Use `enhance()` pattern for consistent transformations
167+
168+
```javascript
169+
export const get = async (id) => {
170+
const enhance = (entry) => {
171+
return entry == null ? entry : response(entry)
172+
}
173+
return enhance(await Domain.findOne({ id }))
174+
}
175+
```
176+
177+
### Testing with AVA
178+
179+
- Use `test.serial()` for tests that depend on execution order
180+
- Import AVA as `test from 'ava'`
181+
- Use `test.before`, `test.after.always`, `test.beforeEach`, `test.afterEach.always`
182+
- Test context (`t.context`) stores shared state (e.g., tokens)
183+
- Organize tests in folders matching source structure
184+
185+
```javascript
186+
import test from 'ava'
187+
import { api, cleanup, fillDatabase, gql } from './_utils.js'
188+
189+
test.beforeEach(fillDatabase)
190+
test.afterEach.always(cleanupDatabase)
191+
192+
test.serial('create domain', async (t) => {
193+
const { json } = await api(base, body, t.context.token.id)
194+
t.true(json.data.createDomain.success)
195+
t.is(json.data.createDomain.payload.title, expectedTitle)
196+
})
197+
```
198+
199+
## ESLint Rules
200+
201+
Base config: `@electerious/eslint-config`
202+
203+
Disabled rules for this project:
204+
205+
- `import-x/dynamic-import-chunkname`
206+
- `unicorn/filename-case`
207+
- `unicorn/consistent-function-scoping`
208+
- `unicorn/no-await-expression-member`
209+
- `unicorn/no-anonymous-default-export`
210+
- `unicorn/prefer-top-level-await`
211+
- `unicorn/no-thenable`
212+
- `unicorn/no-process-exit`
213+
214+
## Project Structure
215+
216+
```
217+
src/
218+
├── aggregations/ # Data aggregation functions
219+
├── constants/ # Shared constants and enums
220+
├── database/ # Database CRUD operations
221+
├── middlewares/ # GraphQL middleware (auth, demo mode)
222+
├── models/ # Mongoose models
223+
├── resolvers/ # GraphQL resolvers
224+
├── stages/ # Pipeline stages
225+
├── types/ # GraphQL type definitions
226+
├── ui/ # React frontend
227+
│ ├── scripts/ # React components, hooks, utils
228+
│ └── styles/ # SCSS stylesheets
229+
└── utils/ # Utility functions
230+
231+
test/
232+
├── aggregations/ # Aggregation tests
233+
├── constants/ # Constants tests
234+
├── resolvers/ # Resolver tests
235+
└── utils/ # Utility tests
236+
```
237+
238+
## Important Notes
239+
240+
- **Node.js version**: Requires Node.js >= 24
241+
- **Environment variables**: Uses `.env` files (see `.env` for local config)
242+
- **MongoDB**: Required for development and testing (uses mongodb-memory-server for tests)
243+
- **Development mode**: Set `NODE_ENV=development` for GraphQL Playground access
244+
- **Demo mode**: Set `ACKEE_DEMO=true` to enable demo mode (blocks mutations)
245+
- **Contributing**: Always work on `develop` branch, discuss changes in issues first
246+
247+
## References
248+
249+
- [Documentation](docs/)
250+
- [API Documentation](docs/API.md)
251+
- [Contributing Guide](CONTRIBUTING.md)
252+
- [Changelog](CHANGELOG.md)

0 commit comments

Comments
 (0)