Skip to content
View acetennyson's full-sized avatar
✌️
Follow the development
✌️
Follow the development

Block or report acetennyson

Block user

Prevent this user from interacting with your repositories and sending you notifications. Learn more about blocking users.

You must be logged in to block users.

Content in all repositories owned by your account will be closed.
Maximum 250 characters. Please don’t include any personal information such as legal names or email addresses. Markdown is supported. This note will only be visible to you.
Report abuse

Contact GitHub support about this user’s behavior. Learn more about reporting abuse.

Report abuse
acetennyson/README.md

Ado Daniel NJI

Engineering Secure, Automated & Adaptable Systems

Portfolio · LinkedIn · DEV · Email

I build the systems underneath a product: APIs, stateful services, integrations, and automation and AI workflows. I try to start from the product problem: what the thing has to do, who or what will call it, and what has to stay true when requests are retried, state is shared, or another team builds on top of it. The stack comes after that.

Software developer · Cameroon


Selected work

Several of these are private codebases, so each entry says what the project does and links code only where it's public.

Beta Gamer

Live · built solo

Site · Docs · React SDK · React Native SDK · How the matchmaker works

A games-as-a-service platform: an app that wants multiplayer games calls an API instead of building game servers and matchmaking of its own.

sequenceDiagram
    participant P as Partner backend
    participant B as Beta Gamer API
    participant C as Partner client
    P->>B: POST /v1/sessions with API key
    B-->>P: sessionId and sessionToken, JWT valid 5 min
    P->>C: hand over sessionToken only
    C->>B: realtime connection with sessionToken
    Note over B: tenant queue, rating-based pairing, game state
    B-->>P: signed webhook with result, live mode only
Loading
  • Keys stay on the server. The client only ever holds a session token, a JWT that expires after five minutes. Test and training modes sit alongside live, and webhooks fire in live mode only.
  • Tenant-isolated matchmaking. Queues belong to the partner and pairing is rating-based, so players only meet others from the same app.
  • Group-first. A match is a list of groups, and a group can be one player. A 1v1, four-player Ludo and a 2v2 are the same structure with different configuration. The matchmaker decides who plays whom; the game engine owns turns and rules.
  • Session types. Queue-matched, private room (joined by room code), or a bot match. Hosted matchmaking is the explicit route: the partner's backend submits pre-formed groups or starts a match directly instead of using the auto-queue.
  • Bots. Partners can inject bots into pending or live sessions with an API call, either a specific bot of their own or one from their configured pool. An internal event bus carries the request from the REST layer into the live WebSocket room.

Ten games are playable, and the React and React Native SDKs are on npm.

Task Manager API

Public code · built for a skill assessment

Code · Playground

A REST API on Next.js route handlers and Supabase Postgres, with JWT auth, built to work through failure cases rather than to pile up features. When two people edit the same task, the second save carries a stale version and gets the current task back instead of overwriting the first:

PATCH /api/tasks/:id   { "status": "done", "version": 3 }

409 Conflict           { "error": { "details": { "current": { … } } } }
Other cases it's written to handle
retried create           → original task (200)
same key, other body     → 422
bulk, one bad id         → 404/403, nothing written
reset link used twice    → rejected (single-use)
forgot-password          → 200 for any email
wrong pw / unknown user  → same 401, dummy hash compared
repeated failed logins   → 429 + Retry-After

Rate-limit counters live in Postgres, so serverless instances share them. Deletes are soft: the row stays as a tombstone with a task.deleted event, and GET /api/sync replays events from a cursor so an offline device learns what was removed. Tombstones are purged after a retention window (30 days by default). POST /api/sync applies a batch of operations in order, each with its own idempotency key, and returns what was accepted, conflicted or rejected.

Note

Server side only: there is no offline client and no reset-password page yet. The README lists these, along with known limitations and a prioritised scaling plan.

JobHub

Live

Live

Ranks job listings against a candidate's skills, seniority and location, and shows why each one matched. The score combines TF-IDF with cosine similarity and Jaro-Winkler string similarity, so it goes beyond keyword overlap. Employers are verified before they can post, candidates get alerts when a strong new match appears, and API keys and webhooks let other platforms push listings in or pull them out.

NightShift

Public code · built for the Notion MCP Challenge

Code · Demo

Notion client record → AI draft → your approval → sent when the client's window opens

Each client's time zone and availability window live in a Notion database. Drafts use previously sent messages as context, and nothing is sent without approval. A scheduled job runs every 15 minutes and sends approved drafts whose window has opened. Several AI providers are wired in with key rotation, and an MCP server exposes three tools to Claude Desktop.

Also

  • Mbende Stay · live, contributor. A property listing and rental platform for Cameroon (mbendestay.com). I work on backend and product features.
  • SafeCircle · hackathon build. Guardian mobile apps (Capacitor) and GPS trackers connected over persistent Socket.IO connections, with real-time alerts, a community safe-zone feed and AI-assisted post classification.
  • Axir · in development. An AI assistant being built toward a workspace where organizations configure their own agents. So far: tool execution and orchestration, model-provider abstraction, task persistence and multi-tenancy.

Range

Boundaries and access · Beta Gamer, Task Manager API
Tenant isolation, API keys, short-lived session tokens, signed webhooks, hashed single-use reset tokens, parameterized SQL with allow-listed identifiers.
JWT bcrypt HMAC Zod

Consistency under failure · Task Manager API, Beta Gamer
Idempotent writes, optimistic versioning, transactional bulk operations, tombstones and change events for sync, shared rate limits, reconnection windows for dropped players.
PostgreSQL Supabase

Real-time and connected devices · Beta Gamer, SafeCircle
Room state, nested-group matchmaking, bot injection into live sessions, GPS trackers on persistent connections.
Socket.IO WebSockets Redis

Matching and AI · JobHub, NightShift, Axir
Explainable ranking, multi-provider model integration with key rotation, MCP servers, scheduled workflows, agent tool execution.
MCP Gemini Claude Groq Notion API

Clients, SDKs and delivery
React and React Native SDKs, Capacitor mobile apps, web front ends, payment integrations, deployment and CI.
React React Native Capacitor Next.js MTN MoMo Orange Money Tranzak Stripe PayPal Vercel Docker GitHub Actions

Languages: TypeScript, JavaScript, PHP.


On GitHub

GitHub statistics for acetennyson Most used languages across acetennyson's public repositories

GitHub contribution streak for acetennyson

Much of the work above is in private repositories, so public activity understates it.


Contact

If you'd have made a different call on something here, I'd like to hear it. Issues are open on Task Manager API and NightShift, and email works too. I write about what I'm learning on my site and on DEV.

Pinned Loading

  1. elementTouch elementTouch Public

    Keeping Special Reusable Cool JavaScript Functionalities here

    JavaScript 1

  2. myPortfolio myPortfolio Public

    A portfoiio Made with Bootstrap | IAmSupreme

    PHP 1

  3. global-freelancer-assistant global-freelancer-assistant Public

    Global Freelancer Sync — an AI-powered command center for freelancers and remote workers managing clients across timezones.

    TypeScript