diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..25006ea
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+node_modules/
+.vibe42-run.log
+.vibe42-run.pid
diff --git a/data.json b/data.json
new file mode 100644
index 0000000..200977b
--- /dev/null
+++ b/data.json
@@ -0,0 +1,26 @@
+[
+ {
+ "id": 1,
+ "firstName": "Алишер",
+ "lastName": "Нурсултанов",
+ "phone": "+7 (777) 123-45-67",
+ "telegram": "@alisher_ns",
+ "registeredAt": "2026-09-12T10:30:00.000Z"
+ },
+ {
+ "id": 2,
+ "firstName": "Динара",
+ "lastName": "Кенжегулова",
+ "phone": "+7 (701) 234-56-78",
+ "telegram": "@dinara_kz",
+ "registeredAt": "2026-09-13T14:15:00.000Z"
+ },
+ {
+ "id": 3,
+ "firstName": "Максат",
+ "lastName": "Ибрагимов",
+ "phone": "+7 (778) 345-67-89",
+ "telegram": "@maxat_dev",
+ "registeredAt": "2026-09-13T16:45:00.000Z"
+ }
+]
diff --git a/index.html b/index.html
index b9535da..b4c873c 100644
--- a/index.html
+++ b/index.html
@@ -75,6 +75,14 @@
font-size: 48px;
margin-bottom: var(--kt-ai-space-3);
}
+ .error-message {
+ background: var(--kt-ai-bg-soft);
+ border: 1px solid var(--kt-ai-border);
+ border-radius: var(--kt-ai-radius-xl);
+ padding: var(--kt-ai-space-4);
+ color: var(--kt-ai-fg-muted);
+ margin-top: var(--kt-ai-space-4);
+ }
@@ -100,7 +108,7 @@
@@ -175,9 +183,10 @@
Регистрация успешна!
Добро пожаловать на Hackathon Open 2026!
+
-
+
📅 Когда
15-17 ноября 2026, старт в пятницу 18:00
@@ -199,8 +208,6 @@
-
-
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..1bf705e
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,10 @@
+{
+ "name": "hackathon-registration",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "hackathon-registration"
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..80a471f
--- /dev/null
+++ b/package.json
@@ -0,0 +1,6 @@
+{
+ "name": "hackathon-registration",
+ "private": true,
+ "type": "commonjs",
+ "scripts": { "start": "node server.js" }
+}
diff --git a/server.js b/server.js
new file mode 100644
index 0000000..1bba6d4
--- /dev/null
+++ b/server.js
@@ -0,0 +1,65 @@
+const http = require("http");
+const fs = require("fs");
+const path = require("path");
+
+const PORT = process.env.PORT || 3000;
+const DATA = path.join(__dirname, "data.json");
+
+function readItems() {
+ try { return JSON.parse(fs.readFileSync(DATA, "utf8")); } catch (_) { return []; }
+}
+function writeItems(items) {
+ fs.writeFileSync(DATA, JSON.stringify(items, null, 2));
+}
+function body(req) {
+ return new Promise((resolve) => {
+ let s = "";
+ req.on("data", (c) => (s += c));
+ req.on("end", () => { try { resolve(JSON.parse(s || "{}")); } catch (_) { resolve({}); } });
+ });
+}
+
+http.createServer(async (req, res) => {
+ const urlPath = req.url.split("?")[0];
+
+ if (req.method === "GET" && urlPath === "/api/registrations") {
+ res.writeHead(200, { "Content-Type": "application/json" });
+ return res.end(JSON.stringify(readItems()));
+ }
+
+ if (req.method === "POST" && urlPath === "/api/registrations") {
+ const item = await body(req);
+ const items = readItems();
+ const newItem = {
+ id: Date.now(),
+ firstName: item.firstName || "",
+ lastName: item.lastName || "",
+ phone: item.phone || "",
+ telegram: item.telegram || "",
+ registeredAt: new Date().toISOString()
+ };
+ items.push(newItem);
+ writeItems(items);
+ res.writeHead(200, { "Content-Type": "application/json" });
+ return res.end(JSON.stringify({ ok: true, data: newItem }));
+ }
+
+ if (req.method === "GET" && urlPath === "/api/stats") {
+ const items = readItems();
+ const today = new Date().toDateString();
+ const todayCount = items.filter(p => new Date(p.registeredAt).toDateString() === today).length;
+ res.writeHead(200, { "Content-Type": "application/json" });
+ return res.end(JSON.stringify({ total: items.length, today: todayCount }));
+ }
+
+ let file = req.url === "/" ? "/index.html" : urlPath;
+ const full = path.join(__dirname, file);
+ if (full.startsWith(__dirname) && fs.existsSync(full) && fs.statSync(full).isFile()) {
+ const ext = path.extname(full);
+ const type = ext === ".css" ? "text/css" : ext === ".js" ? "application/javascript" : "text/html";
+ res.writeHead(200, { "Content-Type": type + "; charset=utf-8" });
+ return res.end(fs.readFileSync(full));
+ }
+
+ res.writeHead(404); res.end("Not found");
+}).listen(PORT, () => console.log("Сервер запущен на порту " + PORT));