Skip to content

Commit 6b55881

Browse files
authored
Merge pull request #302 from spseol/feat-agents
docs(agents): AGENTS.md
2 parents b9fc643 + 124cee6 commit 6b55881

1 file changed

Lines changed: 287 additions & 0 deletions

File tree

AGENTS.md

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
# AGENTS.md — project-thesaurus
2+
3+
> Instructions for agentic coding agents operating in this repository.
4+
5+
---
6+
7+
## Project Overview
8+
9+
**project-thesaurus** is a university thesis management system with a dual-stack architecture:
10+
11+
| Layer | Location | Stack |
12+
|-----------|-------------|-------------------------------------------------|
13+
| Backend | `django/` | Python 3.9, Django 3.2, Django REST Framework 3.15 |
14+
| Frontend | `webpack/` | TypeScript 4.4, Vue 2.7, Vuetify 2, Webpack 4 |
15+
| Database || PostgreSQL |
16+
| Proxy | `nginx/` | Nginx |
17+
18+
The full dev environment runs via Docker Compose. The Django backend serves a REST API; the Vue SPA is served by the webpack-dev-server in development.
19+
20+
---
21+
22+
## Build & Dev Commands
23+
24+
### Frontend (`webpack/`)
25+
26+
```bash
27+
# Install dependencies
28+
cd webpack && npm install
29+
30+
# Development server (hot-reload, port 3000)
31+
cd webpack && npm run dev
32+
33+
# Production build
34+
cd webpack && npm run build
35+
36+
# Check for missing/unused i18n keys
37+
cd webpack && npm run extract-locale
38+
39+
# Merge translation keys exported from Django into the frontend locale JSON files
40+
cd webpack && npm run merge-locale
41+
```
42+
43+
### Backend (`django/`)
44+
45+
```bash
46+
# Run development server (inside Docker or with Pipenv shell active)
47+
cd django && python manage.py runserver
48+
49+
# Apply migrations
50+
cd django && python manage.py migrate
51+
52+
# Create a superuser
53+
cd django && python manage.py createsuperuser
54+
55+
# Install Python dependencies (Pipenv)
56+
cd django && pipenv install --dev
57+
```
58+
59+
### Docker Compose (recommended for full-stack dev)
60+
61+
```bash
62+
# Start everything (Django + webpack-dev-server + nginx)
63+
docker-compose -f docker-compose.base.yml -f docker-compose.dev.yml up
64+
65+
# Production stack
66+
docker-compose -f docker-compose.base.yml -f docker-compose.prod.yml up
67+
68+
# Build and release a Django image
69+
make release-django TAG=x.y.z
70+
```
71+
72+
### Tests & Linting
73+
74+
**⚠️ This project currently has no automated tests and no linter configuration.**
75+
76+
- No `pytest` / `jest` / `vitest` setup exists — do not attempt to run tests.
77+
- No `eslint`, `prettier`, `ruff`, or `mypy` configs exist — do not attempt to run linters.
78+
- When writing new code, follow the manual style conventions documented below.
79+
- If you add tests or linting infrastructure, document the commands here.
80+
81+
---
82+
83+
## Git Workflow
84+
85+
- **Never commit directly to `master` or `develop`.**
86+
- `master` — production branch.
87+
- `develop` — integration branch (target for PRs).
88+
- Feature branches: `feature/<short-name>` (e.g. `feature/audit-log`).
89+
- Fix branches: `fix/<short-name>` (e.g. `fix/thesis-reservable-flag`).
90+
91+
### Commit messages
92+
93+
Single-line only. Format: `type(scope): description`
94+
95+
```
96+
feat(thesis): add PDF export endpoint
97+
fix(review): correct overlapping layout in detail panel
98+
chore(django): bump Python and Django versions
99+
refactor(thesis): simplify reservation state transition logic
100+
```
101+
102+
- **Types:** `feat`, `fix`, `chore`, `refactor`, `docs`, `test`
103+
- **Scopes:** match Django app names — `thesis`, `review`, `accounts`, `api`, `audit`, `attachment`, `emails`, `frontend`, `django`, `js`, `utils`
104+
- **Note:** reservation logic lives inside `apps/thesis/` — use scope `thesis` for reservation-related commits
105+
- **Description:** imperative mood, lowercase, no trailing period
106+
- No body or footer lines
107+
108+
---
109+
110+
## Python / Django Code Style
111+
112+
### Import ordering
113+
114+
```python
115+
# 1. Standard library
116+
from typing import Optional, Tuple
117+
118+
# 2. Django
119+
from django.contrib.auth import get_user_model
120+
from django.db import models
121+
122+
# 3. Third-party
123+
from rest_framework.exceptions import ValidationError
124+
from rest_framework.viewsets import ModelViewSet
125+
126+
# 4. Local apps (absolute, from apps.*)
127+
from apps.accounts.models import User
128+
from apps.api.permissions import CanSubmitThesisPermission
129+
```
130+
131+
Imports are grouped with a single blank line between groups. The ordering and grouping above must be maintained; do not collapse or reorder groups.
132+
133+
### Naming conventions
134+
135+
| Construct | Convention | Example |
136+
|----------------------|-------------------------|----------------------------------|
137+
| Variables / functions | `snake_case` | `get_available_theses` |
138+
| Classes | `PascalCase` | `ThesisViewSet` |
139+
| Constants | `SCREAMING_SNAKE_CASE` | `STATE_HELP_TEXTS` |
140+
| Django apps | lowercase, no hyphens | `apps/thesis/`, `apps/review/` |
141+
| URL names | `kebab-case` strings | `thesis-list`, `review-detail` |
142+
143+
### Models
144+
145+
- Inherit from `BaseTimestampedModel` (provides UUID primary key, `created`, `modified` fields, and `django-lifecycle` hooks). Defined in `apps/utils/models/base.py`.
146+
- `related_name` follows the pattern `{model}_{field}` — e.g. `related_name='thesis_supervisor'`.
147+
- Split large model files into a `models/` package; re-export from `models/__init__.py`.
148+
- Nested classes: `class Meta`, `class State(models.TextChoices)`.
149+
- Custom managers are named descriptively: `objects`, `api_objects`, `import_objects`.
150+
151+
### Error handling
152+
153+
```python
154+
# Standard DRF pattern — let the framework handle the response
155+
serializer.is_valid(raise_exception=True)
156+
157+
# Business rule violations
158+
from rest_framework.exceptions import ValidationError
159+
raise ValidationError('Thesis is already reserved.')
160+
161+
# The custom exception handler shapes all error responses:
162+
# apps.api.utils.exceptions.exception_handler
163+
```
164+
165+
- Don't use `try/except` in views solely to shape HTTP responses; let DRF and the custom exception handler handle error responses.
166+
- Prefer `raise_exception=True` and DRF exceptions for validation/business-rule errors; avoid hand-crafting 400 responses unless a view has a specific, documented reason.
167+
168+
### Type annotations
169+
170+
- Add type hints to function signatures; return types where non-obvious.
171+
- Use string forward references for models not yet defined: `def foo(self: 'ThesisViewSet')`.
172+
- Inline `# type: QuerySet` comments are acceptable for local variables.
173+
- `from __future__ import annotations` is not currently used — keep it that way.
174+
175+
---
176+
177+
## TypeScript / Vue Code Style
178+
179+
### Import ordering
180+
181+
```ts
182+
// 1. Third-party packages (alphabetical)
183+
import * as Sentry from '@sentry/browser';
184+
import Vue from 'vue';
185+
186+
// 2. Side-effect imports
187+
import '../scss/index.scss';
188+
189+
// 3. Local source files
190+
import App from './App.vue';
191+
import { DjangoPermsPlugin, I18nRoutePlugin } from './plugins';
192+
```
193+
194+
Imports run together without blank lines between groups — do not add separators.
195+
196+
### Naming conventions
197+
198+
| Construct | Convention | Example |
199+
|-------------------------|-------------------------|---------------------------------|
200+
| Variables / functions | `camelCase` | `loadThesisList` |
201+
| Classes / components | `PascalCase` | `ThesisDetailPanel` |
202+
| Enums | `SCREAMING_SNAKE_CASE` | `THESIS_ACTIONS`, `PERMS` |
203+
| Enum values | Descriptive strings | `LOAD_THESES = 'Load theses'` |
204+
| Vue files | `PascalCase.vue` | `ThesisDetail.vue` |
205+
| TS utility files | `camelCase.ts` | `axios.ts`, `router.ts` |
206+
207+
### Vue component structure
208+
209+
- Use **Options API** with `Vue.extend({})`. Do not use `defineComponent` or class-based components.
210+
- Script tag: `<script type="text/tsx">` (not `<script lang="ts">`).
211+
- File order: `<template>``<script>``<style scoped>`.
212+
- Page-level components live in their own subdirectory with a thin `Page.vue` wrapper:
213+
```
214+
pages/ThesisList/Page.vue ← route target, thin wrapper
215+
pages/ThesisList/ThesisList.vue ← feature component with logic
216+
```
217+
218+
### Vuex store modules
219+
220+
```ts
221+
export enum MODULE_MUTATIONS { SET_DATA = 'Set data' }
222+
export enum MODULE_ACTIONS { LOAD_DATA = 'Load data' }
223+
224+
const state = { data: null as Data | null };
225+
type State = typeof state;
226+
227+
export default {
228+
namespaced: true,
229+
state,
230+
mutations: { [MODULE_MUTATIONS.SET_DATA](state: State, payload: Data) { ... } },
231+
actions: { async [MODULE_ACTIONS.LOAD_DATA]({ commit }) { ... } },
232+
getters: { ... },
233+
};
234+
```
235+
236+
- All modules are namespaced.
237+
- Use `Vue.set` / `Vue.delete` for reactive object mutations.
238+
239+
### TypeScript strictness
240+
241+
- `strict: false` in `tsconfig.json` — implicit `any` is tolerated for existing code.
242+
- Add explicit types to new public class properties and function signatures.
243+
- Domain types are declared as `declare class X extends Object {}` in `webpack/src/js/types.d.ts`.
244+
245+
### Error handling
246+
247+
- All HTTP errors are handled centrally in `webpack/src/js/axios.ts` interceptors:
248+
- `401` → force page reload (re-auth)
249+
- `403` → treated as a **success** by default `validateStatus` (resolves, never reaches the error interceptor); only callers that override `validateStatus` to treat 403 as an error will trigger a toast warning (suppress with `config.allow403 = true`, in which case the error interceptor **handles and swallows** the 403 instead of propagating it)
250+
- `5xx` → flash error banner
251+
- Use optional chaining (`?.`) throughout; never assume response shape.
252+
- Error interceptors must `return Promise.reject(error)` to propagate errors to callers, **except** in explicitly documented cases where an error is intentionally handled and swallowed (e.g. `403` with `config.allow403 = true`).
253+
- Validation errors (`400`) are treated as successful responses and handled per-form.
254+
255+
---
256+
257+
## Directory Reference
258+
259+
```
260+
django/
261+
apps/ # Django applications (one per domain)
262+
utils/ # Shared utilities: BaseTimestampedModel and helpers
263+
thesaurus/ # Django project config (settings, urls, wsgi/asgi)
264+
templates/ # Django HTML templates
265+
locale/ # .po/.mo translation files
266+
fixtures/ # Initial data
267+
Pipfile # Python dependencies
268+
269+
webpack/
270+
src/js/
271+
app.ts # Vue app factory / bootstrap
272+
axios.ts # Configured Axios instance + interceptors
273+
router.ts # Vue Router with guards
274+
plugins.ts # Vue plugins (DjangoPermsPlugin, I18nRoutePlugin)
275+
utils.ts # Shared utilities: notificationBus, pageContext
276+
user.ts # Permission helpers: hasPerm, hasGroup
277+
cache.ts # localforage-backed request cache helpers
278+
types.d.ts # Global TypeScript type declarations
279+
vue-shim.d.ts # Module declaration shim for .vue files
280+
store/ # Vuex modules (one file per domain)
281+
pages/ # Page-level Vue components
282+
components/ # Shared reusable components
283+
locale/ # i18n JSON files (cs.json, en.json)
284+
src/scss/ # Global SCSS
285+
tsconfig.json
286+
webpack.*.config.js
287+
```

0 commit comments

Comments
 (0)