Skip to content

DocOps/clientele-as-code

Repository files navigation

Clientele-as-Code

Use Git and docs-as-code to track and manage freelance/consulting projects, clients, and associated payments and invoicing.

Warning
This is a minimum-viable proof of concept (MVP). It is mainly intended to be exemplary and to poll for interest in further development.

Features and Purpose

Here is what the Clientele-as-Code project can already enable:

  • Store client metadata and payment/invoice records in a YAML file.

  • Generate invoices from the YAML sources:

    • HTML and PDF output formats

    • AsciiDoc source files written automatically

  • Track payments and unpaid invoices.

See the demo PDF artifacts:

Why Do Invoices This Way?

There are a few benefits of this approach that I have considered, though they are yet to be demonstrated in practice to be true advantages.

source control

Track all of your payments in Git.

cost control

It’s free! Forever.

total control!

You can customize and extend to your heart’s content.

GAI/GPT assist

Use AI to help you fill out your invoices.

Cloud and other premium software that helps you track work and perform invoicing can get very expensive.

Filling out forms is less fun than letting a tool like GitHub Co-pilot help you write your invoices.

Free backup to GitHub, GitLab, or your private Git repo host of choice — or just backup to your backup. This is more confidence, privacy, and security than most paid systems provide.

Who is This For?

While no real experience with the underlying technologies is required, this project will probably be most useful to people who already use Git and markup.

If you want to heavily customize the invoice template, you will need to use Liquid, which is designed for non-programmers. This is also the only case in which you would need to know any AsciiDoc, and to be frank, AsciiDoc with Liquid markup mixed in is not the easiest way to learn either format if you are not already adept at using markup.

The YAML files as currently implemented should be fairly intuitive for “less-technical” users. While they can be “broken,” so to speak, this whole system is safe for novice users — it does not automatically send anything to clients. If something is broken, you’ll know it before your clients see anything.

It’s not yet clear if Clientele-as-Code will make invoicing more collaborative for large teams, but my hope is that it will offer all the advantages that source-control systems have provided for collectively managing product codebases. I can imagine a situation where multiple workers at a firm can track their time on a given project, and an additional worker can handle the actual generating and management of invoices, all from a central repository.

Setup

This is a quickstart guide to getting up and running with Clientele-as-Code. More thorough documentation will be a feature of further development, if this MVP is successful.

Prerequisites

  • Docker OR a proper Ruby environment (2.6+).

It is strongly recommended to use the provided Dockerfile to generate a Docker image that will run the script in a temporary container. This process is very fast.

Docker requires a proper Unix-like environment, so either MacOS or Windows with WSL2 will work, in addition to native Linux.

If you are already a Ruby user, try bundle install and bundle exec ruby invoices.rb <client-name> after cloning the repo.

Installation

  1. Navigate to your main (global) work projects directory in your terminal application.

    Example
    cd ~/Documents/work/projects
  2. Get this repository using either of these methods:

    1. Clone the repo with Git.

      git clone https://github.com/DocOps/clientele-as-code.git invoices
    2. Download the ZIP file and extract it.

      curl -L https://github.com/DocOps/clientele-as-code/archive/refs/heads/main.zip -o clientele-as-code.zip && unzip clientele-as-code.zip && mv clientele-as-code-main invoices && rm clientele-as-code.zip
  3. Change to the project directory.

    cd invoices
  4. Build the Docker image.

    docker build -t clientele:latest .

Demo Procedure

Test the procedure using the sample data provided.

  1. Run the script to generate the latest invoice.

    ./invoice.sh acme-corporation

    This generates the latest invoice to the path clients/acme-corporation/generated/ in AsciiDoc (.adoc), HTML5 (.html) and PDF (.pdf) formats.

    Note
    If this step does not work, you may need to run chmod +x invoice.sh to make the script executable.
  2. Try it with a specific (previous) invoice ID.

    ./invoice.sh acme-corporation 001
    ./invoice.sh acme-corporation 002

Note, there are three sample invoice periods, each showing off different aspects of the rendering system. Invoice 001 received multiple payments but was paid off.

Customize Data Source Files

You’ll need your own versions of the global _config.yml file, which reflects your company details and configuration settings.

To establish this, edit the _config.yml file in the root directory.

