Skip to content

Commit 9d0a872

Browse files
committed
v0.2.1 add unified inquiry receive api
1 parent f93e90a commit 9d0a872

27 files changed

Lines changed: 1334 additions & 139 deletions

.gitignore

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
/vendor/
22
/storage/logs/*.log
3-
/storage/uploads/*
4-
!/storage/uploads/.gitkeep
5-
.env
3+
/storage/cache/
4+
/node_modules/
5+
/dist/
6+
/.idea/
7+
/.vscode/
68
.DS_Store
79
Thumbs.db

CHANGELOG.md

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,25 @@
11
# Changelog
22

3-
## v0.1.0 - Initial scaffold
3+
## v0.2.0
44

5-
### Added
6-
- Full pure PHP project scaffold
7-
- Front controller routing
8-
- Login and logout flow
9-
- CSRF protection helper
10-
- Session helper
11-
- PDO database wrapper
12-
- Dashboard page
13-
- Inquiry list page
14-
- Inquiry detail page
15-
- Site list page
16-
- Blacklist IP page
17-
- Personal settings page
18-
- SQL schema and seed files
19-
- Basic responsive admin UI
5+
- Added unified receive API endpoint
6+
- Added API health check endpoint
7+
- Added `site_key + api_token` validation
8+
- Added required field validation for `name`, `email`, `content`
9+
- Added blocked IP check before insert
10+
- Added basic spam checks for honeypot, duplicate content, link count, IP/email rate limit
11+
- Added storage for `extra_data` and `raw_payload`
12+
- Added inquiry filters in the backend
13+
- Added quick status update actions
14+
- Added blocked IP add form in the backend
15+
- Added API quick start info in dashboard and sites page
16+
- Added GitHub Actions build-release workflow
17+
- Added PHP and JavaScript integration examples
2018

21-
### Notes
22-
- This version is the foundation version.
23-
- External website inquiry submission API is not included yet.
24-
- Site token authentication and cross-site receiving flow will be implemented in the next version.
19+
## v0.1.0
20+
21+
- Initial scaffold version
22+
- Added login/logout
23+
- Added dashboard, inquiries, detail, sites, blocked IPs, profile pages
24+
- Added schema and seed files
25+
- Added basic project structure and UI

README.md

Lines changed: 97 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,120 @@
11
# Inquiry Management System
22

3-
Version: v0.1.0
3+
Version: **v0.2.0**
44

5-
A lightweight inquiry management system built with pure PHP + MySQL.
5+
A pure PHP + MySQL inquiry management system for collecting inquiry forms from multiple websites into one centralized backend.
66

7-
## Current scope in v0.1.0
7+
## v0.2.0 Highlights
88

9-
- Project scaffold and directory structure
10-
- PDO database connection layer
11-
- Login / logout
12-
- Session + CSRF helper
13-
- Basic dashboard
14-
- Inquiry list page
15-
- Inquiry detail page
16-
- Site list page
17-
- Blacklist IP page
18-
- Personal settings page
19-
- SQL schema and seed files
20-
- Changelog and versioned delivery structure for GitHub Desktop workflow
9+
- Unified receive API is ready: `/api/v1/inquiries/submit`
10+
- `site_key + api_token` validation
11+
- Required field validation for `name`, `email`, `content`
12+
- Stores both `extra_data` and `raw_payload`
13+
- Basic anti-spam checks
14+
- Blocked IP validation
15+
- Inquiry filters and quick status actions in the backend
16+
- GitHub Actions ZIP packaging workflow included
2117

22-
## Recommended environment
18+
## Environment
2319

2420
- PHP 8.1+
25-
- MySQL 5.7+ or MariaDB 10.4+
26-
- Apache / Nginx
21+
- MySQL 5.7+ or MySQL 8+
22+
- Apache or Nginx
2723

28-
## Quick start
24+
## Installation
2925

30-
1. Create a new MySQL database, for example: `inquiry_system`
31-
2. Import the SQL files in order:
26+
1. Create a database, for example: `inquiry_system`
27+
2. Import:
3228
- `database/schema.sql`
3329
- `database/seed.sql`
34-
3. Update database config in:
35-
- `config/database.php`
36-
4. Put the project in your web root and point the document root to:
37-
- `public/`
38-
5. Open the system in your browser.
30+
3. Update database settings in `config/database.php`
31+
4. Point your web root to `public/`
32+
5. Open the project in your browser
3933

40-
## Default admin account
34+
## Default Admin Account
4135

4236
- Username: `admin`
4337
- Password: `Admin@123456`
4438

45-
Please change the password immediately after first login.
39+
## Main Backend Routes
4640

47-
## Suggested GitHub Desktop workflow
41+
- `/login`
42+
- `/dashboard`
43+
- `/inquiries`
44+
- `/sites`
45+
- `/tools/blacklist-ips`
46+
- `/profile`
4847

49-
For each delivery version:
48+
## API Routes
5049

51-
1. Replace the local project files with the new full package
52-
2. Review `CHANGELOG.md`
53-
3. Commit with a versioned message, such as:
54-
- `v0.1.0 initial scaffold`
55-
- `v0.2.0 add inquiry receiving API`
56-
4. Push to GitHub
57-
5. Optionally create a Git tag
50+
### Health Check
5851

59-
## Planned next step
52+
`GET /api/v1/health`
6053

61-
v0.2.0 will focus on:
54+
### Submit Inquiry
6255

63-
- Inquiry receiving API
64-
- Site token validation
65-
- Basic anti-spam checks
66-
- Insert inquiry records from external websites
56+
`POST /api/v1/inquiries/submit`
57+
58+
Supported payload types:
59+
60+
- `application/json`
61+
- standard form POST
62+
63+
### Minimum payload
64+
65+
```json
66+
{
67+
"site_key": "a_main",
68+
"api_token": "token_a_main_2026",
69+
"name": "John Smith",
70+
"email": "john@example.com",
71+
"content": "I want more information about your products."
72+
}
73+
```
74+
75+
### Optional fields
76+
77+
- `form_key`
78+
- `title`
79+
- `country`
80+
- `phone`
81+
- `address`
82+
- `from_company`
83+
- `source_url`
84+
- `referer_url`
85+
- `language`
86+
- `browser`
87+
- `device_type`
88+
- `submitted_at`
89+
- `client_ip`
90+
- `extra_data` (array)
91+
92+
Unknown fields will also be merged into `extra_data` automatically.
93+
94+
## Example Files
95+
96+
- `examples/php-forwarder.php`
97+
- `examples/javascript-fetch-example.js`
98+
99+
## GitHub Actions
100+
101+
Workflow file:
102+
103+
- `.github/workflows/build-release.yml`
104+
105+
It creates a ZIP package automatically when you push a tag like:
106+
107+
```bash
108+
git tag v0.2.0
109+
git push origin v0.2.0
110+
```
111+
112+
## Notes
113+
114+
Recommended production flow:
115+
116+
1. Website form submits to the current website backend
117+
2. The current website backend forwards the payload to this central system
118+
3. This system validates, filters, stores, and manages the inquiry
119+
120+
This is safer than exposing tokens directly in front-end JavaScript.

VERSION.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
v0.1.0
1+
v0.2.0
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Controllers\Api;
6+
7+
use App\Core\Controller;
8+
use App\Services\InquiryReceiveService;
9+
10+
final class InquiryApiController extends Controller
11+
{
12+
public function options(): void
13+
{
14+
$this->sendCorsHeaders();
15+
http_response_code(204);
16+
exit;
17+
}
18+
19+
public function submit(): void
20+
{
21+
$this->sendCorsHeaders();
22+
23+
$payload = request_data();
24+
25+
$authorization = request_header('Authorization');
26+
if (!isset($payload['api_token']) && is_string($authorization) && starts_with_ignore_case($authorization, 'Bearer ')) {
27+
$payload['api_token'] = trim(substr($authorization, 7));
28+
}
29+
30+
if (!isset($payload['api_token'])) {
31+
$siteToken = request_header('X-Site-Token');
32+
if (is_string($siteToken) && $siteToken !== '') {
33+
$payload['api_token'] = $siteToken;
34+
}
35+
}
36+
37+
$service = new InquiryReceiveService();
38+
$result = $service->handle($payload, [
39+
'request_ip' => request_ip(),
40+
'origin_host' => request_origin_host(),
41+
'referer_host' => request_referer_host(),
42+
'referer_url' => $_SERVER['HTTP_REFERER'] ?? null,
43+
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '',
44+
'user_agent_summary' => substr((string) ($_SERVER['HTTP_USER_AGENT'] ?? ''), 0, 255),
45+
'accept_language' => $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '',
46+
'api_token' => $payload['api_token'] ?? '',
47+
]);
48+
49+
json_response($result['body'], $result['status_code']);
50+
}
51+
52+
public function health(): void
53+
{
54+
$this->sendCorsHeaders();
55+
json_response([
56+
'success' => true,
57+
'message' => 'Inquiry receive API is ready.',
58+
'version' => (string) config('app.api.version', 'v1'),
59+
'timestamp' => date('c'),
60+
]);
61+
}
62+
63+
private function sendCorsHeaders(): void
64+
{
65+
if (!(bool) config('app.api.enable_cors', true)) {
66+
return;
67+
}
68+
69+
$origin = request_header('Origin');
70+
if ($origin) {
71+
header('Access-Control-Allow-Origin: ' . $origin);
72+
header('Vary: Origin');
73+
}
74+
75+
header('Access-Control-Allow-Methods: POST, OPTIONS, GET');
76+
header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Site-Token');
77+
header('Access-Control-Max-Age: 86400');
78+
}
79+
}

app/Controllers/DashboardController.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,22 @@
77
use App\Core\Auth;
88
use App\Core\Controller;
99
use App\Models\Inquiry;
10-
10+
use App\Models\Site;
1111

1212
final class DashboardController extends Controller
1313
{
1414
public function index(): void
1515
{
1616
$inquiryModel = new Inquiry();
17+
$siteModel = new Site();
1718

1819
$this->view('dashboard/index', [
1920
'pageTitle' => 'Dashboard',
2021
'user' => Auth::user(),
2122
'stats' => $inquiryModel->stats(),
2223
'latestInquiries' => $inquiryModel->latest(6),
24+
'sites' => $siteModel->all(),
25+
'apiEndpoint' => base_url('api/v1/inquiries/submit'),
2326
]);
2427
}
2528
}

0 commit comments

Comments
 (0)