コンテンツへスキップ

Behind the Scenes: What Senior Software Engineering Actually Looks Like at V Group

I'm Ridhin, a Senior Odoo and Python Full-Stack Developer at V Group. When people outside the ERP world hear "Odoo developer," they usually picture someone tweaking form views and writing the occasional report. The reality — at least on the projects I work on — is closer to systems engineering: multi-tenant infrastructure, hospital-grade integrations, licensing and IP protection, and access-control models that have to survive real-world misuse. I want to walk through a few pieces of that work, not as a highlight reel, but as an honest look at the kind of problems I actually solve day to day.


Case Study 1: Building V-Cloud, an Internal Odoo.sh Alternative

One of the more architecturally interesting projects I've worked on is V-Cloud, an internal SaaS platform for hosting and managing Odoo instances for our own customers — conceptually similar to Odoo.sh, but built and operated in-house.

The core challenge wasn't "can we run Odoo in Docker" — that part is trivial. The real problem was per-customer isolation with centralized operability: every customer needed their own database, filestore, and container stack, deployable and destroyable on demand, while still being manageable from a single control plane (a customer portal plus internal tooling) without one tenant's misbehavior — a runaway cron, a memory leak, a bad migration — affecting anyone else.

That meant working through a stack of decisions:

  • Docker Compose-based per-customer stacks, generated from templates rather than hand-maintained, so onboarding a new customer is a provisioning operation, not a manual server-configuration task
  • GitHub webhook handling to trigger builds/deploys when a customer's custom modules change, which required thinking carefully about idempotency — a webhook can and will fire more than once for the same event, and a naive handler will trigger duplicate deployments or leave a stack in a half-updated state
  • A customer-facing portal that exposes just enough control (restart, view logs, manage backups) without exposing the underlying orchestration layer

The trade-off that took the most thought was isolation granularity versus operational overhead. Fully isolated VMs per customer would have been the "safest" answer, but far too heavy operationally at our scale. Fully shared infrastructure (one Odoo instance, multiple databases) is cheap to run but makes strong tenant isolation much harder to guarantee, especially around resource contention and security boundaries. We landed on container-per-customer as the right middle ground — strong enough isolation for our threat model, light enough to provision and scale without a dedicated ops team per client.


Case Study 2: HIS API Integration for a Hospital Client

Healthcare integrations are a different category of difficulty entirely, because correctness isn't a UX nicety — a duplicated stock move in a retail context is an annoyance; a duplicated stock move in a pharmacy dispensing API means the system now believes stock was deducted twice for a medication that was only actually dispensed once. That has real inventory and, indirectly, patient-care implications.

On one hospital integration project, I inherited a dispensing API that intermittently created duplicate stock.move.line records, silently double-deducting stock. This is the kind of bug that's genuinely hard to catch in testing, because it doesn't fail — it just quietly produces wrong numbers that only show up days later during a stock reconciliation.

The debugging process looked like:

  1. Reproduce deterministically first. Before touching any code, I built a way to reliably trigger the duplication rather than trusting intermittent hospital traffic. Non-deterministic bugs that get "fixed" without a reliable repro almost always come back.
  2. Trace the actual call path, not the assumed one. The API endpoint looked idempotent on paper, but the underlying picking/move creation logic was being invoked twice under specific concurrent-request timing — a classic case of code that's correct in isolation but wrong under concurrency.
  3. Fix at the right layer. Rather than patch the symptom (deduplicate after the fact), I fixed the actual create path so duplicate requests are detected and short-circuited before any stock move is generated.