Note
If you already have a _config.yml file in your root directory, you may name the file _invoices.yml, or just add the provider and settings blocks from our _config.yml to your own, assuming they do not conflict.

Then make a copy of the clients/acme-corporation/ directory and modify it to meet your first client’s specifics.

  1. If necessary, make a client directory.

    mkdir clients/your-client-id
  2. Copy the data files from the example directory.

    cp -r clients/acme-corporation clients/your-client-id

Alternatively, you an just rename the directory and edit the files in place, if you don’t care to keep a copy of the example data.

Generate an Invoice

With your source files customized, you can run the script to build invoices for your client.

./invoice.sh your-client-id

If you are not happy with the invoice output, simply make changes to your data files and try this command again.

Customize Invoice Output

Some basic configuration of how the invoice will render can be established in the settings block inside the _config.yml file. These are presented as commented-out lines that express the default value for each. Uncomment and modify them as needed.

Further customization can be done in the templates/invoice.asciidoc file.

Usage Notes

Here are some tips for using this platform:

  • If you are brand new to YAML, check out this introductory article or this intro video.

  • Invoice records should be listed most recent to oldest — or at least the current/latest should be the first in the sequence, so it can be generated without specifying an ID in the ./invoice.sh command.

  • Adding a paid property to an invoice’s dates block will trigger the -PAID filename tag and the PAID stamp on the PDF version of the invoice. Registering payments will not mark an invoice paid, even if the total is met.

    dates:
      sent: 2024-09-01
      due: 2024-09-30
      paid: 2024-09-15 # whenever this appears, the invoice is considered fully paid

Integrate into Existing Directory (Advanced)

If you already have a directory containing client directories, you can integrate this project into that structure.

Clone to local

If your existing directory is not already a Git repository, you can clone the repository directly into it.

git clone https://github.com/DocOps/clientele-as-code.git .
Download and extract to local

If you just want to add these files to an existing repository, be sure changes are committed and/or the path is backed up:

curl -L https://github.com/DocOps/clientele-as-code/archive/refs/heads/main.zip -o clientele-as-code.zip && unzip clientele-as-code.zip && mv clientele-as-code-main/* . && rm -rf clientele-as-code-main clientele-as-code.zip README.adoc spec

Integration into an existing codebase/repo should be made far more elegant if this project is released as a proper Ruby gem (see Development).

Development

As mentioned, this is simply a proof-of-concept, mainly:

  1. To demonstrate the various ways my preferred AYL DocStack (AsciiDoc, YAML, and Liquid) can be used to solve diverse documentation problems with a code-like, Git-friendly approach.

  2. To see if it makes sense even for me to use on a regular basis to track my own clients and their payments.

  3. Hopefully, to demonstrate how Docker can make docs-as-code projects more accessible.

If you are interested in this project, give it a star and maybe post an Issue requesting a feature or fix that you need.

Here are the big changes I expect to make to this project if others really want to take advantage of it:

more customizaton

The output can be endlessly customized, especially for international users. We should make this as convenient as possible by adding it to the _config.yml file.

more features
  • VAT handling for European users.

  • Dynamically customize invoice filenames.

contracts-as-code

Single-sourced, markup-formatted freelance/consulting/etc contracts that can be managed in Git and digitally signed with extraordinary ease. See Codewriting Contracts.

proper gem release

Package and release the underlying code as a Ruby gem with a proper commandline interface (CLI).

modularize template

The invoice.asciidoc template should be broken down into numerous “partials” that are included into the main template, so users can customize any one part of it without having to maintain a fork of the entire file.

improve invoice theming

Both the PDF and HTML output are basically Asciidoctor default, and could use some better styling.

real documentation

There should be a proper reference for the configuration properties, for starters, and maybe a tutorial.

move heavier logic to Ruby

Some of the parsing now performed in the Liquid template would be better handled in Ruby, meaning we would transform the invoice data object before handing it off to Liquid.

separate core source from demo content

Right now if you clone or fork this repo, your code will diverge as soon as you customize the _config.yml file or remove the acme-corporation directory. A proper release will separate those files while making quickstart demos still possible.

better practices
  • The Gemfile.lock file should be tracked rather than Git-ignored.

  • Gems should persist in a Docker named volume

  • Unit tests should be added to Ruby script.

About

An example project for rendering invoices from YAML

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published