Cộng Đồng Người Việt Muôn Nơi

Cùng xây dựng một cộng đồng Người Việt Muôn Nơi mạnh mẽ và gắn kết, nơi mọi người có thể chia sẻ kinh nghiệm và hỗ trợ lẫn nhau trong cuộc sống và công việc. Đây là nơi bạn có thể tìm thấy sự hỗ trợ từ những người cùng chung chí hướng, tạo dựng các mối quan hệ mới và phát triển bản thân trong một môi trường đa dạng và sáng tạo.


{ "basePath": "/", "modules": [ { "id": "proof-of-reality", "mount": "/m/proof" }, { "id": "trust-receipt", "mount": "/m/trust" }, { "id": "help-exchange", "mount": "/m/help" } ] }
modules/ └─ help-exchange/ ├─ module.json ├─ index.js ├─ db.js ├─ schema.sql └─ public/ ├─ index.html ├─ new.html ├─ list.html └─ request.html
{ "name": "Help Exchange", "version": "1.0.0", "status": "beta", "description": "Cổng yêu cầu hỗ trợ & nhận giúp việc thật. Khi hoàn thành sẽ tự tạo Trust Receipt (biên nhận đóng góp)." }
CREATE TABLE IF NOT EXISTS help_requests ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, category TEXT NOT NULL, urgency TEXT NOT NULL, -- low | normal | high mode TEXT NOT NULL, -- online | onsite | hybrid location TEXT, detail TEXT NOT NULL, requester_name TEXT NOT NULL, requester_contact TEXT, created_at TEXT NOT NULL, ip_address TEXT, status TEXT NOT NULL DEFAULT 'open' -- open | claimed | done | closed ); CREATE TABLE IF NOT EXISTS help_claims ( id INTEGER PRIMARY KEY AUTOINCREMENT, request_id INTEGER NOT NULL, helper_name TEXT NOT NULL, helper_contact TEXT, helper_role TEXT, message TEXT, created_at TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'active', -- active | cancelled | done FOREIGN KEY (request_id) REFERENCES help_requests(id) ON DELETE CASCADE ); CREATE TABLE IF NOT EXISTS help_receipt_map ( request_id INTEGER PRIMARY KEY, receipt_id INTEGER NOT NULL );
const sqlite3 = require("sqlite3").verbose(); const path = require("path"); const dbPath = path.join(process.cwd(), "data", "iai.db"); const db = new sqlite3.Database(dbPath); db.serialize(() => { db.run(`CREATE TABLE IF NOT EXISTS help_requests ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, category TEXT NOT NULL, urgency TEXT NOT NULL, mode TEXT NOT NULL, location TEXT, detail TEXT NOT NULL, requester_name TEXT NOT NULL, requester_contact TEXT, created_at TEXT NOT NULL, ip_address TEXT, status TEXT NOT NULL DEFAULT 'open' )`); db.run(`CREATE TABLE IF NOT EXISTS help_claims ( id INTEGER PRIMARY KEY AUTOINCREMENT, request_id INTEGER NOT NULL, helper_name TEXT NOT NULL, helper_contact TEXT, helper_role TEXT, message TEXT, created_at TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'active', FOREIGN KEY (request_id) REFERENCES help_requests(id) ON DELETE CASCADE )`); db.run(`CREATE TABLE IF NOT EXISTS help_receipt_map ( request_id INTEGER PRIMARY KEY, receipt_id INTEGER NOT NULL )`); // Ensure Trust Receipt tables exist (Module #2). Safe if already created. db.run(`CREATE TABLE IF NOT EXISTS trust_receipts ( id INTEGER PRIMARY KEY AUTOINCREMENT, title TEXT NOT NULL, actor_name TEXT NOT NULL, actor_contact TEXT, role TEXT, scope TEXT, notes TEXT, created_at TEXT NOT NULL, ip_address TEXT, status TEXT NOT NULL DEFAULT 'submitted' )`); db.run(`CREATE TABLE IF NOT EXISTS trust_checklist_items ( id INTEGER PRIMARY KEY AUTOINCREMENT, receipt_id INTEGER NOT NULL, item_text TEXT NOT NULL, is_done INTEGER NOT NULL DEFAULT 0 )`); db.run(`CREATE TABLE IF NOT EXISTS trust_evidence ( id INTEGER PRIMARY KEY AUTOINCREMENT, receipt_id INTEGER NOT NULL, kind TEXT NOT NULL, url TEXT, filename TEXT, stored_path TEXT, hash_sha256 TEXT, created_at TEXT NOT NULL )`); }); module.exports = db;
const path = require("path"); const fs = require("fs"); const crypto = require("crypto"); const multer = require("multer"); const express = require("express"); const db = require("./db"); function getClientIp(req) { return req.headers["x-forwarded-for"]?.toString()?.split(",")[0]?.trim() || req.socket.remoteAddress; } function sha256File(filePath) { const buf = fs.readFileSync(filePath); return crypto.createHash("sha256").update(buf).digest("hex"); } function nowISO() { return new Date().toISOString(); } module.exports = function HelpExchangeModule({ app, mount, moduleDir }) { // uploads for evidence files const uploadsDir = path.join(moduleDir, "uploads"); if (!fs.existsSync(uploadsDir)) fs.mkdirSync(uploadsDir, { recursive: true }); const upload = multer({ dest: uploadsDir }); app.use(mount, express.static(path.join(moduleDir, "public"))); app.use(express.json({ limit: "2mb" })); // ---------- Requests ---------- // POST /api/requests app.post(`${mount}/api/requests`, (req, res) => { const { title, category, urgency, mode, location, detail, requester_name, requester_contact } = req.body || {}; if (!title || !detail || !requester_name) { return res.status(400).json({ error: "missing_required_fields" }); } const cat = String(category || "general").trim(); const urg = ["low", "normal", "high"].includes(String(urgency)) ? String(urgency) : "normal"; const m = ["online", "onsite", "hybrid"].includes(String(mode)) ? String(mode) : "online"; const created_at = nowISO(); const ip = getClientIp(req); db.run( `INSERT INTO help_requests (title, category, urgency, mode, location, detail, requester_name, requester_contact, created_at, ip_address, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'open')`, [ String(title).trim(), cat, urg, m, String(location || "").trim(), String(detail).trim(), String(requester_name).trim(), String(requester_contact || "").trim(), created_at, ip ], function () { res.json({ request_id: this.lastID }); } ); }); // GET /api/requests?status=open app.get(`${mount}/api/requests`, (req, res) => { const status = String(req.query.status || "open").trim(); const allowed = ["open", "claimed", "done", "closed", "all"]; const s = allowed.includes(status) ? status : "open"; const sql = (s === "all") ? `SELECT * FROM help_requests ORDER BY id DESC LIMIT 200` : `SELECT * FROM help_requests WHERE status = ? ORDER BY id DESC LIMIT 200`; const params = (s === "all") ? [] : [s]; db.all(sql, params, (err, rows) => { if (err) return res.status(500).json({ error: "db_error" }); res.json({ items: rows || [] }); }); }); // GET /api/requests/:id (includes claim + receipt mapping if any) app.get(`${mount}/api/requests/:id`, (req, res) => { const id = Number(req.params.id); if (!Number.isFinite(id) || id <= 0) return res.status(400).json({ error: "invalid_id" }); db.get(`SELECT * FROM help_requests WHERE id = ?`, [id], (err, request) => { if (err) return res.status(500).json({ error: "db_error" }); if (!request) return res.json({ valid: false }); db.get( `SELECT * FROM help_claims WHERE request_id = ? AND status = 'active' ORDER BY id DESC LIMIT 1`, [id], (err2, claim) => { if (err2) return res.status(500).json({ error: "db_error" }); db.get( `SELECT receipt_id FROM help_receipt_map WHERE request_id = ?`, [id], (err3, mapRow) => { if (err3) return res.status(500).json({ error: "db_error" }); res.json({ valid: true, request, claim: claim || null, receipt_id: mapRow?.receipt_id || null }); } ); } ); }); }); // ---------- Claim ---------- // POST /api/requests/:id/claim app.post(`${mount}/api/requests/:id/claim`, (req, res) => { const id = Number(req.params.id); const { helper_name, helper_contact, helper_role, message } = req.body || {}; if (!Number.isFinite(id) || id <= 0) return res.status(400).json({ error: "invalid_id" }); if (!helper_name) return res.status(400).json({ error: "missing_helper_name" }); db.get(`SELECT status FROM help_requests WHERE id = ?`, [id], (err, row) => { if (err) return res.status(500).json({ error: "db_error" }); if (!row) return res.status(404).json({ error: "not_found" }); if (row.status !== "open") return res.status(400).json({ error: "request_not_open" }); const created_at = nowISO(); db.run( `INSERT INTO help_claims (request_id, helper_name, helper_contact, helper_role, message, created_at, status) VALUES (?, ?, ?, ?, ?, ?, 'active')`, [ id, String(helper_name).trim(), String(helper_contact || "").trim(), String(helper_role || "").trim(), String(message || "").trim(), created_at ], function () { db.run(`UPDATE help_requests SET status = 'claimed' WHERE id = ?`, [id], () => { res.json({ claim_id: this.lastID }); }); } ); }); }); // ---------- Complete -> Auto Trust Receipt ---------- // POST /api/requests/:id/complete // body: { completion_notes?, evidence_links?: string[] } app.post(`${mount}/api/requests/:id/complete`, (req, res) => { const id = Number(req.params.id); const { completion_notes, evidence_links } = req.body || {}; if (!Number.isFinite(id) || id <= 0) return res.status(400).json({ error: "invalid_id" }); db.get(`SELECT * FROM help_requests WHERE id = ?`, [id], (err, request) => { if (err) return res.status(500).json({ error: "db_error" }); if (!request) return res.status(404).json({ error: "not_found" }); db.get( `SELECT * FROM help_claims WHERE request_id = ? AND status = 'active' ORDER BY id DESC LIMIT 1`, [id], (err2, claim) => { if (err2) return res.status(500).json({ error: "db_error" }); if (!claim) return res.status(400).json({ error: "no_active_claim" }); // Create Trust Receipt const receiptTitle = `HELP: ${request.title}`; const actorName = claim.helper_name; const actorContact = claim.helper_contact || ""; const role = claim.helper_role || "Helper"; const scope = "LMN Community"; const notes = [ `Category: ${request.category}`, `Mode: ${request.mode}`, `Urgency: ${request.urgency}`, `Requester: ${request.requester_name} (${request.requester_contact || ""})`, `Helper message: ${claim.message || ""}`, `Completion notes: ${String(completion_notes || "").trim()}` ].filter(Boolean).join("\n"); const created_at = nowISO(); const ip = request.ip_address || ""; db.run( `INSERT INTO trust_receipts (title, actor_name, actor_contact, role, scope, notes, created_at, ip_address, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'submitted')`, [receiptTitle, actorName, actorContact, role, scope, notes, created_at, ip], function () { const receiptId = this.lastID; // checklist defaults const checklist = [ "Đã liên hệ người yêu cầu", "Đã thực hiện hỗ trợ", "Đã cung cấp minh chứng" ]; const stmt = db.prepare( `INSERT INTO trust_checklist_items (receipt_id, item_text, is_done) VALUES (?, ?, 0)` ); checklist.forEach(t => stmt.run([receiptId, t])); stmt.finalize(() => { // evidence links (optional) const links = Array.isArray(evidence_links) ? evidence_links : []; const evStmt = db.prepare( `INSERT INTO trust_evidence (receipt_id, kind, url, filename, stored_path, hash_sha256, created_at) VALUES (?, 'link', ?, '', '', '', ?)` ); for (const u of links) { const url = String(u || "").trim(); if (url && (url.startsWith("http://") || url.startsWith("https://"))) { evStmt.run([receiptId, url, nowISO()]); } } evStmt.finalize(() => { // mark request & claim done + map receipt db.run(`UPDATE help_requests SET status = 'done' WHERE id = ?`, [id], () => { db.run(`UPDATE help_claims SET status = 'done' WHERE request_id = ? AND id = ?`, [id, claim.id], () => { db.run( `INSERT OR REPLACE INTO help_receipt_map (request_id, receipt_id) VALUES (?, ?)`, [id, receiptId], () => res.json({ ok: true, receipt_id: receiptId }) ); }); }); }); }); } ); } ); }); }); // Upload file as evidence INTO trust_evidence of mapped receipt // POST /api/requests/:id/evidence/file (multipart form-data: file) app.post(`${mount}/api/requests/:id/evidence/file`, upload.single("file"), (req, res) => { const id = Number(req.params.id); if (!Number.isFinite(id) || id <= 0) return res.status(400).json({ error: "invalid_id" }); if (!req.file) return res.status(400).json({ error: "file_required" }); db.get(`SELECT receipt_id FROM help_receipt_map WHERE request_id = ?`, [id], (err, mapRow) => { if (err) return res.status(500).json({ error: "db_error" }); if (!mapRow?.receipt_id) return res.status(400).json({ error: "receipt_not_created_yet" }); const hash = sha256File(req.file.path); const created_at = nowISO(); db.run( `INSERT INTO trust_evidence (receipt_id, kind, url, filename, stored_path, hash_sha256, created_at) VALUES (?, 'file', '', ?, ?, ?, ?)`, [mapRow.receipt_id, req.file.originalname, req.file.path, hash, created_at], function () { res.json({ evidence_id: this.lastID, receipt_id: mapRow.receipt_id, hash_sha256: hash }); } ); }); }); };

Các Hoạt Động Cộng Đồng

  1. Sự Kiện Kết Nối
    Tổ chức các sự kiện trực tuyến và ngoại tuyến để tạo cơ hội gặp gỡ, trao đổi, học hỏi và kết nối với nhau, giữa những người Việt khác sống và làm việc ở nước ngoài, như các buổi hội thảo, gặp mặt cà phê, và các chương trình dã ngoại.
  1. Nhóm Hỗ Trợ
    Các nhóm hỗ trợ trực tuyến và ngoại tuyến để chia sẻ kinh nghiệm và tư vấn: nhóm Facebook, diễn đàn và các nhóm trò chuyện trên ứng dụng nhắn tin giúp thành viên chia sẻ và nhận được lời khuyên về cuộc sống và công việc.
  1. Hội Thảo & Hội Nghị
    Tham gia các hội thảo và hội nghị về các chủ đề khác nhau: các hội thảo về kỹ năng mềm, kinh doanh, sức khỏe và phong cách sống giúp nâng cao kiến thức và kỹ năng cho các thành viên.
  1. Hoạt Động Tình Nguyện
    Tham gia các hoạt động tình nguyện để giúp đỡ cộng đồng địa phương: các dự án như dạy học miễn phí, tổ chức sự kiện từ thiện, và tham gia các chiến dịch môi trường.
  1. Hoạt Động Văn Hóa
    Tổ chức và tham gia các sự kiện văn hóa để giữ gìn và phát huy bản sắc văn hóa Việt Nam: các lễ hội văn hóa, triển lãm nghệ thuật và các buổi biểu diễn âm nhạc truyền thống.
  1. Câu Lạc Bộ Sở Thích
    Tham gia các câu lạc bộ về sở thích cá nhân như thể thao, nghệ thuật, công nghệ: các câu lạc bộ yoga, nhiếp ảnh, lập trình, và các hoạt động thể thao khác.
  1. Chương Trình Trao Đổi
    Trao đổi kiến thức, kinh nghiệm và kỹ năng giữa các thành viên: chương trình trao đổi sinh viên, trao đổi nhân viên và các buổi hội thảo chia sẻ kinh nghiệm.
  1. Mạng Lưới Kinh Doanh
    Kết nối và hỗ trợ các doanh nghiệp của người Việt Nam ở nước ngoài: các buổi gặp mặt doanh nghiệp, hội thảo kinh doanh và các chương trình hỗ trợ khởi nghiệp.
  1. Chương Trình Hỗ Trợ
     Hỗ trợ các thành viên gặp khó khăn trong cuộc sống và công việc: tư vấn tâm lý, hỗ trợ tài chính, và các chương trình đào tạo kỹ năng.

Lợi Ích của Cộng Đồng

  1. Kết Nối & Giao Lưu
    Tạo cơ hội kết nối và giao lưu với những người cùng chí hướng: giúp bạn mở rộng mạng lưới quan hệ, học hỏi kinh nghiệm từ người khác, và tạo dựng các mối quan hệ bền vững.
  1. Chia Sẻ & Học Hỏi
    Chia sẻ kiến thức và học hỏi từ cộng đồng: các buổi chia sẻ kinh nghiệm, học hỏi kỹ năng mới và tiếp cận với những nguồn tài nguyên phong phú.
  1. Hỗ Trợ & Tư Vấn
    Nhận được sự hỗ trợ và tư vấn từ các chuyên gia và cộng đồng: hỗ trợ từ các chuyên gia trong lĩnh vực tài chính, pháp lý, y tế và giáo dục.
  1. Phát Triển Kỹ Năng
    Phát triển kỹ năng cá nhân và nghề nghiệp: tham gia các khóa học, hội thảo và chương trình đào tạo kỹ năng mềm và chuyên môn.
  1. Cơ Hội Kinh Doanh
    Tìm kiếm và phát triển cơ hội kinh doanh: kết nối với các doanh nghiệp, tìm kiếm đối tác kinh doanh và mở rộng thị trường.
  1. Sức Khỏe & Phúc Lợi
    Đảm bảo sức khỏe và phúc lợi cho bản thân và gia đình: tham gia các chương trình chăm sóc sức khỏe, tư vấn y tế và các hoạt động thể thao.
  1. Văn Hóa & Giải Trí
    Tham gia các hoạt động văn hóa và giải trí: tham gia các sự kiện văn hóa, lễ hội, buổi biểu diễn nghệ thuật và các hoạt động giải trí khác.
  1. Đóng Góp & Tình Nguyện
    Đóng góp và tham gia các hoạt động tình nguyện: tham gia các dự án từ thiện, hoạt động tình nguyện và giúp đỡ cộng đồng địa phương.
  1. Tạo Dựng Giá Trị
    Tạo dựng giá trị cho bản thân và cộng đồng: đóng góp cho sự phát triển bền vững của cộng đồng, truyền cảm hứng và lan tỏa giá trị tích cực.

Liên hệ

Hãy liên lạc với chúng tôi để bắt đầu hành trình cuộc sống của bạn ngay hôm nay.