odac 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent/rules/memory.md +7 -1
- package/.github/workflows/release.yml +0 -4
- package/AGENTS.md +47 -0
- package/CHANGELOG.md +32 -0
- package/README.md +1 -1
- package/bin/odac.js +169 -6
- package/client/odac.js +15 -11
- package/docs/ai/README.md +49 -0
- package/docs/ai/skills/SKILL.md +39 -0
- package/docs/ai/skills/backend/authentication.md +67 -0
- package/docs/ai/skills/backend/config.md +32 -0
- package/docs/ai/skills/backend/controllers.md +62 -0
- package/docs/ai/skills/backend/cron.md +50 -0
- package/docs/ai/skills/backend/database.md +21 -0
- package/docs/ai/skills/backend/forms.md +19 -0
- package/docs/ai/skills/backend/ipc.md +55 -0
- package/docs/ai/skills/backend/mail.md +34 -0
- package/docs/ai/skills/backend/request_response.md +35 -0
- package/docs/ai/skills/backend/routing.md +51 -0
- package/docs/ai/skills/backend/storage.md +43 -0
- package/docs/ai/skills/backend/streaming.md +34 -0
- package/docs/ai/skills/backend/structure.md +57 -0
- package/docs/ai/skills/backend/translations.md +42 -0
- package/docs/ai/skills/backend/utilities.md +24 -0
- package/docs/ai/skills/backend/validation.md +53 -0
- package/docs/ai/skills/backend/views.md +61 -0
- package/docs/ai/skills/frontend/core.md +66 -0
- package/docs/ai/skills/frontend/forms.md +21 -0
- package/docs/ai/skills/frontend/navigation.md +20 -0
- package/docs/ai/skills/frontend/realtime.md +47 -0
- package/docs/backend/10-authentication/01-user-logins-with-authjs.md +2 -0
- package/docs/backend/10-authentication/05-session-management.md +25 -3
- package/package.json +1 -1
- package/src/Auth.js +100 -15
- package/src/Route/Internal.js +21 -18
- package/src/Route/MimeTypes.js +56 -0
- package/src/Route.js +40 -63
- package/src/View/Form.js +91 -51
- package/src/View.js +8 -3
- package/test/Auth.test.js +249 -0
- package/test/Client.test.js +29 -0
- package/test/View/Form.test.js +37 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Backend Cron Jobs Skill
|
|
2
|
+
|
|
3
|
+
ODAC provides a built-in cron system for automating background tasks without external dependencies.
|
|
4
|
+
|
|
5
|
+
## Architectural Approach
|
|
6
|
+
Cron jobs are defined in routes and executed by the internal scheduler. They can use either external controller files (recommended) or inline functions.
|
|
7
|
+
|
|
8
|
+
## Core Rules
|
|
9
|
+
1. **Definition**: Use `Odac.Route.cron('name')` to start a definition.
|
|
10
|
+
2. **Scheduling**: Use fluent methods like `.everyMinute(n)`, `.at('HH:MM')`, `.day(n)`, etc.
|
|
11
|
+
3. **Controllers**: Cron controllers should be in `controller/cron/`. They receive the `Odac` instance.
|
|
12
|
+
4. **Wildcard Warning**: If you specify an hour but no minute, it will run every minute during that hour. Always use `.at()` or specify the minute.
|
|
13
|
+
|
|
14
|
+
## Reference Patterns
|
|
15
|
+
|
|
16
|
+
### 1. File-Based Cron (Recommended)
|
|
17
|
+
```javascript
|
|
18
|
+
// route/cron.js
|
|
19
|
+
Odac.Route.cron('cleanup').at('03:00'); // Runs daily at 03:00
|
|
20
|
+
|
|
21
|
+
// controller/cron/cleanup.js
|
|
22
|
+
module.exports = async (Odac) => {
|
|
23
|
+
console.log('Running nightly cleanup...');
|
|
24
|
+
await Odac.Db.table('logs').where('created_at', '<', 'NOW() - INTERVAL 30 DAY').delete();
|
|
25
|
+
};
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 2. Inline Function Cron
|
|
29
|
+
```javascript
|
|
30
|
+
Odac.Route.cron(async () => {
|
|
31
|
+
const stats = await Odac.Db.table('orders').count();
|
|
32
|
+
console.log('Current orders:', stats);
|
|
33
|
+
}).everyHour(1);
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### 3. Raw Unix Cron Patterns
|
|
37
|
+
```javascript
|
|
38
|
+
// Run every 15 minutes
|
|
39
|
+
Odac.Route.cron('sync').raw('*/15 * * * *');
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Available Schedulers
|
|
43
|
+
- `.minute(0-59)`, `.hour(0-23)`, `.day(1-31)`, `.month(1-12)`, `.weekDay(0-6)`.
|
|
44
|
+
- `.everyMinute(n)`, `.everyHour(n)`, `.everyDay(n)`.
|
|
45
|
+
- `.at('HH:MM')`: Shorthand for setting specific hour and minute.
|
|
46
|
+
|
|
47
|
+
## Best Practices
|
|
48
|
+
- **Logging**: Always log the start and completion of background tasks to the console or a file.
|
|
49
|
+
- **Timeouts**: Be aware that long-running tasks might overlap if the interval is too short.
|
|
50
|
+
- **Service Injection**: Use Service Classes inside cron jobs to keep the logic clean.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Backend Database Skill
|
|
2
|
+
|
|
3
|
+
High-performance database operations using the ODAC Query Builder.
|
|
4
|
+
|
|
5
|
+
## Principles
|
|
6
|
+
1. **Directness**: Avoid ORM overhead. Use fluent Query Builder.
|
|
7
|
+
2. **Safety**: Always use parameterized queries (built-in).
|
|
8
|
+
3. **Efficiency**: Index foreign keys. No `SELECT *`.
|
|
9
|
+
|
|
10
|
+
## Patterns
|
|
11
|
+
```javascript
|
|
12
|
+
const user = await Odac.Db.table('users')
|
|
13
|
+
.select('id', 'name', 'email')
|
|
14
|
+
.where('status', 'active')
|
|
15
|
+
.first();
|
|
16
|
+
|
|
17
|
+
await Odac.Db.table('posts').insert({
|
|
18
|
+
title: 'Hello',
|
|
19
|
+
user_id: 1
|
|
20
|
+
});
|
|
21
|
+
```
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Backend Forms & Validation Skill
|
|
2
|
+
|
|
3
|
+
Processing form data securely and validating inputs.
|
|
4
|
+
|
|
5
|
+
## Rules
|
|
6
|
+
1. **Validator**: Always use `Odac.Validator` for input.
|
|
7
|
+
2. **Auto-save**: Use `Odac.Db.table().save(Odac.Request.post())` for quick inserts.
|
|
8
|
+
3. **CSRF**: Ensure `{{ TOKEN }}` is in your HTML forms.
|
|
9
|
+
|
|
10
|
+
## Patterns
|
|
11
|
+
```javascript
|
|
12
|
+
// Validation
|
|
13
|
+
const check = Odac.Validator.run(Odac.Request.post(), {
|
|
14
|
+
email: 'required|email',
|
|
15
|
+
password: 'required|min:8'
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
if (check.failed()) return Odac.Request.error(check.errors());
|
|
19
|
+
```
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Backend IPC (Inter-Process Communication) Skill
|
|
2
|
+
|
|
3
|
+
ODAC provides a built-in IPC system to share data and sync states across application workers or multiple servers.
|
|
4
|
+
|
|
5
|
+
## Architectural Approach
|
|
6
|
+
IPC abstracts the underlying driver, allowing seamless transition between `memory` (Node.js cluster) and `redis` (multi-server scaling).
|
|
7
|
+
|
|
8
|
+
## Core Rules
|
|
9
|
+
1. **Drivers**:
|
|
10
|
+
- `memory`: Shared across local workers via Main process (Default).
|
|
11
|
+
- `redis`: Shared across multiple servers/clusters.
|
|
12
|
+
2. **State Sharing**: Use `Odac.Ipc` for global key-value storage.
|
|
13
|
+
3. **Messaging**: Use Pub/Sub for worker-to-worker communication.
|
|
14
|
+
|
|
15
|
+
## Reference Patterns
|
|
16
|
+
|
|
17
|
+
### 1. Key-Value Storage
|
|
18
|
+
```javascript
|
|
19
|
+
// Set value with optional TTL (seconds)
|
|
20
|
+
await Odac.Ipc.set('maintenance_mode', true);
|
|
21
|
+
await Odac.Ipc.set('cache_key', { data: 123 }, 60);
|
|
22
|
+
|
|
23
|
+
// Get value
|
|
24
|
+
const status = await Odac.Ipc.get('maintenance_mode');
|
|
25
|
+
|
|
26
|
+
// Delete value
|
|
27
|
+
await Odac.Ipc.del('maintenance_mode');
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 2. Pub/Sub Messaging
|
|
31
|
+
```javascript
|
|
32
|
+
// Subscribe to a channel (usually in a service or app start)
|
|
33
|
+
await Odac.Ipc.subscribe('notifications', (msg) => {
|
|
34
|
+
console.log('Received:', msg);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
// Publish a message from any worker
|
|
38
|
+
await Odac.Ipc.publish('notifications', { type: 'alert', text: 'System update' });
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Configuration
|
|
42
|
+
In `odac.json` or a config provider:
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"ipc": {
|
|
46
|
+
"driver": "redis",
|
|
47
|
+
"redis": "default"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Best Practices
|
|
53
|
+
- **Async First**: All IPC operations are asynchronous.
|
|
54
|
+
- **TTL Usage**: Always set a TTL for temporary cache data to prevent memory bloat.
|
|
55
|
+
- **Scaling**: Switch to `redis` driver when deploying across multiple containers or servers.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Backend Mail Skill
|
|
2
|
+
|
|
3
|
+
Sending transactional emails using the fluent `Odac.Mail` service.
|
|
4
|
+
|
|
5
|
+
## Core Rules
|
|
6
|
+
1. **Transport**: Configured via `odac.json` (SMTP, etc.).
|
|
7
|
+
2. **Templating**: Combine with `Odac.Var().replace()` for dynamic content.
|
|
8
|
+
3. **Methods**: Use `Odac.Mail.send({ ... })`.
|
|
9
|
+
|
|
10
|
+
## Reference Patterns
|
|
11
|
+
### 1. Simple Email
|
|
12
|
+
```javascript
|
|
13
|
+
await Odac.Mail.send({
|
|
14
|
+
to: 'user@example.com',
|
|
15
|
+
subject: 'Welcome!',
|
|
16
|
+
body: '<h1>Hello!</h1>',
|
|
17
|
+
type: 'html' // default is text
|
|
18
|
+
});
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### 2. Template-based Email
|
|
22
|
+
```javascript
|
|
23
|
+
const template = 'Hello {{ name }}, welcome to {{ site }}!';
|
|
24
|
+
const body = Odac.Var(template).replace({
|
|
25
|
+
'{{ name }}': user.name,
|
|
26
|
+
'{{ site }}': 'ODAC'
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
await Odac.Mail.send({
|
|
30
|
+
to: user.email,
|
|
31
|
+
subject: 'Registration Success',
|
|
32
|
+
body: body
|
|
33
|
+
});
|
|
34
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Backend Request & Response Skill
|
|
2
|
+
|
|
3
|
+
Handling incoming data and sending structured responses.
|
|
4
|
+
|
|
5
|
+
## Core Rules
|
|
6
|
+
1. **Request Data**:
|
|
7
|
+
- `Odac.request('key')`: Auto-detect GET/POST (Recommended).
|
|
8
|
+
- `Odac.Request.post('key')`: Targeted POST data.
|
|
9
|
+
- `Odac.Request.get('key')`: Targeted URL parameters.
|
|
10
|
+
2. **Metadata**: Access `Odac.Request.method`, `Odac.Request.ip`, `Odac.Request.header('name')`.
|
|
11
|
+
3. **Returning Data**:
|
|
12
|
+
- `return { ... }`: Returns JSON.
|
|
13
|
+
- `return Odac.return({ ... })`: Explicit JSON return.
|
|
14
|
+
- `Odac.Response.header('Key', 'Value')`: Set custom headers.
|
|
15
|
+
|
|
16
|
+
## Reference Patterns
|
|
17
|
+
### 1. Unified Request Handling
|
|
18
|
+
```javascript
|
|
19
|
+
module.exports = async function(Odac) {
|
|
20
|
+
const name = await Odac.request('name');
|
|
21
|
+
const method = Odac.Request.method;
|
|
22
|
+
|
|
23
|
+
if (method === 'POST') {
|
|
24
|
+
return { success: true, message: `Saved ${name}` };
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Header and Status Management
|
|
30
|
+
```javascript
|
|
31
|
+
module.exports = function(Odac) {
|
|
32
|
+
Odac.Response.header('Content-Type', 'text/plain');
|
|
33
|
+
return "Raw text response";
|
|
34
|
+
};
|
|
35
|
+
```
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Backend Routing & Middleware Skill
|
|
2
|
+
|
|
3
|
+
Routing manages the request pipeline, directing URLs to controllers while applying security and business logic via middlewares.
|
|
4
|
+
|
|
5
|
+
## Architectural Approach
|
|
6
|
+
Routes are defined in the `route/` directory. ODAC uses a two-phase routing strategy: O(1) exact matches followed by an indexed segment-based parametric lookup for maximum performance.
|
|
7
|
+
|
|
8
|
+
## Core Rules
|
|
9
|
+
1. **Methods**:
|
|
10
|
+
- `Odac.Route.page(url, controller)`: For HTML views (GET).
|
|
11
|
+
- `Odac.Route.get(url, controller)`: Targeted GET requests.
|
|
12
|
+
- `Odac.Route.post(url, controller)`: Sensitive POST requests (CSRF enabled by default).
|
|
13
|
+
2. **Parameters**: Use `{id}` syntax for dynamic segments. Accessed via `Odac.request('id')`.
|
|
14
|
+
3. **Middlewares**: Chain logic using `.use('name')`. Global middlewares reside in `middleware/`.
|
|
15
|
+
4. **Error Handling**: Use `Odac.Route.error(code, controller)` for custom 404/500 pages.
|
|
16
|
+
5. **Auth Guard**: `Odac.Route.auth` automatically checks authentication before running the route.
|
|
17
|
+
|
|
18
|
+
## Reference Patterns
|
|
19
|
+
|
|
20
|
+
### 1. Standard Web Routes
|
|
21
|
+
```javascript
|
|
22
|
+
// page(path, controller)
|
|
23
|
+
Odac.Route.page('/', 'Home');
|
|
24
|
+
Odac.Route.page('/profile/{username}', 'User@profile');
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### 2. Protected Routes & Middlewares
|
|
28
|
+
```javascript
|
|
29
|
+
// Only authenticated admins can see stats
|
|
30
|
+
Odac.Route.auth
|
|
31
|
+
.use('is_admin')
|
|
32
|
+
.page('/admin/stats', 'Admin@stats');
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 3. Error Pages mapping
|
|
36
|
+
```javascript
|
|
37
|
+
Odac.Route.error(404, 'errors/NotFound');
|
|
38
|
+
Odac.Route.error(500, 'errors/ServerError');
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 4. API Routes
|
|
42
|
+
```javascript
|
|
43
|
+
// Disable CSRF token check for external APIs
|
|
44
|
+
Odac.Route.post('/api/webhook', 'Api@webhook', { token: false });
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Best Practices
|
|
48
|
+
- **Method Specification**: Use `.page()` for views to enable AJAX navigation compatibility.
|
|
49
|
+
- **Static First**: Prefer exact URL matches over parametric ones where possible (faster).
|
|
50
|
+
- **Controller Isolation**: Place error controllers in `controller/errors/` for better organization.
|
|
51
|
+
- **Parametric Safety**: Do not use too many nested dynamic segments in a single route.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Backend Persistent Storage Skill
|
|
2
|
+
|
|
3
|
+
ODAC provides a high-performance, embedded key-value store using LMDB, exposed via `Odac.Storage`.
|
|
4
|
+
|
|
5
|
+
## Architectural Approach
|
|
6
|
+
Storage is ideal for persistent data that requires sub-millisecond access and does not need the complexity of a relational database. It is shared across all processes and workers.
|
|
7
|
+
|
|
8
|
+
## Core Rules
|
|
9
|
+
1. **Usage**: Access via `Odac.Storage`.
|
|
10
|
+
2. **Atomicity**: LMDB is ACID compliant and thread-safe.
|
|
11
|
+
3. **Data Types**: Supports strings, numbers, and JSON objects natively.
|
|
12
|
+
4. **Automatic Initialization**: The primary storage is initialized in the `storage/` directory automatically.
|
|
13
|
+
|
|
14
|
+
## Reference Patterns
|
|
15
|
+
|
|
16
|
+
### 1. Basic KV Operations
|
|
17
|
+
```javascript
|
|
18
|
+
// Setting data
|
|
19
|
+
Odac.Storage.put('setting_theme', 'dark');
|
|
20
|
+
Odac.Storage.put('app_data', { version: '1.0.0', last_check: Date.now() });
|
|
21
|
+
|
|
22
|
+
// Getting data
|
|
23
|
+
const theme = Odac.Storage.get('setting_theme');
|
|
24
|
+
const appData = Odac.Storage.get('app_data');
|
|
25
|
+
|
|
26
|
+
// Removing data
|
|
27
|
+
Odac.Storage.remove('setting_theme');
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 2. Range Queries
|
|
31
|
+
```javascript
|
|
32
|
+
// Get all keys starting with 'pref:'
|
|
33
|
+
const preferences = Odac.Storage.getRange({ start: 'pref:', end: 'pref:~' });
|
|
34
|
+
for (const { key, value } of preferences) {
|
|
35
|
+
console.log(key, value);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Best Practices
|
|
40
|
+
- **Keyspacing**: Use prefixes like `sess:`, `cache:`, or `pref:` to organize your keys.
|
|
41
|
+
- **Performance**: Since it's memory-mapped, random reads are extremely fast (O(1)).
|
|
42
|
+
- **No Migrations**: Unlike SQL, Storage is schemaless. Ensure your code handles version changes in the stored JSON objects.
|
|
43
|
+
- **Avoid Large Blobs**: While it can store large values, keep them reasonable to maintain OS-level cache efficiency.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Backend Streaming API Skill
|
|
2
|
+
|
|
3
|
+
Real-time data streaming using Server-Sent Events (SSE).
|
|
4
|
+
|
|
5
|
+
## Core Rules
|
|
6
|
+
1. **Usage**: Use `Odac.stream(callback)` to keep the connection open.
|
|
7
|
+
2. **Safety**: Always use `Odac.setInterval` and `Odac.setTimeout` inside streams; they are automatically cleaned up on disconnect.
|
|
8
|
+
3. **Return**: You must `return Odac.stream(...)` from the controller.
|
|
9
|
+
|
|
10
|
+
## Reference Patterns
|
|
11
|
+
### 1. Simple Stream
|
|
12
|
+
```javascript
|
|
13
|
+
module.exports = async (Odac) => {
|
|
14
|
+
return Odac.stream((send) => {
|
|
15
|
+
send({ status: 'connected' });
|
|
16
|
+
|
|
17
|
+
Odac.setInterval(() => {
|
|
18
|
+
send({ time: Date.now() });
|
|
19
|
+
}, 1000);
|
|
20
|
+
});
|
|
21
|
+
};
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### 2. Async Generator Stream
|
|
25
|
+
```javascript
|
|
26
|
+
module.exports = async (Odac) => {
|
|
27
|
+
return Odac.stream(async function* () {
|
|
28
|
+
const logs = await getLogStream();
|
|
29
|
+
for await (const log of logs) {
|
|
30
|
+
yield log;
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
```
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Backend Structure & Services Skill
|
|
2
|
+
|
|
3
|
+
ODAC follows a strictly organized directory structure and focuses on request-scoped architecture. This skill explains how to organize code and use Service Classes.
|
|
4
|
+
|
|
5
|
+
## Architectural Approach
|
|
6
|
+
ODAC uses a request-scoped container. Most logic should be encapsulated in Service Classes (`class/`) which are automatically instantiated and attached to the `Odac` instance for every request.
|
|
7
|
+
|
|
8
|
+
## Core Rules
|
|
9
|
+
1. **Directory Mapping**:
|
|
10
|
+
- `route/`: URL definitions using `Odac.Route`.
|
|
11
|
+
- `controller/`: Request handling logic (Input -> Response).
|
|
12
|
+
- `class/`: Reusable business logic (Service Classes).
|
|
13
|
+
- `view/`: HTML/Template files.
|
|
14
|
+
- `middleware/`: Request interceptors.
|
|
15
|
+
- `locale/`: Translation JSON files.
|
|
16
|
+
2. **Service Classes**:
|
|
17
|
+
- Place classes in the `class/` directory.
|
|
18
|
+
- They are automatically instantiated and attached to `Odac` as `Odac.ClassName`.
|
|
19
|
+
- They are **Request Scoped** (new instance per request).
|
|
20
|
+
3. **Dependency Injection**: Services receive the framework instance (`Odac`) in their constructor.
|
|
21
|
+
|
|
22
|
+
## Reference Patterns
|
|
23
|
+
|
|
24
|
+
### 1. Defining a Service Class (Recommended)
|
|
25
|
+
```javascript
|
|
26
|
+
// class/User.js
|
|
27
|
+
class User {
|
|
28
|
+
constructor(Odac) {
|
|
29
|
+
this.Odac = Odac;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async getProfile(id) {
|
|
33
|
+
// Access database or auth via this.Odac
|
|
34
|
+
return await this.Odac.Db.table('users').where('id', id).first();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
module.exports = User;
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 2. Using a Service in a Controller
|
|
41
|
+
```javascript
|
|
42
|
+
// controller/User.js
|
|
43
|
+
class User {
|
|
44
|
+
async show(Odac) {
|
|
45
|
+
// Service is automatically available as Odac.User
|
|
46
|
+
const profile = await Odac.User.getProfile(Odac.Request.input('id'));
|
|
47
|
+
|
|
48
|
+
return Odac.View.make('user.profile', { profile });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
module.exports = User;
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Best Practices
|
|
55
|
+
- **Context Awareness**: Use `this.Odac` inside service classes to access the specific request's state (current user, session, etc.).
|
|
56
|
+
- **Naming**: If a class name conflicts with core services (like `Mail`), it is placed under `Odac.App` (e.g., `Odac.App.Mail`).
|
|
57
|
+
- **Separation**: Keep controllers focused on request/response; move all data processing and business logic to the `class/` directory.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Backend Translations (i18n) Skill
|
|
2
|
+
|
|
3
|
+
ODAC provides built-in support for internationalization, allowing for easy multi-language application development.
|
|
4
|
+
|
|
5
|
+
## Architectural Approach
|
|
6
|
+
Translations are managed via JSON files in the `locale/` directory. The framework uses a flexible key-based system with support for placeholders.
|
|
7
|
+
|
|
8
|
+
## Core Rules
|
|
9
|
+
1. **Storage**: Place translation files in `locale/` (e.g., `en.json`, `tr.json`).
|
|
10
|
+
2. **Tag Usage**: Use `<odac translate>Key</odac>` in views.
|
|
11
|
+
3. **Placeholders**: Use `%s1`, `%s2` in JSON and nested `<odac var="...">` tags in views.
|
|
12
|
+
4. **Backend Access**: Use `Odac.__(key, ...args)` in controllers.
|
|
13
|
+
|
|
14
|
+
## Reference Patterns
|
|
15
|
+
|
|
16
|
+
### 1. View Translations
|
|
17
|
+
```html
|
|
18
|
+
<!-- Simple -->
|
|
19
|
+
<odac translate>Welcome</odac>
|
|
20
|
+
|
|
21
|
+
<!-- With Placeholders -->
|
|
22
|
+
<odac translate>Hello <odac var="user.name" /></odac>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### 2. Controller Translations
|
|
26
|
+
```javascript
|
|
27
|
+
const msg = Odac.__('Welcome back, %s1!', user.name);
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### 3. Locale JSON Structure
|
|
31
|
+
```json
|
|
32
|
+
// locale/tr.json
|
|
33
|
+
{
|
|
34
|
+
"Welcome": "Hoş Geldiniz",
|
|
35
|
+
"Hello %s1": "Merhaba %s1"
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Best Practices
|
|
40
|
+
- **Descriptive Keys**: Use meaningful keys like `nav.home` or `form.error.required`.
|
|
41
|
+
- **Html Safety**: By default, translations are escaped. Use the `raw` attribute (`<odac translate raw>`) only for trusted HTML.
|
|
42
|
+
- **Language Selection**: Set the language at the start of a request via `Odac.Lang.setLanguage('tr')`.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Backend Utilities Skill
|
|
2
|
+
|
|
3
|
+
String manipulation, hashing, and flow control.
|
|
4
|
+
|
|
5
|
+
## Core Rules
|
|
6
|
+
1. **Odac.Var**: A fluent interface for strings. Use it for `.slug()`, `.hash()`, `.is('email')`, and `.encrypt()`.
|
|
7
|
+
2. **Flow Control**:
|
|
8
|
+
- `Odac.abort(code)`: Terminate request with HTTP status (e.g., 404, 403).
|
|
9
|
+
- `Odac.direct(url)`: Redirect the user.
|
|
10
|
+
- `Odac.session(key, value)`: Manage session data.
|
|
11
|
+
|
|
12
|
+
## Reference Patterns
|
|
13
|
+
### 1. Odac.Var (String Power)
|
|
14
|
+
```javascript
|
|
15
|
+
const slug = Odac.Var('My Post Title').slug();
|
|
16
|
+
const isValid = Odac.Var('test@test.com').is('email');
|
|
17
|
+
const password = Odac.Var('secret').hash(); // BCrypt
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 2. Redirect and Abort
|
|
21
|
+
```javascript
|
|
22
|
+
if (!user) return Odac.abort(404);
|
|
23
|
+
if (!isLoggedIn) return Odac.direct('/login');
|
|
24
|
+
```
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Backend Validation Skill
|
|
2
|
+
|
|
3
|
+
The `Validator` service provides a fluent, chainable API for securing user input and enforcing business rules.
|
|
4
|
+
|
|
5
|
+
## Architectural Approach
|
|
6
|
+
Validation should happen as early as possible in the request lifecycle. The `Validator` service handles automatic error formatting and frontend integration.
|
|
7
|
+
|
|
8
|
+
## Core Rules
|
|
9
|
+
1. **Chaining**: Use the fluent API: `.post(key).check(rules).message(msg)`.
|
|
10
|
+
2. **Brute Force**: Protect sensitive endpoints with `.brute(attempts)`.
|
|
11
|
+
3. **Automatic Errors**: Use `await validator.error()` to check status and `await validator.result()` to return standardized JSON.
|
|
12
|
+
4. **Inverse Rules**: Use `!` to invert any rule (e.g., `!required`).
|
|
13
|
+
|
|
14
|
+
## Reference Patterns
|
|
15
|
+
|
|
16
|
+
### 1. Standard Validation Chaining
|
|
17
|
+
```javascript
|
|
18
|
+
module.exports = async function (Odac) {
|
|
19
|
+
const validator = Odac.Validator;
|
|
20
|
+
|
|
21
|
+
validator
|
|
22
|
+
.post('email').check('required|email').message('Valid email required')
|
|
23
|
+
.post('password').check('required|minlen:8').message('Password too short');
|
|
24
|
+
|
|
25
|
+
if (await validator.error()) {
|
|
26
|
+
return validator.result('Please fix input errors');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Proceed with validated data
|
|
30
|
+
return validator.success('Success');
|
|
31
|
+
};
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### 2. Custom Variable and Security Validation
|
|
35
|
+
```javascript
|
|
36
|
+
validator.var('age', userAge).check('numeric|min:18').message('Must be 18+');
|
|
37
|
+
|
|
38
|
+
// Security checks
|
|
39
|
+
validator.post('bio').check('xss').message('Malicious HTML detected');
|
|
40
|
+
validator.var('auth', null).check('usercheck').message('Authentication required');
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### 3. Common Rules Reference
|
|
44
|
+
- `required`, `email`, `numeric`, `username`, `url`, `ip`, `json`.
|
|
45
|
+
- `len:X`, `minlen:X`, `maxlen:X`.
|
|
46
|
+
- `mindate:YYYY-MM-DD`, `maxdate:YYYY-MM-DD`.
|
|
47
|
+
- `regex:pattern`, `same:field`, `different:field`.
|
|
48
|
+
- `!disposable`: Blocks temporary email providers.
|
|
49
|
+
|
|
50
|
+
## Best Practices
|
|
51
|
+
- **Specific Messages**: Provide helpful error messages that guide the user.
|
|
52
|
+
- **Security First**: Use the `xss` rule for any user-generated content that will be rendered later.
|
|
53
|
+
- **Fail Fast**: Return the validation result immediately if `validator.error()` is true.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Backend Views & Templates Skill
|
|
2
|
+
|
|
3
|
+
High-performance server-side rendering using ODAC's optimized template engine.
|
|
4
|
+
|
|
5
|
+
## Architectural Approach
|
|
6
|
+
Views in ODAC are logic-light but powerful. They support automatic XSS protection, high-performance looping, and server-side JavaScript execution via `<script:odac>`.
|
|
7
|
+
|
|
8
|
+
## Core Rules
|
|
9
|
+
1. **Skeleton Architecture**: Use `Odac.View.skeleton('name')` to wrap content in a layout.
|
|
10
|
+
2. **Data Binding**:
|
|
11
|
+
- `{{ key }}`: Escaped output (Standard).
|
|
12
|
+
- `{!! key !!}`: Raw output (Use with extreme caution).
|
|
13
|
+
3. **Conditionals**: Use `<odac:if condition="VAR"> ... </odac:if>`.
|
|
14
|
+
4. **Looping**: Use `<odac:for in="ARRAY" value="ITEM"> ... </odac:for>` or the performance-optimized `[[odac_for ...]]`.
|
|
15
|
+
5. **Server-Side JS**: Use `<script:odac>` for complex calculations during rendering.
|
|
16
|
+
|
|
17
|
+
## Reference Patterns
|
|
18
|
+
|
|
19
|
+
### 1. The Controller to View Flow
|
|
20
|
+
```javascript
|
|
21
|
+
// Controller
|
|
22
|
+
Odac.View.skeleton('main');
|
|
23
|
+
Odac.View.set({
|
|
24
|
+
title: 'Dashboard',
|
|
25
|
+
stats: { users: 150, orders: 45 }
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 2. Template Syntax Reference
|
|
30
|
+
```html
|
|
31
|
+
<!-- Display Variable -->
|
|
32
|
+
<h1>{{ title }}</h1>
|
|
33
|
+
|
|
34
|
+
<!-- Conditional -->
|
|
35
|
+
<odac:if condition="stats.users > 100">
|
|
36
|
+
<span class="badge">Popular!</span>
|
|
37
|
+
</odac:if>
|
|
38
|
+
|
|
39
|
+
<!-- Performance Loop -->
|
|
40
|
+
[[odac_for user in users]]
|
|
41
|
+
<li>{{ user.name }}</li>
|
|
42
|
+
[[odac_endfor]]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 3. Backend JavaScript (`<script:odac>`)
|
|
46
|
+
Perfect for calculations that shouldn't clutter the controller but are too complex for simple tags.
|
|
47
|
+
```html
|
|
48
|
+
<script:odac>
|
|
49
|
+
// Runs on the SERVER during rendering
|
|
50
|
+
const total = items.reduce((sum, i) => sum + i.price, 0);
|
|
51
|
+
const tax = total * 0.18;
|
|
52
|
+
</script:odac>
|
|
53
|
+
|
|
54
|
+
<p>Subtotal: ${{ total }}</p>
|
|
55
|
+
<p>Tax: ${{ tax }}</p>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Security Best Practices
|
|
59
|
+
- **Always use `{{ }}`**: Standard tags prevent XSS.
|
|
60
|
+
- **Limit `<script:odac>`**: Do not perform database queries or API calls inside views; keep them in the controller.
|
|
61
|
+
- **Partial Awareness**: Use `<odac:include view="path.to.view" />` for reusable components.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Frontend Core Skill
|
|
2
|
+
|
|
3
|
+
The foundational principles of the `odac.js` library for building reactive and interactive user interfaces.
|
|
4
|
+
|
|
5
|
+
## Architectural Approach
|
|
6
|
+
Frontend logic is organized into **Actions** using `Odac.action()`. This method centralizes event listeners, page-specific code, and lifecycle hooks.
|
|
7
|
+
|
|
8
|
+
## Core Rules
|
|
9
|
+
1. **Centralization**: All frontend logic should be defined within `Odac.action({})`.
|
|
10
|
+
2. **Lifecycle Hooks**:
|
|
11
|
+
- `start`: Fires once when the script initializes.
|
|
12
|
+
- `load`: Fires after every page load (including AJAX navigations).
|
|
13
|
+
3. **Page Scoping**: Use the `page: { name: fn }` object to isolate code to specific routes.
|
|
14
|
+
4. **Persistent Storage**: Use `odac.storage(key, value)` for a secure LocalStorage wrapper.
|
|
15
|
+
|
|
16
|
+
## Reference Patterns
|
|
17
|
+
|
|
18
|
+
### 1. Global Lifecycle & Page Scoping
|
|
19
|
+
```javascript
|
|
20
|
+
Odac.action({
|
|
21
|
+
// Global - runs on every page
|
|
22
|
+
load: function() {
|
|
23
|
+
console.log('Page ready');
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
// Scoped - runs only on the 'dashboard' page
|
|
27
|
+
page: {
|
|
28
|
+
dashboard: function(vars) {
|
|
29
|
+
console.log('Welcome to Dashboard', vars);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 2. Event Handling
|
|
36
|
+
```javascript
|
|
37
|
+
Odac.action({
|
|
38
|
+
click: {
|
|
39
|
+
'#save-btn': function() {
|
|
40
|
+
alert('Saving...');
|
|
41
|
+
},
|
|
42
|
+
'.delete-item': 'fn.confirmDelete' // Reference a custom function
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
fn: {
|
|
46
|
+
confirmDelete: function() {
|
|
47
|
+
return confirm('Are you sure?');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. Data Utilities
|
|
54
|
+
```javascript
|
|
55
|
+
// Accessing data shared from backend (Odac.share)
|
|
56
|
+
const user = odac.data('user');
|
|
57
|
+
|
|
58
|
+
// Using Storage wrapper
|
|
59
|
+
odac.storage('theme', 'dark');
|
|
60
|
+
const theme = odac.storage('theme');
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Best Practices
|
|
64
|
+
- **Clean Selectors**: Use ID or specific data-attributes for event listeners to avoid conflicts.
|
|
65
|
+
- **No Inline JS**: Move all logic from HTML attributes (onclick, etc.) into `Odac.action()`.
|
|
66
|
+
- **Shared State**: Use `odac.data()` to pass complex objects from the backend once per request.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Frontend Forms & API Skill
|
|
2
|
+
|
|
3
|
+
Handling AJAX form submissions and API requests.
|
|
4
|
+
|
|
5
|
+
## Rules
|
|
6
|
+
1. **Forms**: Use `odac.form('#id', callback)` for AJAX submission.
|
|
7
|
+
2. **Requests**: Use `odac.get()` and `odac.post()` for manual requests.
|
|
8
|
+
3. **Realtime**: Handle WebSocket events using Hub structures in `Odac.action()`.
|
|
9
|
+
|
|
10
|
+
## Patterns
|
|
11
|
+
```javascript
|
|
12
|
+
// Form with automatic validation feedback
|
|
13
|
+
odac.form('#my-form', (res) => {
|
|
14
|
+
if(res.success) odac.visit('/done');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// Simple API Check
|
|
18
|
+
odac.get('/api/status', (data) => {
|
|
19
|
+
console.log('Status:', data);
|
|
20
|
+
});
|
|
21
|
+
```
|