A related, less dramatic but equally important fix in the same integration was a location-lookup helper that searched on the wrong field (barcode instead of the hospital's own internal his_location_code). It worked fine as long as the two happened to be identical, which is exactly the kind of "coincidentally correct" code that becomes a production incident the day someone maintains data properly. I made picking-type resolution warehouse-aware at the same time, since the original logic silently assumed a single warehouse — an assumption that doesn't hold once a hospital has multiple wards or dispensing points on the same instance.

The broader lesson: in integration work, the hardest bugs are rarely the ones that throw an error. They're the ones that succeed silently while doing the wrong thing.


Case Study 3: Protecting IP with PyArmor, Without Breaking Odoo

When we ship custom modules onto a client-managed server rather than infrastructure we control, we have to think about source protection — the client owns the server, but the module logic (and the effort behind it) is ours. That's where code protection tooling like PyArmor comes in: obfuscating and packaging Python source so the module still runs correctly inside Odoo's addon-loading mechanism, without shipping readable source.

This sounds simple until you actually try it against a framework like Odoo, which does a lot of introspection at load time — it inspects module manifests, walks class hierarchies for ORM model registration, and in some cases relies on being able to read source-level metadata. Naive obfuscation breaks things like:

  • Model class discovery, if the obfuscation tooling interferes with how Odoo's registry inspects class definitions
  • Dynamic imports and lazy-loaded submodules, which obfuscators can mishandle if they assume a simpler import graph
  • Runtime performance, since obfuscated bytecode adds overhead on every import — something that matters when a module is imported on every worker restart

Getting this right meant testing obfuscated modules against the actual Odoo module-loading lifecycle rather than just confirming "the script runs," and being deliberate about what gets protected versus what stays readable — manifest files and thin integration glue generally need to stay plain, while the actual business logic is what gets locked down. It's a good example of a problem that's 20% cryptography-adjacent tooling and 80% understanding a framework's internals well enough to know exactly where it will break.


Case Study 4: Getting Sub-User Access Control Right

A recurring request across several client projects is some version of: "we need our main portal user to be able to create limited sub-accounts for their own team or customers, with restricted visibility." It sounds like a small feature. It rarely is.

The naive approach — a new security group with fewer permissions — breaks down fast, because access control in these cases usually isn't just "can this user see model X," it's relationship-scoped: a sub-user should see only records tied to their parent account, not the whole company's data, and that scoping has to hold across every model the sub-user touches, including ones added later by other modules.

That pushes the design toward record rules built on a stable relational field (e.g., a parent_account_id or equivalent) rather than group membership alone, combined with careful ownership of create()/write() so a sub-user can't reassign a record's parent and escalate their own visibility. The trade-off worth calling out: record-rule-based scoping is more work upfront and needs discipline every time a new model is added to the flow, but it holds up under audits and doesn't quietly leak data the way ad-hoc domain filtering in views does — view-level filtering is a UX convenience, not a security boundary, and treating it as one is a mistake I've seen bite other teams.


Why the Work Culture at V Group Stands Out

I want to be direct about this, because it's one of the main reasons I enjoy working here: the work culture at V Group is genuinely good.

The process is straightforward and well organized. Our functional consultants gather the requirements directly from the client, understand what the client actually needs, and then the task is assigned to me with a clear scope and a clear deadline. From there, I own the technical implementation — analyzing the problem, designing the solution, writing and testing the code — and once it's ready, I demo the completed work back to the client. That loop — clear requirement, clear ownership, a real deadline, and a demo at the end — repeats project after project, and it works because everyone in that chain does their part well.

What makes it good, specifically:

  • I'm trusted with ownership. Once a task is assigned to me, I'm the one making the technical calls — how to solve it, what trade-offs to make — not micromanaged through every step.
  • Deadlines are real but reasonable. I'm expected to deliver on time, and I do, but I've never been asked to ship something I knew was broken just to hit a date.
  • The demo culture keeps everyone honest. Presenting finished work directly to the client means there's a natural, healthy pressure to get it right — and real, visible credit when it goes well.
  • Consultants and developers work as one team, not separate silos. The handoff from requirement-gathering to development to demo is smooth because the functional and technical sides actually talk to each other throughout, not just at the start and end.

That combination — clear process, real ownership, supportive team, and visible results — is what makes the harder technical problems in this post feel rewarding rather than just stressful.


What This Kind of Work Teaches You

Working across hosting infrastructure, healthcare integrations, licensing, and access control on the same team forces a particular kind of engineering maturity: you stop thinking about "the Odoo way" as a fixed set of patterns and start thinking about the framework as a foundation whose internals you need to actually understand — its ORM behavior under concurrency, its module loading lifecycle, its security model's real boundaries versus its apparent ones.


What to Expect Joining V Group as a Developer

Honestly: expect ambiguity. Requirements from healthcare, logistics, and manufacturing clients rarely arrive fully specified, and a meaningful part of the job is asking the right clarifying questions before writing code, not after. Expect to work across the full stack — Docker and deployment one day, ORM-level debugging the next, a security review the day after. And expect that "it works in testing" is the beginning of the review, not the end of it — especially on anything touching money, stock, or patient data, where a silent wrong answer is worse than a loud error.


Join Us

V Group Consulting & Solutions 
- Exist for your Success - 


Behind the Scenes: What Senior Software Engineering Actually Looks Like at V Group
V Group Consulting & Solutions Co., Ltd., Ridhin 2026年8月27日
このポストを共有
アーカイブ